diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-11-07 23:01:10 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-11-15 15:04:52 -0500 |
commit | cd063bef414c51d79b9c6ea7a8ef8f9d319529bc (patch) | |
tree | 7c003f3c6e865cc0eaf4df43683a37802ce4cb5d | |
parent | 1920ed61fbbbb38919edfb2427b0b1fd4e4ad8d9 (diff) |
target/sbc: Seperate WRITE_SAME based on UNMAP flag in sbc_ops
This patch adds a new sbc_ops->execute_write_same_unmap() caller for use
with WRITE_SAME w/ UNMAP=1, and performs the ->execute_cmd() setup based
this bit within sbc_setup_write_same() code.
Also, makes the changes in sbc_parse_cdb() to handle a sense_reason_t
return from sbc_setup_write_same() on error.
Reported-by: Christoph Hellwig <hch@lst.de>
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_sbc.c | 51 | ||||
-rw-r--r-- | include/target/target_core_backend.h | 1 |
2 files changed, 24 insertions, 28 deletions
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index b8024219cd4f..a5a8f463004b 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
@@ -235,26 +235,30 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb) | |||
235 | return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; | 235 | return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32; |
236 | } | 236 | } |
237 | 237 | ||
238 | static int sbc_write_same_supported(struct se_device *dev, | 238 | static sense_reason_t |
239 | unsigned char *flags) | 239 | sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops) |
240 | { | 240 | { |
241 | if ((flags[0] & 0x04) || (flags[0] & 0x02)) { | 241 | if ((flags[0] & 0x04) || (flags[0] & 0x02)) { |
242 | pr_err("WRITE_SAME PBDATA and LBDATA" | 242 | pr_err("WRITE_SAME PBDATA and LBDATA" |
243 | " bits not supported for Block Discard" | 243 | " bits not supported for Block Discard" |
244 | " Emulation\n"); | 244 | " Emulation\n"); |
245 | return -ENOSYS; | 245 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
246 | } | 246 | } |
247 | |||
248 | /* | 247 | /* |
249 | * Currently for the emulated case we only accept | 248 | * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting |
250 | * tpws with the UNMAP=1 bit set. | 249 | * translated into block discard requests within backend code. |
251 | */ | 250 | */ |
252 | if (!(flags[0] & 0x08)) { | 251 | if (flags[0] & 0x08) { |
253 | pr_err("WRITE_SAME w/o UNMAP bit not" | 252 | if (!ops->execute_write_same_unmap) |
254 | " supported for Block Discard Emulation\n"); | 253 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
255 | return -ENOSYS; | 254 | |
255 | cmd->execute_cmd = ops->execute_write_same_unmap; | ||
256 | return 0; | ||
256 | } | 257 | } |
258 | if (!ops->execute_write_same) | ||
259 | return TCM_UNSUPPORTED_SCSI_OPCODE; | ||
257 | 260 | ||
261 | cmd->execute_cmd = ops->execute_write_same; | ||
258 | return 0; | 262 | return 0; |
259 | } | 263 | } |
260 | 264 | ||
@@ -418,9 +422,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
418 | cmd->se_cmd_flags |= SCF_FUA; | 422 | cmd->se_cmd_flags |= SCF_FUA; |
419 | break; | 423 | break; |
420 | case WRITE_SAME_32: | 424 | case WRITE_SAME_32: |
421 | if (!ops->execute_write_same) | ||
422 | return TCM_UNSUPPORTED_SCSI_OPCODE; | ||
423 | |||
424 | sectors = transport_get_sectors_32(cdb); | 425 | sectors = transport_get_sectors_32(cdb); |
425 | if (!sectors) { | 426 | if (!sectors) { |
426 | pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" | 427 | pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not" |
@@ -431,9 +432,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
431 | size = sbc_get_size(cmd, 1); | 432 | size = sbc_get_size(cmd, 1); |
432 | cmd->t_task_lba = get_unaligned_be64(&cdb[12]); | 433 | cmd->t_task_lba = get_unaligned_be64(&cdb[12]); |
433 | 434 | ||
434 | if (sbc_write_same_supported(dev, &cdb[10]) < 0) | 435 | ret = sbc_setup_write_same(cmd, &cdb[10], ops); |
435 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 436 | if (ret < 0) |
436 | cmd->execute_cmd = ops->execute_write_same; | 437 | return ret; |
437 | break; | 438 | break; |
438 | default: | 439 | default: |
439 | pr_err("VARIABLE_LENGTH_CMD service action" | 440 | pr_err("VARIABLE_LENGTH_CMD service action" |
@@ -495,9 +496,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
495 | cmd->execute_cmd = ops->execute_unmap; | 496 | cmd->execute_cmd = ops->execute_unmap; |
496 | break; | 497 | break; |
497 | case WRITE_SAME_16: | 498 | case WRITE_SAME_16: |
498 | if (!ops->execute_write_same) | ||
499 | return TCM_UNSUPPORTED_SCSI_OPCODE; | ||
500 | |||
501 | sectors = transport_get_sectors_16(cdb); | 499 | sectors = transport_get_sectors_16(cdb); |
502 | if (!sectors) { | 500 | if (!sectors) { |
503 | pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); | 501 | pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); |
@@ -507,14 +505,11 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
507 | size = sbc_get_size(cmd, 1); | 505 | size = sbc_get_size(cmd, 1); |
508 | cmd->t_task_lba = get_unaligned_be64(&cdb[2]); | 506 | cmd->t_task_lba = get_unaligned_be64(&cdb[2]); |
509 | 507 | ||
510 | if (sbc_write_same_supported(dev, &cdb[1]) < 0) | 508 | ret = sbc_setup_write_same(cmd, &cdb[1], ops); |
511 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 509 | if (ret < 0) |
512 | cmd->execute_cmd = ops->execute_write_same; | 510 | return ret; |
513 | break; | 511 | break; |
514 | case WRITE_SAME: | 512 | case WRITE_SAME: |
515 | if (!ops->execute_write_same) | ||
516 | return TCM_UNSUPPORTED_SCSI_OPCODE; | ||
517 | |||
518 | sectors = transport_get_sectors_10(cdb); | 513 | sectors = transport_get_sectors_10(cdb); |
519 | if (!sectors) { | 514 | if (!sectors) { |
520 | pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); | 515 | pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); |
@@ -528,9 +523,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
528 | * Follow sbcr26 with WRITE_SAME (10) and check for the existence | 523 | * Follow sbcr26 with WRITE_SAME (10) and check for the existence |
529 | * of byte 1 bit 3 UNMAP instead of original reserved field | 524 | * of byte 1 bit 3 UNMAP instead of original reserved field |
530 | */ | 525 | */ |
531 | if (sbc_write_same_supported(dev, &cdb[1]) < 0) | 526 | ret = sbc_setup_write_same(cmd, &cdb[1], ops); |
532 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 527 | if (ret < 0) |
533 | cmd->execute_cmd = ops->execute_write_same; | 528 | return ret; |
534 | break; | 529 | break; |
535 | case VERIFY: | 530 | case VERIFY: |
536 | size = 0; | 531 | size = 0; |
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index aa868090b9ab..3393ab10766c 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h | |||
@@ -41,6 +41,7 @@ struct sbc_ops { | |||
41 | sense_reason_t (*execute_rw)(struct se_cmd *cmd); | 41 | sense_reason_t (*execute_rw)(struct se_cmd *cmd); |
42 | sense_reason_t (*execute_sync_cache)(struct se_cmd *cmd); | 42 | sense_reason_t (*execute_sync_cache)(struct se_cmd *cmd); |
43 | sense_reason_t (*execute_write_same)(struct se_cmd *cmd); | 43 | sense_reason_t (*execute_write_same)(struct se_cmd *cmd); |
44 | sense_reason_t (*execute_write_same_unmap)(struct se_cmd *cmd); | ||
44 | sense_reason_t (*execute_unmap)(struct se_cmd *cmd); | 45 | sense_reason_t (*execute_unmap)(struct se_cmd *cmd); |
45 | }; | 46 | }; |
46 | 47 | ||