Skip to content

Commit bd81372

Browse files
gonzoleemanmartinkpetersen
authored andcommitted
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 <[email protected]> Signed-off-by: Lee Duncan <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 51b910c commit bd81372

File tree

3 files changed

+62
-8
lines changed

3 files changed

+62
-8
lines changed

Diff for: drivers/target/target_core_pscsi.c

+24-2
Original file line numberDiff line numberDiff line change
@@ -689,8 +689,29 @@ static void pscsi_complete_cmd(struct se_cmd *cmd, u8 scsi_status,
689689
}
690690
after_mode_select:
691691

692-
if (scsi_status == SAM_STAT_CHECK_CONDITION)
692+
if (scsi_status == SAM_STAT_CHECK_CONDITION) {
693693
transport_copy_sense_to_cmd(cmd, req_sense);
694+
695+
/*
696+
* check for TAPE device reads with
697+
* FM/EOM/ILI set, so that we can get data
698+
* back despite framework assumption that a
699+
* check condition means there is no data
700+
*/
701+
if (sd->type == TYPE_TAPE &&
702+
cmd->data_direction == DMA_FROM_DEVICE) {
703+
/*
704+
* is sense data valid, fixed format,
705+
* and have FM, EOM, or ILI set?
706+
*/
707+
if (req_sense[0] == 0xf0 && /* valid, fixed format */
708+
req_sense[2] & 0xe0 && /* FM, EOM, or ILI */
709+
(req_sense[2] & 0xf) == 0) { /* key==NO_SENSE */
710+
pr_debug("Tape FM/EOM/ILI status detected. Treat as normal read.\n");
711+
cmd->se_cmd_flags |= SCF_TREAT_READ_AS_NORMAL;
712+
}
713+
}
714+
}
694715
}
695716

696717
enum {
@@ -1061,7 +1082,8 @@ static void pscsi_req_done(struct request *req, blk_status_t status)
10611082

10621083
switch (host_byte(result)) {
10631084
case DID_OK:
1064-
target_complete_cmd(cmd, scsi_status);
1085+
target_complete_cmd_with_length(cmd, scsi_status,
1086+
cmd->data_length - scsi_req(req)->resid_len);
10651087
break;
10661088
default:
10671089
pr_debug("PSCSI Host Byte exception at cmd: %p CDB:"

Diff for: drivers/target/target_core_transport.c

+37-6
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,9 @@ EXPORT_SYMBOL(target_complete_cmd);
779779

780780
void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
781781
{
782-
if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) {
782+
if ((scsi_status == SAM_STAT_GOOD ||
783+
cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) &&
784+
length < cmd->data_length) {
783785
if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
784786
cmd->residual_count += cmd->data_length - length;
785787
} else {
@@ -2084,12 +2086,24 @@ static void transport_complete_qf(struct se_cmd *cmd)
20842086
goto queue_status;
20852087
}
20862088

2087-
if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)
2089+
/*
2090+
* Check if we need to send a sense buffer from
2091+
* the struct se_cmd in question. We do NOT want
2092+
* to take this path of the IO has been marked as
2093+
* needing to be treated like a "normal read". This
2094+
* is the case if it's a tape read, and either the
2095+
* FM, EOM, or ILI bits are set, but there is no
2096+
* sense data.
2097+
*/
2098+
if (!(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) &&
2099+
cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)
20882100
goto queue_status;
20892101

20902102
switch (cmd->data_direction) {
20912103
case DMA_FROM_DEVICE:
2092-
if (cmd->scsi_status)
2104+
/* queue status if not treating this as a normal read */
2105+
if (cmd->scsi_status &&
2106+
!(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL))
20932107
goto queue_status;
20942108

20952109
trace_target_cmd_complete(cmd);
@@ -2194,9 +2208,15 @@ static void target_complete_ok_work(struct work_struct *work)
21942208

21952209
/*
21962210
* Check if we need to send a sense buffer from
2197-
* the struct se_cmd in question.
2211+
* the struct se_cmd in question. We do NOT want
2212+
* to take this path of the IO has been marked as
2213+
* needing to be treated like a "normal read". This
2214+
* is the case if it's a tape read, and either the
2215+
* FM, EOM, or ILI bits are set, but there is no
2216+
* sense data.
21982217
*/
2199-
if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
2218+
if (!(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) &&
2219+
cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
22002220
WARN_ON(!cmd->scsi_status);
22012221
ret = transport_send_check_condition_and_sense(
22022222
cmd, 0, 1);
@@ -2238,7 +2258,18 @@ static void target_complete_ok_work(struct work_struct *work)
22382258
queue_rsp:
22392259
switch (cmd->data_direction) {
22402260
case DMA_FROM_DEVICE:
2241-
if (cmd->scsi_status)
2261+
/*
2262+
* if this is a READ-type IO, but SCSI status
2263+
* is set, then skip returning data and just
2264+
* return the status -- unless this IO is marked
2265+
* as needing to be treated as a normal read,
2266+
* in which case we want to go ahead and return
2267+
* the data. This happens, for example, for tape
2268+
* reads with the FM, EOM, or ILI bits set, with
2269+
* no sense data.
2270+
*/
2271+
if (cmd->scsi_status &&
2272+
!(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL))
22422273
goto queue_status;
22432274

22442275
atomic_long_add(cmd->data_length,

Diff for: include/target/target_core_base.h

+1
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ enum se_cmd_flags_table {
143143
SCF_ACK_KREF = 0x00400000,
144144
SCF_USE_CPUID = 0x00800000,
145145
SCF_TASK_ATTR_SET = 0x01000000,
146+
SCF_TREAT_READ_AS_NORMAL = 0x02000000,
146147
};
147148

148149
/*

0 commit comments

Comments
 (0)