diff options
author | Lee Duncan <lduncan@suse.com> | 2018-05-16 04:25:24 +0300 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2018-05-18 19:22:48 +0300 |
commit | bd81372065fa467e262150c70be885f47f9535df (patch) | |
tree | dfa782e8a1a792f76ca14dffb4b224c6174abebd /drivers/target/target_core_transport.c | |
parent | 51b910c3c70986a5a0a84eea11cb8e904e37ba8b (diff) | |
download | linux-bd81372065fa467e262150c70be885f47f9535df.tar.xz |
scsi: target: transport should handle st FM/EOM/ILI reads
When a tape drive is exported via LIO using the pscsi module, a read
that requests more bytes per block than the tape can supply returns an
empty buffer. This is because the pscsi pass-through target module sees
the "ILI" illegal length bit set and thinks there is no reason to return
the data.
This is a long-standing transport issue, since it assumes that no data
need be returned under a check condition, which isn't always the case
for tape.
Add in a check for tape reads with the ILI, EOM, or FM bits set, with a
sense code of NO_SENSE, treating such cases as if the read
succeeded. The layered tape driver then "does the right thing" when it
gets such a response.
Signed-off-by: Bodo Stroesser <bstroesser@ts.fujitsu.com>
Signed-off-by: Lee Duncan <lduncan@suse.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/target/target_core_transport.c')
-rw-r--r-- | drivers/target/target_core_transport.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3500aa5927f2..bde14f46ed5b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -779,7 +779,9 @@ EXPORT_SYMBOL(target_complete_cmd); void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) { - if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { + if ((scsi_status == SAM_STAT_GOOD || + cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) && + length < cmd->data_length) { if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { cmd->residual_count += cmd->data_length - length; } else { @@ -2084,12 +2086,24 @@ static void transport_complete_qf(struct se_cmd *cmd) goto queue_status; } - if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) + /* + * Check if we need to send a sense buffer from + * the struct se_cmd in question. We do NOT want + * to take this path of the IO has been marked as + * needing to be treated like a "normal read". This + * is the case if it's a tape read, and either the + * FM, EOM, or ILI bits are set, but there is no + * sense data. + */ + if (!(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) && + cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) goto queue_status; switch (cmd->data_direction) { case DMA_FROM_DEVICE: - if (cmd->scsi_status) + /* queue status if not treating this as a normal read */ + if (cmd->scsi_status && + !(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL)) goto queue_status; trace_target_cmd_complete(cmd); @@ -2194,9 +2208,15 @@ static void target_complete_ok_work(struct work_struct *work) /* * Check if we need to send a sense buffer from - * the struct se_cmd in question. + * the struct se_cmd in question. We do NOT want + * to take this path of the IO has been marked as + * needing to be treated like a "normal read". This + * is the case if it's a tape read, and either the + * FM, EOM, or ILI bits are set, but there is no + * sense data. */ - if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { + if (!(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) && + cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { WARN_ON(!cmd->scsi_status); ret = transport_send_check_condition_and_sense( cmd, 0, 1); @@ -2238,7 +2258,18 @@ static void target_complete_ok_work(struct work_struct *work) queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: - if (cmd->scsi_status) + /* + * if this is a READ-type IO, but SCSI status + * is set, then skip returning data and just + * return the status -- unless this IO is marked + * as needing to be treated as a normal read, + * in which case we want to go ahead and return + * the data. This happens, for example, for tape + * reads with the FM, EOM, or ILI bits set, with + * no sense data. + */ + if (cmd->scsi_status && + !(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL)) goto queue_status; atomic_long_add(cmd->data_length, |