diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-01-13 15:01:34 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-01-18 03:30:22 -0500 |
commit | 91ec1d3535b2acf12c599045cc19ad9be3c6a47b (patch) | |
tree | 12a312b34c2a932832ca02d28c082e86ab7d2813 | |
parent | 9fbc8909876a2160044e71d376848973b9bfdc3f (diff) |
target: Add workaround for zero-length control CDB handling
This patch adds a work-around for handling zero allocation length
control CDBs (type SCF_SCSI_CONTROL_SG_IO_CDB) that was causing an
OOPs with the following raw calls:
# sg_raw -v /dev/sdd 3 0 0 0 0 0
# sg_raw -v /dev/sdd 0x1a 0 1 0 0 0
This patch will follow existing zero-length handling for data I/O
and silently return with GOOD status. This addresses the zero length
issue, but the proper long-term resolution for handling arbitary
allocation lengths will be to refactor out data-phase handling in
individual CDB emulation logic within target_core_cdb.c
Reported-by: Roland Dreier <roland@purestorage.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_transport.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2869fb7d2c05..50d6911d4120 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -3759,6 +3759,11 @@ transport_allocate_control_task(struct se_cmd *cmd) | |||
3759 | struct se_task *task; | 3759 | struct se_task *task; |
3760 | unsigned long flags; | 3760 | unsigned long flags; |
3761 | 3761 | ||
3762 | /* Workaround for handling zero-length control CDBs */ | ||
3763 | if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && | ||
3764 | !cmd->data_length) | ||
3765 | return 0; | ||
3766 | |||
3762 | task = transport_generic_get_task(cmd, cmd->data_direction); | 3767 | task = transport_generic_get_task(cmd, cmd->data_direction); |
3763 | if (!task) | 3768 | if (!task) |
3764 | return -ENOMEM; | 3769 | return -ENOMEM; |
@@ -3830,6 +3835,14 @@ int transport_generic_new_cmd(struct se_cmd *cmd) | |||
3830 | else if (!task_cdbs && (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) { | 3835 | else if (!task_cdbs && (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) { |
3831 | cmd->t_state = TRANSPORT_COMPLETE; | 3836 | cmd->t_state = TRANSPORT_COMPLETE; |
3832 | atomic_set(&cmd->t_transport_active, 1); | 3837 | atomic_set(&cmd->t_transport_active, 1); |
3838 | |||
3839 | if (cmd->t_task_cdb[0] == REQUEST_SENSE) { | ||
3840 | u8 ua_asc = 0, ua_ascq = 0; | ||
3841 | |||
3842 | core_scsi3_ua_clear_for_request_sense(cmd, | ||
3843 | &ua_asc, &ua_ascq); | ||
3844 | } | ||
3845 | |||
3833 | INIT_WORK(&cmd->work, target_complete_ok_work); | 3846 | INIT_WORK(&cmd->work, target_complete_ok_work); |
3834 | queue_work(target_completion_wq, &cmd->work); | 3847 | queue_work(target_completion_wq, &cmd->work); |
3835 | return 0; | 3848 | return 0; |