diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 14:42:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 14:42:23 -0500 |
commit | ecc88efbe7adceb3f4bfdbbb1efb669efcaab124 (patch) | |
tree | d9288ef55a17de21ac41cf84ae696ee83a28e336 /drivers/target | |
parent | 70a3a06d01ed9ca887316a881813cdefb8a20170 (diff) | |
parent | 972b29c8f86093f44e1d781588bd5c5faae3d8e3 (diff) |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull scsi target updates from Nicholas Bellinger:
"The highlights in this series include:
- Improve sg_table lookup scalability in RAMDISK_MCP (martin)
- Add device attribute to expose config name for INQUIRY model (tregaron)
- Convert tcm_vhost to use lock-less list for cmd completion (asias)
- Add tcm_vhost support for multiple target's per endpoint (asias)
- Add tcm_vhost support for multiple queues per vhost (asias)
- Add missing mapped_lun bounds checking during make_mappedlun setup
in generic fabric configfs code (jan engelhardt + nab)
- Enforce individual iscsi-target network portal export once per
TargetName endpoint (grover + nab)
- Add WRITE_SAME w/ UNMAP=0 emulation to FILEIO backend (nab)
Things have been mostly quiet this round, with majority of the work
being done on the iser-target WIP driver + associated iscsi-target
refactoring patches currently in flight for v3.10 code.
At this point there is one patch series left outstanding from Asias to
add support for UNMAP + WRITE_SAME w/ UNMAP=1 to FILEIO awaiting
feedback from hch & Co, that will likely be included in a post
v3.9-rc1 PULL request if there are no objections.
Also, there is a regression bug recently reported off-list that seems
to be effecting v3.5 and v3.6 kernels with MSFT iSCSI initiators that
is still being tracked down. No word if this effects >= v3.7 just
yet, but if so there will likely another PULL request coming your
way.."
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (26 commits)
target: Rename spc_get_write_same_sectors -> sbc_get_write_same_sectors
target/file: Add WRITE_SAME w/ UNMAP=0 emulation support
iscsi-target: Enforce individual network portal export once per TargetName
iscsi-target: Refactor iscsit_get_np sockaddr matching into iscsit_check_np_match
target: Add missing mapped_lun bounds checking during make_mappedlun setup
target: Fix lookup of dynamic NodeACLs during cached demo-mode operation
target: Fix parameter list length checking in MODE SELECT
target: Fix error checking for UNMAP commands
target: Fix sense data for out-of-bounds IO operations
target_core_rd: break out unterminated loop during copy
tcm_vhost: Multi-queue support
tcm_vhost: Multi-target support
target: Add device attribute to expose config_item_name for INQUIRY model
target: don't truncate the fail intr address
target: don't always say "ipv6" as address type
target/iblock: Use backend REQ_FLUSH hint for WriteCacheEnabled status
iscsi-target: make some temporary buffers larger
tcm_vhost: Optimize gup in vhost_scsi_map_to_sgl
tcm_vhost: Use iov_num_pages to calculate sgl_count
tcm_vhost: Introduce iov_num_pages
...
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 65 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target.h | 2 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_parameters.c | 8 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_stat.c | 25 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.c | 39 | ||||
-rw-r--r-- | drivers/target/target_core_configfs.c | 4 | ||||
-rw-r--r-- | drivers/target/target_core_device.c | 58 | ||||
-rw-r--r-- | drivers/target/target_core_fabric_configfs.c | 12 | ||||
-rw-r--r-- | drivers/target/target_core_file.c | 114 | ||||
-rw-r--r-- | drivers/target/target_core_iblock.c | 46 | ||||
-rw-r--r-- | drivers/target/target_core_internal.h | 3 | ||||
-rw-r--r-- | drivers/target/target_core_rd.c | 18 | ||||
-rw-r--r-- | drivers/target/target_core_sbc.c | 8 | ||||
-rw-r--r-- | drivers/target/target_core_spc.c | 42 | ||||
-rw-r--r-- | drivers/target/target_core_tmr.c | 12 | ||||
-rw-r--r-- | drivers/target/target_core_tpg.c | 10 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 19 |
17 files changed, 387 insertions, 98 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 339f97f7085b..23a98e658306 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -264,16 +264,50 @@ int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) | |||
264 | return 0; | 264 | return 0; |
265 | } | 265 | } |
266 | 266 | ||
267 | static struct iscsi_np *iscsit_get_np( | 267 | bool iscsit_check_np_match( |
268 | struct __kernel_sockaddr_storage *sockaddr, | 268 | struct __kernel_sockaddr_storage *sockaddr, |
269 | struct iscsi_np *np, | ||
269 | int network_transport) | 270 | int network_transport) |
270 | { | 271 | { |
271 | struct sockaddr_in *sock_in, *sock_in_e; | 272 | struct sockaddr_in *sock_in, *sock_in_e; |
272 | struct sockaddr_in6 *sock_in6, *sock_in6_e; | 273 | struct sockaddr_in6 *sock_in6, *sock_in6_e; |
273 | struct iscsi_np *np; | 274 | bool ip_match = false; |
274 | int ip_match = 0; | ||
275 | u16 port; | 275 | u16 port; |
276 | 276 | ||
277 | if (sockaddr->ss_family == AF_INET6) { | ||
278 | sock_in6 = (struct sockaddr_in6 *)sockaddr; | ||
279 | sock_in6_e = (struct sockaddr_in6 *)&np->np_sockaddr; | ||
280 | |||
281 | if (!memcmp(&sock_in6->sin6_addr.in6_u, | ||
282 | &sock_in6_e->sin6_addr.in6_u, | ||
283 | sizeof(struct in6_addr))) | ||
284 | ip_match = true; | ||
285 | |||
286 | port = ntohs(sock_in6->sin6_port); | ||
287 | } else { | ||
288 | sock_in = (struct sockaddr_in *)sockaddr; | ||
289 | sock_in_e = (struct sockaddr_in *)&np->np_sockaddr; | ||
290 | |||
291 | if (sock_in->sin_addr.s_addr == sock_in_e->sin_addr.s_addr) | ||
292 | ip_match = true; | ||
293 | |||
294 | port = ntohs(sock_in->sin_port); | ||
295 | } | ||
296 | |||
297 | if ((ip_match == true) && (np->np_port == port) && | ||
298 | (np->np_network_transport == network_transport)) | ||
299 | return true; | ||
300 | |||
301 | return false; | ||
302 | } | ||
303 | |||
304 | static struct iscsi_np *iscsit_get_np( | ||
305 | struct __kernel_sockaddr_storage *sockaddr, | ||
306 | int network_transport) | ||
307 | { | ||
308 | struct iscsi_np *np; | ||
309 | bool match; | ||
310 | |||
277 | spin_lock_bh(&np_lock); | 311 | spin_lock_bh(&np_lock); |
278 | list_for_each_entry(np, &g_np_list, np_list) { | 312 | list_for_each_entry(np, &g_np_list, np_list) { |
279 | spin_lock(&np->np_thread_lock); | 313 | spin_lock(&np->np_thread_lock); |
@@ -282,29 +316,8 @@ static struct iscsi_np *iscsit_get_np( | |||
282 | continue; | 316 | continue; |
283 | } | 317 | } |
284 | 318 | ||
285 | if (sockaddr->ss_family == AF_INET6) { | 319 | match = iscsit_check_np_match(sockaddr, np, network_transport); |
286 | sock_in6 = (struct sockaddr_in6 *)sockaddr; | 320 | if (match == true) { |
287 | sock_in6_e = (struct sockaddr_in6 *)&np->np_sockaddr; | ||
288 | |||
289 | if (!memcmp(&sock_in6->sin6_addr.in6_u, | ||
290 | &sock_in6_e->sin6_addr.in6_u, | ||
291 | sizeof(struct in6_addr))) | ||
292 | ip_match = 1; | ||
293 | |||
294 | port = ntohs(sock_in6->sin6_port); | ||
295 | } else { | ||
296 | sock_in = (struct sockaddr_in *)sockaddr; | ||
297 | sock_in_e = (struct sockaddr_in *)&np->np_sockaddr; | ||
298 | |||
299 | if (sock_in->sin_addr.s_addr == | ||
300 | sock_in_e->sin_addr.s_addr) | ||
301 | ip_match = 1; | ||
302 | |||
303 | port = ntohs(sock_in->sin_port); | ||
304 | } | ||
305 | |||
306 | if ((ip_match == 1) && (np->np_port == port) && | ||
307 | (np->np_network_transport == network_transport)) { | ||
308 | /* | 321 | /* |
309 | * Increment the np_exports reference count now to | 322 | * Increment the np_exports reference count now to |
310 | * prevent iscsit_del_np() below from being called | 323 | * prevent iscsit_del_np() below from being called |
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index f1e4f3155bac..b1a1e6350707 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h | |||
@@ -8,6 +8,8 @@ extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *); | |||
8 | extern void iscsit_del_tiqn(struct iscsi_tiqn *); | 8 | extern void iscsit_del_tiqn(struct iscsi_tiqn *); |
9 | extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *); | 9 | extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *); |
10 | extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *); | 10 | extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *); |
11 | extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *, | ||
12 | struct iscsi_np *, int); | ||
11 | extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, | 13 | extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, |
12 | char *, int); | 14 | char *, int); |
13 | extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, | 15 | extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, |
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index d89164287d00..ca2be406f141 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c | |||
@@ -1095,11 +1095,11 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value, | |||
1095 | SET_PSTATE_REPLY_OPTIONAL(param); | 1095 | SET_PSTATE_REPLY_OPTIONAL(param); |
1096 | } | 1096 | } |
1097 | } else if (IS_TYPE_NUMBER(param)) { | 1097 | } else if (IS_TYPE_NUMBER(param)) { |
1098 | char *tmpptr, buf[10]; | 1098 | char *tmpptr, buf[11]; |
1099 | u32 acceptor_value = simple_strtoul(param->value, &tmpptr, 0); | 1099 | u32 acceptor_value = simple_strtoul(param->value, &tmpptr, 0); |
1100 | u32 proposer_value = simple_strtoul(value, &tmpptr, 0); | 1100 | u32 proposer_value = simple_strtoul(value, &tmpptr, 0); |
1101 | 1101 | ||
1102 | memset(buf, 0, 10); | 1102 | memset(buf, 0, sizeof(buf)); |
1103 | 1103 | ||
1104 | if (!strcmp(param->name, MAXCONNECTIONS) || | 1104 | if (!strcmp(param->name, MAXCONNECTIONS) || |
1105 | !strcmp(param->name, MAXBURSTLENGTH) || | 1105 | !strcmp(param->name, MAXBURSTLENGTH) || |
@@ -1503,8 +1503,8 @@ static int iscsi_enforce_integrity_rules( | |||
1503 | FirstBurstLength = simple_strtoul(param->value, | 1503 | FirstBurstLength = simple_strtoul(param->value, |
1504 | &tmpptr, 0); | 1504 | &tmpptr, 0); |
1505 | if (FirstBurstLength > MaxBurstLength) { | 1505 | if (FirstBurstLength > MaxBurstLength) { |
1506 | char tmpbuf[10]; | 1506 | char tmpbuf[11]; |
1507 | memset(tmpbuf, 0, 10); | 1507 | memset(tmpbuf, 0, sizeof(tmpbuf)); |
1508 | sprintf(tmpbuf, "%u", MaxBurstLength); | 1508 | sprintf(tmpbuf, "%u", MaxBurstLength); |
1509 | if (iscsi_update_param_value(param, tmpbuf)) | 1509 | if (iscsi_update_param_value(param, tmpbuf)) |
1510 | return -1; | 1510 | return -1; |
diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index 421d6947dc64..464b4206a51e 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c | |||
@@ -410,14 +410,16 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr_type( | |||
410 | struct iscsi_tiqn *tiqn = container_of(igrps, | 410 | struct iscsi_tiqn *tiqn = container_of(igrps, |
411 | struct iscsi_tiqn, tiqn_stat_grps); | 411 | struct iscsi_tiqn, tiqn_stat_grps); |
412 | struct iscsi_login_stats *lstat = &tiqn->login_stats; | 412 | struct iscsi_login_stats *lstat = &tiqn->login_stats; |
413 | unsigned char buf[8]; | 413 | int ret; |
414 | 414 | ||
415 | spin_lock(&lstat->lock); | 415 | spin_lock(&lstat->lock); |
416 | snprintf(buf, 8, "%s", (lstat->last_intr_fail_ip_addr != NULL) ? | 416 | if (lstat->last_intr_fail_ip_family == AF_INET6) |
417 | "ipv6" : "ipv4"); | 417 | ret = snprintf(page, PAGE_SIZE, "ipv6\n"); |
418 | else | ||
419 | ret = snprintf(page, PAGE_SIZE, "ipv4\n"); | ||
418 | spin_unlock(&lstat->lock); | 420 | spin_unlock(&lstat->lock); |
419 | 421 | ||
420 | return snprintf(page, PAGE_SIZE, "%s\n", buf); | 422 | return ret; |
421 | } | 423 | } |
422 | ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr_type); | 424 | ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr_type); |
423 | 425 | ||
@@ -427,16 +429,19 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr( | |||
427 | struct iscsi_tiqn *tiqn = container_of(igrps, | 429 | struct iscsi_tiqn *tiqn = container_of(igrps, |
428 | struct iscsi_tiqn, tiqn_stat_grps); | 430 | struct iscsi_tiqn, tiqn_stat_grps); |
429 | struct iscsi_login_stats *lstat = &tiqn->login_stats; | 431 | struct iscsi_login_stats *lstat = &tiqn->login_stats; |
430 | unsigned char buf[32]; | 432 | int ret; |
431 | 433 | ||
432 | spin_lock(&lstat->lock); | 434 | spin_lock(&lstat->lock); |
433 | if (lstat->last_intr_fail_ip_family == AF_INET6) | 435 | if (lstat->last_intr_fail_ip_family == AF_INET6) { |
434 | snprintf(buf, 32, "[%s]", lstat->last_intr_fail_ip_addr); | 436 | ret = snprintf(page, PAGE_SIZE, "[%s]\n", |
435 | else | 437 | lstat->last_intr_fail_ip_addr); |
436 | snprintf(buf, 32, "%s", lstat->last_intr_fail_ip_addr); | 438 | } else { |
439 | ret = snprintf(page, PAGE_SIZE, "%s\n", | ||
440 | lstat->last_intr_fail_ip_addr); | ||
441 | } | ||
437 | spin_unlock(&lstat->lock); | 442 | spin_unlock(&lstat->lock); |
438 | 443 | ||
439 | return snprintf(page, PAGE_SIZE, "%s\n", buf); | 444 | return ret; |
440 | } | 445 | } |
441 | ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr); | 446 | ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr); |
442 | 447 | ||
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index de9ea32b6104..ee8f8c66248d 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c | |||
@@ -422,6 +422,35 @@ struct iscsi_tpg_np *iscsit_tpg_locate_child_np( | |||
422 | return NULL; | 422 | return NULL; |
423 | } | 423 | } |
424 | 424 | ||
425 | static bool iscsit_tpg_check_network_portal( | ||
426 | struct iscsi_tiqn *tiqn, | ||
427 | struct __kernel_sockaddr_storage *sockaddr, | ||
428 | int network_transport) | ||
429 | { | ||
430 | struct iscsi_portal_group *tpg; | ||
431 | struct iscsi_tpg_np *tpg_np; | ||
432 | struct iscsi_np *np; | ||
433 | bool match = false; | ||
434 | |||
435 | spin_lock(&tiqn->tiqn_tpg_lock); | ||
436 | list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) { | ||
437 | |||
438 | spin_lock(&tpg->tpg_np_lock); | ||
439 | list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { | ||
440 | np = tpg_np->tpg_np; | ||
441 | |||
442 | match = iscsit_check_np_match(sockaddr, np, | ||
443 | network_transport); | ||
444 | if (match == true) | ||
445 | break; | ||
446 | } | ||
447 | spin_unlock(&tpg->tpg_np_lock); | ||
448 | } | ||
449 | spin_unlock(&tiqn->tiqn_tpg_lock); | ||
450 | |||
451 | return match; | ||
452 | } | ||
453 | |||
425 | struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | 454 | struct iscsi_tpg_np *iscsit_tpg_add_network_portal( |
426 | struct iscsi_portal_group *tpg, | 455 | struct iscsi_portal_group *tpg, |
427 | struct __kernel_sockaddr_storage *sockaddr, | 456 | struct __kernel_sockaddr_storage *sockaddr, |
@@ -432,6 +461,16 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | |||
432 | struct iscsi_np *np; | 461 | struct iscsi_np *np; |
433 | struct iscsi_tpg_np *tpg_np; | 462 | struct iscsi_tpg_np *tpg_np; |
434 | 463 | ||
464 | if (!tpg_np_parent) { | ||
465 | if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr, | ||
466 | network_transport) == true) { | ||
467 | pr_err("Network Portal: %s already exists on a" | ||
468 | " different TPG on %s\n", ip_str, | ||
469 | tpg->tpg_tiqn->tiqn); | ||
470 | return ERR_PTR(-EEXIST); | ||
471 | } | ||
472 | } | ||
473 | |||
435 | tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL); | 474 | tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL); |
436 | if (!tpg_np) { | 475 | if (!tpg_np) { |
437 | pr_err("Unable to allocate memory for" | 476 | pr_err("Unable to allocate memory for" |
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 4efb61b8d001..43b7ac6c5b1c 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c | |||
@@ -609,6 +609,9 @@ static struct target_core_dev_attrib_attribute \ | |||
609 | __CONFIGFS_EATTR_RO(_name, \ | 609 | __CONFIGFS_EATTR_RO(_name, \ |
610 | target_core_dev_show_attr_##_name); | 610 | target_core_dev_show_attr_##_name); |
611 | 611 | ||
612 | DEF_DEV_ATTRIB(emulate_model_alias); | ||
613 | SE_DEV_ATTR(emulate_model_alias, S_IRUGO | S_IWUSR); | ||
614 | |||
612 | DEF_DEV_ATTRIB(emulate_dpo); | 615 | DEF_DEV_ATTRIB(emulate_dpo); |
613 | SE_DEV_ATTR(emulate_dpo, S_IRUGO | S_IWUSR); | 616 | SE_DEV_ATTR(emulate_dpo, S_IRUGO | S_IWUSR); |
614 | 617 | ||
@@ -681,6 +684,7 @@ SE_DEV_ATTR(max_write_same_len, S_IRUGO | S_IWUSR); | |||
681 | CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); | 684 | CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); |
682 | 685 | ||
683 | static struct configfs_attribute *target_core_dev_attrib_attrs[] = { | 686 | static struct configfs_attribute *target_core_dev_attrib_attrs[] = { |
687 | &target_core_dev_attrib_emulate_model_alias.attr, | ||
684 | &target_core_dev_attrib_emulate_dpo.attr, | 688 | &target_core_dev_attrib_emulate_dpo.attr, |
685 | &target_core_dev_attrib_emulate_fua_write.attr, | 689 | &target_core_dev_attrib_emulate_fua_write.attr, |
686 | &target_core_dev_attrib_emulate_fua_read.attr, | 690 | &target_core_dev_attrib_emulate_fua_read.attr, |
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index f2aa7543d20a..2e4d655471bc 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
@@ -713,6 +713,44 @@ int se_dev_set_max_write_same_len( | |||
713 | return 0; | 713 | return 0; |
714 | } | 714 | } |
715 | 715 | ||
716 | static void dev_set_t10_wwn_model_alias(struct se_device *dev) | ||
717 | { | ||
718 | const char *configname; | ||
719 | |||
720 | configname = config_item_name(&dev->dev_group.cg_item); | ||
721 | if (strlen(configname) >= 16) { | ||
722 | pr_warn("dev[%p]: Backstore name '%s' is too long for " | ||
723 | "INQUIRY_MODEL, truncating to 16 bytes\n", dev, | ||
724 | configname); | ||
725 | } | ||
726 | snprintf(&dev->t10_wwn.model[0], 16, "%s", configname); | ||
727 | } | ||
728 | |||
729 | int se_dev_set_emulate_model_alias(struct se_device *dev, int flag) | ||
730 | { | ||
731 | if (dev->export_count) { | ||
732 | pr_err("dev[%p]: Unable to change model alias" | ||
733 | " while export_count is %d\n", | ||
734 | dev, dev->export_count); | ||
735 | return -EINVAL; | ||
736 | } | ||
737 | |||
738 | if (flag != 0 && flag != 1) { | ||
739 | pr_err("Illegal value %d\n", flag); | ||
740 | return -EINVAL; | ||
741 | } | ||
742 | |||
743 | if (flag) { | ||
744 | dev_set_t10_wwn_model_alias(dev); | ||
745 | } else { | ||
746 | strncpy(&dev->t10_wwn.model[0], | ||
747 | dev->transport->inquiry_prod, 16); | ||
748 | } | ||
749 | dev->dev_attrib.emulate_model_alias = flag; | ||
750 | |||
751 | return 0; | ||
752 | } | ||
753 | |||
716 | int se_dev_set_emulate_dpo(struct se_device *dev, int flag) | 754 | int se_dev_set_emulate_dpo(struct se_device *dev, int flag) |
717 | { | 755 | { |
718 | if (flag != 0 && flag != 1) { | 756 | if (flag != 0 && flag != 1) { |
@@ -772,6 +810,12 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag) | |||
772 | pr_err("emulate_write_cache not supported for pSCSI\n"); | 810 | pr_err("emulate_write_cache not supported for pSCSI\n"); |
773 | return -EINVAL; | 811 | return -EINVAL; |
774 | } | 812 | } |
813 | if (dev->transport->get_write_cache) { | ||
814 | pr_warn("emulate_write_cache cannot be changed when underlying" | ||
815 | " HW reports WriteCacheEnabled, ignoring request\n"); | ||
816 | return 0; | ||
817 | } | ||
818 | |||
775 | dev->dev_attrib.emulate_write_cache = flag; | 819 | dev->dev_attrib.emulate_write_cache = flag; |
776 | pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", | 820 | pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", |
777 | dev, dev->dev_attrib.emulate_write_cache); | 821 | dev, dev->dev_attrib.emulate_write_cache); |
@@ -1182,24 +1226,18 @@ static struct se_lun *core_dev_get_lun(struct se_portal_group *tpg, u32 unpacked | |||
1182 | 1226 | ||
1183 | struct se_lun_acl *core_dev_init_initiator_node_lun_acl( | 1227 | struct se_lun_acl *core_dev_init_initiator_node_lun_acl( |
1184 | struct se_portal_group *tpg, | 1228 | struct se_portal_group *tpg, |
1229 | struct se_node_acl *nacl, | ||
1185 | u32 mapped_lun, | 1230 | u32 mapped_lun, |
1186 | char *initiatorname, | ||
1187 | int *ret) | 1231 | int *ret) |
1188 | { | 1232 | { |
1189 | struct se_lun_acl *lacl; | 1233 | struct se_lun_acl *lacl; |
1190 | struct se_node_acl *nacl; | ||
1191 | 1234 | ||
1192 | if (strlen(initiatorname) >= TRANSPORT_IQN_LEN) { | 1235 | if (strlen(nacl->initiatorname) >= TRANSPORT_IQN_LEN) { |
1193 | pr_err("%s InitiatorName exceeds maximum size.\n", | 1236 | pr_err("%s InitiatorName exceeds maximum size.\n", |
1194 | tpg->se_tpg_tfo->get_fabric_name()); | 1237 | tpg->se_tpg_tfo->get_fabric_name()); |
1195 | *ret = -EOVERFLOW; | 1238 | *ret = -EOVERFLOW; |
1196 | return NULL; | 1239 | return NULL; |
1197 | } | 1240 | } |
1198 | nacl = core_tpg_get_initiator_node_acl(tpg, initiatorname); | ||
1199 | if (!nacl) { | ||
1200 | *ret = -EINVAL; | ||
1201 | return NULL; | ||
1202 | } | ||
1203 | lacl = kzalloc(sizeof(struct se_lun_acl), GFP_KERNEL); | 1241 | lacl = kzalloc(sizeof(struct se_lun_acl), GFP_KERNEL); |
1204 | if (!lacl) { | 1242 | if (!lacl) { |
1205 | pr_err("Unable to allocate memory for struct se_lun_acl.\n"); | 1243 | pr_err("Unable to allocate memory for struct se_lun_acl.\n"); |
@@ -1210,7 +1248,8 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl( | |||
1210 | INIT_LIST_HEAD(&lacl->lacl_list); | 1248 | INIT_LIST_HEAD(&lacl->lacl_list); |
1211 | lacl->mapped_lun = mapped_lun; | 1249 | lacl->mapped_lun = mapped_lun; |
1212 | lacl->se_lun_nacl = nacl; | 1250 | lacl->se_lun_nacl = nacl; |
1213 | snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); | 1251 | snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", |
1252 | nacl->initiatorname); | ||
1214 | 1253 | ||
1215 | return lacl; | 1254 | return lacl; |
1216 | } | 1255 | } |
@@ -1390,6 +1429,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) | |||
1390 | dev->t10_alua.t10_dev = dev; | 1429 | dev->t10_alua.t10_dev = dev; |
1391 | 1430 | ||
1392 | dev->dev_attrib.da_dev = dev; | 1431 | dev->dev_attrib.da_dev = dev; |
1432 | dev->dev_attrib.emulate_model_alias = DA_EMULATE_MODEL_ALIAS; | ||
1393 | dev->dev_attrib.emulate_dpo = DA_EMULATE_DPO; | 1433 | dev->dev_attrib.emulate_dpo = DA_EMULATE_DPO; |
1394 | dev->dev_attrib.emulate_fua_write = DA_EMULATE_FUA_WRITE; | 1434 | dev->dev_attrib.emulate_fua_write = DA_EMULATE_FUA_WRITE; |
1395 | dev->dev_attrib.emulate_fua_read = DA_EMULATE_FUA_READ; | 1435 | dev->dev_attrib.emulate_fua_read = DA_EMULATE_FUA_READ; |
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index c57bbbc7a7d1..04c775cb3e65 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c | |||
@@ -354,9 +354,17 @@ static struct config_group *target_fabric_make_mappedlun( | |||
354 | ret = -EINVAL; | 354 | ret = -EINVAL; |
355 | goto out; | 355 | goto out; |
356 | } | 356 | } |
357 | if (mapped_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { | ||
358 | pr_err("Mapped LUN: %lu exceeds TRANSPORT_MAX_LUNS_PER_TPG" | ||
359 | "-1: %u for Target Portal Group: %u\n", mapped_lun, | ||
360 | TRANSPORT_MAX_LUNS_PER_TPG-1, | ||
361 | se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); | ||
362 | ret = -EINVAL; | ||
363 | goto out; | ||
364 | } | ||
357 | 365 | ||
358 | lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun, | 366 | lacl = core_dev_init_initiator_node_lun_acl(se_tpg, se_nacl, |
359 | config_item_name(acl_ci), &ret); | 367 | mapped_lun, &ret); |
360 | if (!lacl) { | 368 | if (!lacl) { |
361 | ret = -EINVAL; | 369 | ret = -EINVAL; |
362 | goto out; | 370 | goto out; |
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index b9c88497e8f0..ca36a38eb274 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c | |||
@@ -190,6 +190,11 @@ static int fd_configure_device(struct se_device *dev) | |||
190 | 190 | ||
191 | fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; | 191 | fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; |
192 | fd_dev->fd_queue_depth = dev->queue_depth; | 192 | fd_dev->fd_queue_depth = dev->queue_depth; |
193 | /* | ||
194 | * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB) | ||
195 | * based upon struct iovec limit for vfs_writev() | ||
196 | */ | ||
197 | dev->dev_attrib.max_write_same_len = 0x1000; | ||
193 | 198 | ||
194 | pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," | 199 | pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," |
195 | " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, | 200 | " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, |
@@ -328,6 +333,114 @@ fd_execute_sync_cache(struct se_cmd *cmd) | |||
328 | return 0; | 333 | return 0; |
329 | } | 334 | } |
330 | 335 | ||
336 | static unsigned char * | ||
337 | fd_setup_write_same_buf(struct se_cmd *cmd, struct scatterlist *sg, | ||
338 | unsigned int len) | ||
339 | { | ||
340 | struct se_device *se_dev = cmd->se_dev; | ||
341 | unsigned int block_size = se_dev->dev_attrib.block_size; | ||
342 | unsigned int i = 0, end; | ||
343 | unsigned char *buf, *p, *kmap_buf; | ||
344 | |||
345 | buf = kzalloc(min_t(unsigned int, len, PAGE_SIZE), GFP_KERNEL); | ||
346 | if (!buf) { | ||
347 | pr_err("Unable to allocate fd_execute_write_same buf\n"); | ||
348 | return NULL; | ||
349 | } | ||
350 | |||
351 | kmap_buf = kmap(sg_page(sg)) + sg->offset; | ||
352 | if (!kmap_buf) { | ||
353 | pr_err("kmap() failed in fd_setup_write_same\n"); | ||
354 | kfree(buf); | ||
355 | return NULL; | ||
356 | } | ||
357 | /* | ||
358 | * Fill local *buf to contain multiple WRITE_SAME blocks up to | ||
359 | * min(len, PAGE_SIZE) | ||
360 | */ | ||
361 | p = buf; | ||
362 | end = min_t(unsigned int, len, PAGE_SIZE); | ||
363 | |||
364 | while (i < end) { | ||
365 | memcpy(p, kmap_buf, block_size); | ||
366 | |||
367 | i += block_size; | ||
368 | p += block_size; | ||
369 | } | ||
370 | kunmap(sg_page(sg)); | ||
371 | |||
372 | return buf; | ||
373 | } | ||
374 | |||
375 | static sense_reason_t | ||
376 | fd_execute_write_same(struct se_cmd *cmd) | ||
377 | { | ||
378 | struct se_device *se_dev = cmd->se_dev; | ||
379 | struct fd_dev *fd_dev = FD_DEV(se_dev); | ||
380 | struct file *f = fd_dev->fd_file; | ||
381 | struct scatterlist *sg; | ||
382 | struct iovec *iov; | ||
383 | mm_segment_t old_fs; | ||
384 | sector_t nolb = sbc_get_write_same_sectors(cmd); | ||
385 | loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size; | ||
386 | unsigned int len, len_tmp, iov_num; | ||
387 | int i, rc; | ||
388 | unsigned char *buf; | ||
389 | |||
390 | if (!nolb) { | ||
391 | target_complete_cmd(cmd, SAM_STAT_GOOD); | ||
392 | return 0; | ||
393 | } | ||
394 | sg = &cmd->t_data_sg[0]; | ||
395 | |||
396 | if (cmd->t_data_nents > 1 || | ||
397 | sg->length != cmd->se_dev->dev_attrib.block_size) { | ||
398 | pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u" | ||
399 | " block_size: %u\n", cmd->t_data_nents, sg->length, | ||
400 | cmd->se_dev->dev_attrib.block_size); | ||
401 | return TCM_INVALID_CDB_FIELD; | ||
402 | } | ||
403 | |||
404 | len = len_tmp = nolb * se_dev->dev_attrib.block_size; | ||
405 | iov_num = DIV_ROUND_UP(len, PAGE_SIZE); | ||
406 | |||
407 | buf = fd_setup_write_same_buf(cmd, sg, len); | ||
408 | if (!buf) | ||
409 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
410 | |||
411 | iov = vzalloc(sizeof(struct iovec) * iov_num); | ||
412 | if (!iov) { | ||
413 | pr_err("Unable to allocate fd_execute_write_same iovecs\n"); | ||
414 | kfree(buf); | ||
415 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
416 | } | ||
417 | /* | ||
418 | * Map the single fabric received scatterlist block now populated | ||
419 | * in *buf into each iovec for I/O submission. | ||
420 | */ | ||
421 | for (i = 0; i < iov_num; i++) { | ||
422 | iov[i].iov_base = buf; | ||
423 | iov[i].iov_len = min_t(unsigned int, len_tmp, PAGE_SIZE); | ||
424 | len_tmp -= iov[i].iov_len; | ||
425 | } | ||
426 | |||
427 | old_fs = get_fs(); | ||
428 | set_fs(get_ds()); | ||
429 | rc = vfs_writev(f, &iov[0], iov_num, &pos); | ||
430 | set_fs(old_fs); | ||
431 | |||
432 | vfree(iov); | ||
433 | kfree(buf); | ||
434 | |||
435 | if (rc < 0 || rc != len) { | ||
436 | pr_err("vfs_writev() returned %d for write same\n", rc); | ||
437 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
438 | } | ||
439 | |||
440 | target_complete_cmd(cmd, SAM_STAT_GOOD); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
331 | static sense_reason_t | 444 | static sense_reason_t |
332 | fd_execute_rw(struct se_cmd *cmd) | 445 | fd_execute_rw(struct se_cmd *cmd) |
333 | { | 446 | { |
@@ -486,6 +599,7 @@ static sector_t fd_get_blocks(struct se_device *dev) | |||
486 | static struct sbc_ops fd_sbc_ops = { | 599 | static struct sbc_ops fd_sbc_ops = { |
487 | .execute_rw = fd_execute_rw, | 600 | .execute_rw = fd_execute_rw, |
488 | .execute_sync_cache = fd_execute_sync_cache, | 601 | .execute_sync_cache = fd_execute_sync_cache, |
602 | .execute_write_same = fd_execute_write_same, | ||
489 | }; | 603 | }; |
490 | 604 | ||
491 | static sense_reason_t | 605 | static sense_reason_t |
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index b526d23dcd4f..c73f4a950e23 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
@@ -154,6 +154,7 @@ static int iblock_configure_device(struct se_device *dev) | |||
154 | 154 | ||
155 | if (blk_queue_nonrot(q)) | 155 | if (blk_queue_nonrot(q)) |
156 | dev->dev_attrib.is_nonrot = 1; | 156 | dev->dev_attrib.is_nonrot = 1; |
157 | |||
157 | return 0; | 158 | return 0; |
158 | 159 | ||
159 | out_free_bioset: | 160 | out_free_bioset: |
@@ -390,10 +391,19 @@ iblock_execute_unmap(struct se_cmd *cmd) | |||
390 | sense_reason_t ret = 0; | 391 | sense_reason_t ret = 0; |
391 | int dl, bd_dl, err; | 392 | int dl, bd_dl, err; |
392 | 393 | ||
394 | /* We never set ANC_SUP */ | ||
395 | if (cmd->t_task_cdb[1]) | ||
396 | return TCM_INVALID_CDB_FIELD; | ||
397 | |||
398 | if (cmd->data_length == 0) { | ||
399 | target_complete_cmd(cmd, SAM_STAT_GOOD); | ||
400 | return 0; | ||
401 | } | ||
402 | |||
393 | if (cmd->data_length < 8) { | 403 | if (cmd->data_length < 8) { |
394 | pr_warn("UNMAP parameter list length %u too small\n", | 404 | pr_warn("UNMAP parameter list length %u too small\n", |
395 | cmd->data_length); | 405 | cmd->data_length); |
396 | return TCM_INVALID_PARAMETER_LIST; | 406 | return TCM_PARAMETER_LIST_LENGTH_ERROR; |
397 | } | 407 | } |
398 | 408 | ||
399 | buf = transport_kmap_data_sg(cmd); | 409 | buf = transport_kmap_data_sg(cmd); |
@@ -463,7 +473,7 @@ iblock_execute_write_same_unmap(struct se_cmd *cmd) | |||
463 | int rc; | 473 | int rc; |
464 | 474 | ||
465 | rc = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba, | 475 | rc = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba, |
466 | spc_get_write_same_sectors(cmd), GFP_KERNEL, 0); | 476 | sbc_get_write_same_sectors(cmd), GFP_KERNEL, 0); |
467 | if (rc < 0) { | 477 | if (rc < 0) { |
468 | pr_warn("blkdev_issue_discard() failed: %d\n", rc); | 478 | pr_warn("blkdev_issue_discard() failed: %d\n", rc); |
469 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 479 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
@@ -481,7 +491,7 @@ iblock_execute_write_same(struct se_cmd *cmd) | |||
481 | struct bio *bio; | 491 | struct bio *bio; |
482 | struct bio_list list; | 492 | struct bio_list list; |
483 | sector_t block_lba = cmd->t_task_lba; | 493 | sector_t block_lba = cmd->t_task_lba; |
484 | sector_t sectors = spc_get_write_same_sectors(cmd); | 494 | sector_t sectors = sbc_get_write_same_sectors(cmd); |
485 | 495 | ||
486 | sg = &cmd->t_data_sg[0]; | 496 | sg = &cmd->t_data_sg[0]; |
487 | 497 | ||
@@ -654,20 +664,24 @@ iblock_execute_rw(struct se_cmd *cmd) | |||
654 | u32 sg_num = sgl_nents; | 664 | u32 sg_num = sgl_nents; |
655 | sector_t block_lba; | 665 | sector_t block_lba; |
656 | unsigned bio_cnt; | 666 | unsigned bio_cnt; |
657 | int rw; | 667 | int rw = 0; |
658 | int i; | 668 | int i; |
659 | 669 | ||
660 | if (data_direction == DMA_TO_DEVICE) { | 670 | if (data_direction == DMA_TO_DEVICE) { |
671 | struct iblock_dev *ib_dev = IBLOCK_DEV(dev); | ||
672 | struct request_queue *q = bdev_get_queue(ib_dev->ibd_bd); | ||
661 | /* | 673 | /* |
662 | * Force data to disk if we pretend to not have a volatile | 674 | * Force writethrough using WRITE_FUA if a volatile write cache |
663 | * write cache, or the initiator set the Force Unit Access bit. | 675 | * is not enabled, or if initiator set the Force Unit Access bit. |
664 | */ | 676 | */ |
665 | if (dev->dev_attrib.emulate_write_cache == 0 || | 677 | if (q->flush_flags & REQ_FUA) { |
666 | (dev->dev_attrib.emulate_fua_write > 0 && | 678 | if (cmd->se_cmd_flags & SCF_FUA) |
667 | (cmd->se_cmd_flags & SCF_FUA))) | 679 | rw = WRITE_FUA; |
668 | rw = WRITE_FUA; | 680 | else if (!(q->flush_flags & REQ_FLUSH)) |
669 | else | 681 | rw = WRITE_FUA; |
682 | } else { | ||
670 | rw = WRITE; | 683 | rw = WRITE; |
684 | } | ||
671 | } else { | 685 | } else { |
672 | rw = READ; | 686 | rw = READ; |
673 | } | 687 | } |
@@ -774,6 +788,15 @@ iblock_parse_cdb(struct se_cmd *cmd) | |||
774 | return sbc_parse_cdb(cmd, &iblock_sbc_ops); | 788 | return sbc_parse_cdb(cmd, &iblock_sbc_ops); |
775 | } | 789 | } |
776 | 790 | ||
791 | bool iblock_get_write_cache(struct se_device *dev) | ||
792 | { | ||
793 | struct iblock_dev *ib_dev = IBLOCK_DEV(dev); | ||
794 | struct block_device *bd = ib_dev->ibd_bd; | ||
795 | struct request_queue *q = bdev_get_queue(bd); | ||
796 | |||
797 | return q->flush_flags & REQ_FLUSH; | ||
798 | } | ||
799 | |||
777 | static struct se_subsystem_api iblock_template = { | 800 | static struct se_subsystem_api iblock_template = { |
778 | .name = "iblock", | 801 | .name = "iblock", |
779 | .inquiry_prod = "IBLOCK", | 802 | .inquiry_prod = "IBLOCK", |
@@ -790,6 +813,7 @@ static struct se_subsystem_api iblock_template = { | |||
790 | .show_configfs_dev_params = iblock_show_configfs_dev_params, | 813 | .show_configfs_dev_params = iblock_show_configfs_dev_params, |
791 | .get_device_type = sbc_get_device_type, | 814 | .get_device_type = sbc_get_device_type, |
792 | .get_blocks = iblock_get_blocks, | 815 | .get_blocks = iblock_get_blocks, |
816 | .get_write_cache = iblock_get_write_cache, | ||
793 | }; | 817 | }; |
794 | 818 | ||
795 | static int __init iblock_module_init(void) | 819 | static int __init iblock_module_init(void) |
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 93e9c1f580b0..853bab60e362 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h | |||
@@ -25,6 +25,7 @@ int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32); | |||
25 | int se_dev_set_unmap_granularity(struct se_device *, u32); | 25 | int se_dev_set_unmap_granularity(struct se_device *, u32); |
26 | int se_dev_set_unmap_granularity_alignment(struct se_device *, u32); | 26 | int se_dev_set_unmap_granularity_alignment(struct se_device *, u32); |
27 | int se_dev_set_max_write_same_len(struct se_device *, u32); | 27 | int se_dev_set_max_write_same_len(struct se_device *, u32); |
28 | int se_dev_set_emulate_model_alias(struct se_device *, int); | ||
28 | int se_dev_set_emulate_dpo(struct se_device *, int); | 29 | int se_dev_set_emulate_dpo(struct se_device *, int); |
29 | int se_dev_set_emulate_fua_write(struct se_device *, int); | 30 | int se_dev_set_emulate_fua_write(struct se_device *, int); |
30 | int se_dev_set_emulate_fua_read(struct se_device *, int); | 31 | int se_dev_set_emulate_fua_read(struct se_device *, int); |
@@ -45,7 +46,7 @@ struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_device *, u3 | |||
45 | int core_dev_del_lun(struct se_portal_group *, u32); | 46 | int core_dev_del_lun(struct se_portal_group *, u32); |
46 | struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); | 47 | struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); |
47 | struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, | 48 | struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, |
48 | u32, char *, int *); | 49 | struct se_node_acl *, u32, int *); |
49 | int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, | 50 | int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, |
50 | struct se_lun_acl *, u32, u32); | 51 | struct se_lun_acl *, u32, u32); |
51 | int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, | 52 | int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, |
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 0457de362e68..e0b3c379aa14 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c | |||
@@ -256,10 +256,12 @@ static void rd_free_device(struct se_device *dev) | |||
256 | 256 | ||
257 | static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) | 257 | static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) |
258 | { | 258 | { |
259 | u32 i; | ||
260 | struct rd_dev_sg_table *sg_table; | 259 | struct rd_dev_sg_table *sg_table; |
260 | u32 i, sg_per_table = (RD_MAX_ALLOCATION_SIZE / | ||
261 | sizeof(struct scatterlist)); | ||
261 | 262 | ||
262 | for (i = 0; i < rd_dev->sg_table_count; i++) { | 263 | i = page / sg_per_table; |
264 | if (i < rd_dev->sg_table_count) { | ||
263 | sg_table = &rd_dev->sg_table_array[i]; | 265 | sg_table = &rd_dev->sg_table_array[i]; |
264 | if ((sg_table->page_start_offset <= page) && | 266 | if ((sg_table->page_start_offset <= page) && |
265 | (sg_table->page_end_offset >= page)) | 267 | (sg_table->page_end_offset >= page)) |
@@ -314,7 +316,19 @@ rd_execute_rw(struct se_cmd *cmd) | |||
314 | void *rd_addr; | 316 | void *rd_addr; |
315 | 317 | ||
316 | sg_miter_next(&m); | 318 | sg_miter_next(&m); |
319 | if (!(u32)m.length) { | ||
320 | pr_debug("RD[%u]: invalid sgl %p len %zu\n", | ||
321 | dev->rd_dev_id, m.addr, m.length); | ||
322 | sg_miter_stop(&m); | ||
323 | return TCM_INCORRECT_AMOUNT_OF_DATA; | ||
324 | } | ||
317 | len = min((u32)m.length, src_len); | 325 | len = min((u32)m.length, src_len); |
326 | if (len > rd_size) { | ||
327 | pr_debug("RD[%u]: size underrun page %d offset %d " | ||
328 | "size %d\n", dev->rd_dev_id, | ||
329 | rd_page, rd_offset, rd_size); | ||
330 | len = rd_size; | ||
331 | } | ||
318 | m.consumed = len; | 332 | m.consumed = len; |
319 | 333 | ||
320 | rd_addr = sg_virt(rd_sg) + rd_offset; | 334 | rd_addr = sg_virt(rd_sg) + rd_offset; |
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index a664c664a31a..290230de2c53 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
@@ -105,7 +105,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd) | |||
105 | return 0; | 105 | return 0; |
106 | } | 106 | } |
107 | 107 | ||
108 | sector_t spc_get_write_same_sectors(struct se_cmd *cmd) | 108 | sector_t sbc_get_write_same_sectors(struct se_cmd *cmd) |
109 | { | 109 | { |
110 | u32 num_blocks; | 110 | u32 num_blocks; |
111 | 111 | ||
@@ -126,7 +126,7 @@ sector_t spc_get_write_same_sectors(struct se_cmd *cmd) | |||
126 | return cmd->se_dev->transport->get_blocks(cmd->se_dev) - | 126 | return cmd->se_dev->transport->get_blocks(cmd->se_dev) - |
127 | cmd->t_task_lba + 1; | 127 | cmd->t_task_lba + 1; |
128 | } | 128 | } |
129 | EXPORT_SYMBOL(spc_get_write_same_sectors); | 129 | EXPORT_SYMBOL(sbc_get_write_same_sectors); |
130 | 130 | ||
131 | static sense_reason_t | 131 | static sense_reason_t |
132 | sbc_emulate_noop(struct se_cmd *cmd) | 132 | sbc_emulate_noop(struct se_cmd *cmd) |
@@ -233,7 +233,7 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) | |||
233 | static sense_reason_t | 233 | static sense_reason_t |
234 | sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops) | 234 | sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops) |
235 | { | 235 | { |
236 | unsigned int sectors = spc_get_write_same_sectors(cmd); | 236 | unsigned int sectors = sbc_get_write_same_sectors(cmd); |
237 | 237 | ||
238 | if ((flags[0] & 0x04) || (flags[0] & 0x02)) { | 238 | if ((flags[0] & 0x04) || (flags[0] & 0x02)) { |
239 | pr_err("WRITE_SAME PBDATA and LBDATA" | 239 | pr_err("WRITE_SAME PBDATA and LBDATA" |
@@ -486,7 +486,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
486 | */ | 486 | */ |
487 | if (cmd->t_task_lba || sectors) { | 487 | if (cmd->t_task_lba || sectors) { |
488 | if (sbc_check_valid_sectors(cmd) < 0) | 488 | if (sbc_check_valid_sectors(cmd) < 0) |
489 | return TCM_INVALID_CDB_FIELD; | 489 | return TCM_ADDRESS_OUT_OF_RANGE; |
490 | } | 490 | } |
491 | cmd->execute_cmd = ops->execute_sync_cache; | 491 | cmd->execute_cmd = ops->execute_sync_cache; |
492 | break; | 492 | break; |
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 2d88f087d961..4cb667d720a7 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c | |||
@@ -66,8 +66,8 @@ static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) | |||
66 | spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); | 66 | spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); |
67 | } | 67 | } |
68 | 68 | ||
69 | static sense_reason_t | 69 | sense_reason_t |
70 | spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) | 70 | spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf) |
71 | { | 71 | { |
72 | struct se_lun *lun = cmd->se_lun; | 72 | struct se_lun *lun = cmd->se_lun; |
73 | struct se_device *dev = cmd->se_dev; | 73 | struct se_device *dev = cmd->se_dev; |
@@ -104,6 +104,7 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf) | |||
104 | 104 | ||
105 | return 0; | 105 | return 0; |
106 | } | 106 | } |
107 | EXPORT_SYMBOL(spc_emulate_inquiry_std); | ||
107 | 108 | ||
108 | /* unit serial number */ | 109 | /* unit serial number */ |
109 | static sense_reason_t | 110 | static sense_reason_t |
@@ -160,7 +161,7 @@ static void spc_parse_naa_6h_vendor_specific(struct se_device *dev, | |||
160 | * Device identification VPD, for a complete list of | 161 | * Device identification VPD, for a complete list of |
161 | * DESIGNATOR TYPEs see spc4r17 Table 459. | 162 | * DESIGNATOR TYPEs see spc4r17 Table 459. |
162 | */ | 163 | */ |
163 | static sense_reason_t | 164 | sense_reason_t |
164 | spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) | 165 | spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) |
165 | { | 166 | { |
166 | struct se_device *dev = cmd->se_dev; | 167 | struct se_device *dev = cmd->se_dev; |
@@ -404,17 +405,33 @@ check_scsi_name: | |||
404 | buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */ | 405 | buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */ |
405 | return 0; | 406 | return 0; |
406 | } | 407 | } |
408 | EXPORT_SYMBOL(spc_emulate_evpd_83); | ||
409 | |||
410 | static bool | ||
411 | spc_check_dev_wce(struct se_device *dev) | ||
412 | { | ||
413 | bool wce = false; | ||
414 | |||
415 | if (dev->transport->get_write_cache) | ||
416 | wce = dev->transport->get_write_cache(dev); | ||
417 | else if (dev->dev_attrib.emulate_write_cache > 0) | ||
418 | wce = true; | ||
419 | |||
420 | return wce; | ||
421 | } | ||
407 | 422 | ||
408 | /* Extended INQUIRY Data VPD Page */ | 423 | /* Extended INQUIRY Data VPD Page */ |
409 | static sense_reason_t | 424 | static sense_reason_t |
410 | spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) | 425 | spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) |
411 | { | 426 | { |
427 | struct se_device *dev = cmd->se_dev; | ||
428 | |||
412 | buf[3] = 0x3c; | 429 | buf[3] = 0x3c; |
413 | /* Set HEADSUP, ORDSUP, SIMPSUP */ | 430 | /* Set HEADSUP, ORDSUP, SIMPSUP */ |
414 | buf[5] = 0x07; | 431 | buf[5] = 0x07; |
415 | 432 | ||
416 | /* If WriteCache emulation is enabled, set V_SUP */ | 433 | /* If WriteCache emulation is enabled, set V_SUP */ |
417 | if (cmd->se_dev->dev_attrib.emulate_write_cache > 0) | 434 | if (spc_check_dev_wce(dev)) |
418 | buf[6] = 0x01; | 435 | buf[6] = 0x01; |
419 | return 0; | 436 | return 0; |
420 | } | 437 | } |
@@ -764,7 +781,7 @@ static int spc_modesense_caching(struct se_device *dev, u8 pc, u8 *p) | |||
764 | if (pc == 1) | 781 | if (pc == 1) |
765 | goto out; | 782 | goto out; |
766 | 783 | ||
767 | if (dev->dev_attrib.emulate_write_cache > 0) | 784 | if (spc_check_dev_wce(dev)) |
768 | p[2] = 0x04; /* Write Cache Enable */ | 785 | p[2] = 0x04; /* Write Cache Enable */ |
769 | p[12] = 0x20; /* Disabled Read Ahead */ | 786 | p[12] = 0x20; /* Disabled Read Ahead */ |
770 | 787 | ||
@@ -876,7 +893,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) | |||
876 | (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) | 893 | (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) |
877 | spc_modesense_write_protect(&buf[length], type); | 894 | spc_modesense_write_protect(&buf[length], type); |
878 | 895 | ||
879 | if ((dev->dev_attrib.emulate_write_cache > 0) && | 896 | if ((spc_check_dev_wce(dev)) && |
880 | (dev->dev_attrib.emulate_fua_write > 0)) | 897 | (dev->dev_attrib.emulate_fua_write > 0)) |
881 | spc_modesense_dpofua(&buf[length], type); | 898 | spc_modesense_dpofua(&buf[length], type); |
882 | 899 | ||
@@ -983,6 +1000,14 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd) | |||
983 | int ret = 0; | 1000 | int ret = 0; |
984 | int i; | 1001 | int i; |
985 | 1002 | ||
1003 | if (!cmd->data_length) { | ||
1004 | target_complete_cmd(cmd, GOOD); | ||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | if (cmd->data_length < off + 2) | ||
1009 | return TCM_PARAMETER_LIST_LENGTH_ERROR; | ||
1010 | |||
986 | buf = transport_kmap_data_sg(cmd); | 1011 | buf = transport_kmap_data_sg(cmd); |
987 | if (!buf) | 1012 | if (!buf) |
988 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1013 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
@@ -1007,6 +1032,11 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd) | |||
1007 | goto out; | 1032 | goto out; |
1008 | 1033 | ||
1009 | check_contents: | 1034 | check_contents: |
1035 | if (cmd->data_length < off + length) { | ||
1036 | ret = TCM_PARAMETER_LIST_LENGTH_ERROR; | ||
1037 | goto out; | ||
1038 | } | ||
1039 | |||
1010 | if (memcmp(buf + off, tbuf, length)) | 1040 | if (memcmp(buf + off, tbuf, length)) |
1011 | ret = TCM_INVALID_PARAMETER_LIST; | 1041 | ret = TCM_INVALID_PARAMETER_LIST; |
1012 | 1042 | ||
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index c6e0293ffdb0..d0b4dd95b91e 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c | |||
@@ -331,18 +331,6 @@ static void core_tmr_drain_state_list( | |||
331 | 331 | ||
332 | fe_count = atomic_read(&cmd->t_fe_count); | 332 | fe_count = atomic_read(&cmd->t_fe_count); |
333 | 333 | ||
334 | if (!(cmd->transport_state & CMD_T_ACTIVE)) { | ||
335 | pr_debug("LUN_RESET: got CMD_T_ACTIVE for" | ||
336 | " cdb: %p, t_fe_count: %d dev: %p\n", cmd, | ||
337 | fe_count, dev); | ||
338 | cmd->transport_state |= CMD_T_ABORTED; | ||
339 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
340 | |||
341 | core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); | ||
342 | continue; | ||
343 | } | ||
344 | pr_debug("LUN_RESET: Got !CMD_T_ACTIVE for cdb: %p," | ||
345 | " t_fe_count: %d dev: %p\n", cmd, fe_count, dev); | ||
346 | cmd->transport_state |= CMD_T_ABORTED; | 334 | cmd->transport_state |= CMD_T_ABORTED; |
347 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 335 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
348 | 336 | ||
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 5192ac0337f7..9169d6a5d7e4 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c | |||
@@ -111,16 +111,10 @@ struct se_node_acl *core_tpg_get_initiator_node_acl( | |||
111 | struct se_node_acl *acl; | 111 | struct se_node_acl *acl; |
112 | 112 | ||
113 | spin_lock_irq(&tpg->acl_node_lock); | 113 | spin_lock_irq(&tpg->acl_node_lock); |
114 | list_for_each_entry(acl, &tpg->acl_node_list, acl_list) { | 114 | acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); |
115 | if (!strcmp(acl->initiatorname, initiatorname) && | ||
116 | !acl->dynamic_node_acl) { | ||
117 | spin_unlock_irq(&tpg->acl_node_lock); | ||
118 | return acl; | ||
119 | } | ||
120 | } | ||
121 | spin_unlock_irq(&tpg->acl_node_lock); | 115 | spin_unlock_irq(&tpg->acl_node_lock); |
122 | 116 | ||
123 | return NULL; | 117 | return acl; |
124 | } | 118 | } |
125 | 119 | ||
126 | /* core_tpg_add_node_to_devs(): | 120 | /* core_tpg_add_node_to_devs(): |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index bd587b70661a..2030b608136d 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -907,15 +907,18 @@ int transport_dump_vpd_ident( | |||
907 | 907 | ||
908 | switch (vpd->device_identifier_code_set) { | 908 | switch (vpd->device_identifier_code_set) { |
909 | case 0x01: /* Binary */ | 909 | case 0x01: /* Binary */ |
910 | sprintf(buf, "T10 VPD Binary Device Identifier: %s\n", | 910 | snprintf(buf, sizeof(buf), |
911 | "T10 VPD Binary Device Identifier: %s\n", | ||
911 | &vpd->device_identifier[0]); | 912 | &vpd->device_identifier[0]); |
912 | break; | 913 | break; |
913 | case 0x02: /* ASCII */ | 914 | case 0x02: /* ASCII */ |
914 | sprintf(buf, "T10 VPD ASCII Device Identifier: %s\n", | 915 | snprintf(buf, sizeof(buf), |
916 | "T10 VPD ASCII Device Identifier: %s\n", | ||
915 | &vpd->device_identifier[0]); | 917 | &vpd->device_identifier[0]); |
916 | break; | 918 | break; |
917 | case 0x03: /* UTF-8 */ | 919 | case 0x03: /* UTF-8 */ |
918 | sprintf(buf, "T10 VPD UTF-8 Device Identifier: %s\n", | 920 | snprintf(buf, sizeof(buf), |
921 | "T10 VPD UTF-8 Device Identifier: %s\n", | ||
919 | &vpd->device_identifier[0]); | 922 | &vpd->device_identifier[0]); |
920 | break; | 923 | break; |
921 | default: | 924 | default: |
@@ -1514,6 +1517,7 @@ void transport_generic_request_failure(struct se_cmd *cmd, | |||
1514 | case TCM_UNSUPPORTED_SCSI_OPCODE: | 1517 | case TCM_UNSUPPORTED_SCSI_OPCODE: |
1515 | case TCM_INVALID_CDB_FIELD: | 1518 | case TCM_INVALID_CDB_FIELD: |
1516 | case TCM_INVALID_PARAMETER_LIST: | 1519 | case TCM_INVALID_PARAMETER_LIST: |
1520 | case TCM_PARAMETER_LIST_LENGTH_ERROR: | ||
1517 | case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: | 1521 | case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: |
1518 | case TCM_UNKNOWN_MODE_PAGE: | 1522 | case TCM_UNKNOWN_MODE_PAGE: |
1519 | case TCM_WRITE_PROTECTED: | 1523 | case TCM_WRITE_PROTECTED: |
@@ -2674,6 +2678,15 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, | |||
2674 | /* INVALID FIELD IN PARAMETER LIST */ | 2678 | /* INVALID FIELD IN PARAMETER LIST */ |
2675 | buffer[SPC_ASC_KEY_OFFSET] = 0x26; | 2679 | buffer[SPC_ASC_KEY_OFFSET] = 0x26; |
2676 | break; | 2680 | break; |
2681 | case TCM_PARAMETER_LIST_LENGTH_ERROR: | ||
2682 | /* CURRENT ERROR */ | ||
2683 | buffer[0] = 0x70; | ||
2684 | buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; | ||
2685 | /* ILLEGAL REQUEST */ | ||
2686 | buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; | ||
2687 | /* PARAMETER LIST LENGTH ERROR */ | ||
2688 | buffer[SPC_ASC_KEY_OFFSET] = 0x1a; | ||
2689 | break; | ||
2677 | case TCM_UNEXPECTED_UNSOLICITED_DATA: | 2690 | case TCM_UNEXPECTED_UNSOLICITED_DATA: |
2678 | /* CURRENT ERROR */ | 2691 | /* CURRENT ERROR */ |
2679 | buffer[0] = 0x70; | 2692 | buffer[0] = 0x70; |