diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-05-06 20:55:35 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-07-22 05:37:44 -0400 |
commit | dd3a5ad8e0c8706659f02c4a72b8c87f6f7ab479 (patch) | |
tree | 83e4bad30b9dcceb9f19632ffe5cf128609ad06e /drivers/target | |
parent | 1eb437a4ac1813f21424b8c9c39575fd61528a26 (diff) |
target: Fix WRITE_SAME_[16,32] number of blocks=0 case
This patch fixes the handling of WRITE_SAME_[16,32] emulation where a
WRITE_SAME_* CDB with number of blocks=0 was being rejected by SCSI
expected data transfer length overflow checking in target core.
It changes both CDB cases in transport_generic_cmd_sequencer() to use
dev->se_sub_dev->se_dev_attrib.block_size to match what sg_write_same
is sending us with --num=0. It also fixes target_emulate_write_same()
to properly determine the num_blocks with --num=0 case to determine the
remaining range for dev->transport->do_discard().
Reported-by: Chris Greiveldinger <chris.greiveldinger@rnanetworks.com>
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_cdb.c | 28 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 14 |
2 files changed, 32 insertions, 10 deletions
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 95195d718101..8d5a0fc3a220 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c | |||
@@ -1008,18 +1008,30 @@ target_emulate_unmap(struct se_task *task) | |||
1008 | * Note this is not used for TCM/pSCSI passthrough | 1008 | * Note this is not used for TCM/pSCSI passthrough |
1009 | */ | 1009 | */ |
1010 | static int | 1010 | static int |
1011 | target_emulate_write_same(struct se_task *task) | 1011 | target_emulate_write_same(struct se_task *task, int write_same32) |
1012 | { | 1012 | { |
1013 | struct se_cmd *cmd = task->task_se_cmd; | 1013 | struct se_cmd *cmd = task->task_se_cmd; |
1014 | struct se_device *dev = cmd->se_dev; | 1014 | struct se_device *dev = cmd->se_dev; |
1015 | sector_t lba = cmd->t_task.t_task_lba; | 1015 | sector_t range, lba = cmd->t_task.t_task_lba; |
1016 | unsigned int range; | 1016 | unsigned int num_blocks; |
1017 | int ret; | 1017 | int ret; |
1018 | /* | ||
1019 | * Extract num_blocks from the WRITE_SAME_* CDB. Then use the explict | ||
1020 | * range when non zero is supplied, otherwise calculate the remaining | ||
1021 | * range based on ->get_blocks() - starting LBA. | ||
1022 | */ | ||
1023 | if (write_same32) | ||
1024 | num_blocks = get_unaligned_be32(&cmd->t_task.t_task_cdb[28]); | ||
1025 | else | ||
1026 | num_blocks = get_unaligned_be32(&cmd->t_task.t_task_cdb[10]); | ||
1018 | 1027 | ||
1019 | range = (cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size); | 1028 | if (num_blocks != 0) |
1029 | range = num_blocks; | ||
1030 | else | ||
1031 | range = (dev->transport->get_blocks(dev) - lba); | ||
1020 | 1032 | ||
1021 | printk(KERN_INFO "WRITE_SAME UNMAP: LBA: %llu Range: %u\n", | 1033 | printk(KERN_INFO "WRITE_SAME UNMAP: LBA: %llu Range: %llu\n", |
1022 | (unsigned long long)lba, range); | 1034 | (unsigned long long)lba, (unsigned long long)range); |
1023 | 1035 | ||
1024 | ret = dev->transport->do_discard(dev, lba, range); | 1036 | ret = dev->transport->do_discard(dev, lba, range); |
1025 | if (ret < 0) { | 1037 | if (ret < 0) { |
@@ -1081,7 +1093,7 @@ transport_emulate_control_cdb(struct se_task *task) | |||
1081 | " for: %s\n", dev->transport->name); | 1093 | " for: %s\n", dev->transport->name); |
1082 | return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; | 1094 | return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; |
1083 | } | 1095 | } |
1084 | ret = target_emulate_write_same(task); | 1096 | ret = target_emulate_write_same(task, 0); |
1085 | break; | 1097 | break; |
1086 | case VARIABLE_LENGTH_CMD: | 1098 | case VARIABLE_LENGTH_CMD: |
1087 | service_action = | 1099 | service_action = |
@@ -1094,7 +1106,7 @@ transport_emulate_control_cdb(struct se_task *task) | |||
1094 | dev->transport->name); | 1106 | dev->transport->name); |
1095 | return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; | 1107 | return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; |
1096 | } | 1108 | } |
1097 | ret = target_emulate_write_same(task); | 1109 | ret = target_emulate_write_same(task, 1); |
1098 | break; | 1110 | break; |
1099 | default: | 1111 | default: |
1100 | printk(KERN_ERR "Unsupported VARIABLE_LENGTH_CMD SA:" | 1112 | printk(KERN_ERR "Unsupported VARIABLE_LENGTH_CMD SA:" |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index a29f6d3fc55b..bf401da05f35 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -3132,7 +3132,12 @@ static int transport_generic_cmd_sequencer( | |||
3132 | sectors = transport_get_sectors_32(cdb, cmd, §or_ret); | 3132 | sectors = transport_get_sectors_32(cdb, cmd, §or_ret); |
3133 | if (sector_ret) | 3133 | if (sector_ret) |
3134 | goto out_unsupported_cdb; | 3134 | goto out_unsupported_cdb; |
3135 | size = transport_get_size(sectors, cdb, cmd); | 3135 | |
3136 | if (sectors != 0) | ||
3137 | size = transport_get_size(sectors, cdb, cmd); | ||
3138 | else | ||
3139 | size = dev->se_sub_dev->se_dev_attrib.block_size; | ||
3140 | |||
3136 | cmd->t_task.t_task_lba = get_unaligned_be64(&cdb[12]); | 3141 | cmd->t_task.t_task_lba = get_unaligned_be64(&cdb[12]); |
3137 | cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; | 3142 | cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; |
3138 | 3143 | ||
@@ -3416,7 +3421,12 @@ static int transport_generic_cmd_sequencer( | |||
3416 | sectors = transport_get_sectors_16(cdb, cmd, §or_ret); | 3421 | sectors = transport_get_sectors_16(cdb, cmd, §or_ret); |
3417 | if (sector_ret) | 3422 | if (sector_ret) |
3418 | goto out_unsupported_cdb; | 3423 | goto out_unsupported_cdb; |
3419 | size = transport_get_size(sectors, cdb, cmd); | 3424 | |
3425 | if (sectors != 0) | ||
3426 | size = transport_get_size(sectors, cdb, cmd); | ||
3427 | else | ||
3428 | size = dev->se_sub_dev->se_dev_attrib.block_size; | ||
3429 | |||
3420 | cmd->t_task.t_task_lba = get_unaligned_be64(&cdb[2]); | 3430 | cmd->t_task.t_task_lba = get_unaligned_be64(&cdb[2]); |
3421 | passthrough = (dev->transport->transport_type == | 3431 | passthrough = (dev->transport->transport_type == |
3422 | TRANSPORT_PLUGIN_PHBA_PDEV); | 3432 | TRANSPORT_PLUGIN_PHBA_PDEV); |