]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
scsi: target: loopback: Fix READ with data and sensebytes
authorBodo Stroesser <bstroesser@ts.fujitsu.com>
Tue, 28 Apr 2020 18:26:17 +0000 (20:26 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 12 May 2020 02:20:19 +0000 (22:20 -0400)
We use tcm_loop with tape emulations running on tcmu.

In case application reads a short tape block with a longer READ, or a long
tape block with a short READ, according to SCC spec data has to be
tranferred _and_ sensebytes with ILI set and information field containing
the residual count. Similar problem also exists when using fixed block
size in READ.

Up to now tcm_loop is not prepared to handle sensebytes if input data is
provided, as in tcm_loop_queue_data_in() it only sets SAM_STAT_GOOD and, if
necessary, the residual count.

To fix the bug, the same handling for sensebytes as present in
tcm_loop_queue_status() must be done in tcm_loop_queue_data_in() also.

After adding this handling, the two function now are nearly identical, so I
created a single function with two wrappers.

Link: https://lore.kernel.org/r/20200428182617.32726-1-bstroesser@ts.fujitsu.com
Signed-off-by: Bodo Stroesser <bstroesser@ts.fujitsu.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/target/loopback/tcm_loop.c

index 3305b47fdf536f2aaeaf9cb7ed8aca000f998eac..16d5a4e117a273bee3db4ac17db80938c2186932 100644 (file)
@@ -545,32 +545,15 @@ static int tcm_loop_write_pending(struct se_cmd *se_cmd)
        return 0;
 }
 
-static int tcm_loop_queue_data_in(struct se_cmd *se_cmd)
+static int tcm_loop_queue_data_or_status(const char *func,
+               struct se_cmd *se_cmd, u8 scsi_status)
 {
        struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
                                struct tcm_loop_cmd, tl_se_cmd);
        struct scsi_cmnd *sc = tl_cmd->sc;
 
        pr_debug("%s() called for scsi_cmnd: %p cdb: 0x%02x\n",
-                __func__, sc, sc->cmnd[0]);
-
-       sc->result = SAM_STAT_GOOD;
-       set_host_byte(sc, DID_OK);
-       if ((se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) ||
-           (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT))
-               scsi_set_resid(sc, se_cmd->residual_count);
-       sc->scsi_done(sc);
-       return 0;
-}
-
-static int tcm_loop_queue_status(struct se_cmd *se_cmd)
-{
-       struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
-                               struct tcm_loop_cmd, tl_se_cmd);
-       struct scsi_cmnd *sc = tl_cmd->sc;
-
-       pr_debug("%s() called for scsi_cmnd: %p cdb: 0x%02x\n",
-                __func__, sc, sc->cmnd[0]);
+                func, sc, sc->cmnd[0]);
 
        if (se_cmd->sense_buffer &&
           ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
@@ -581,7 +564,7 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd)
                sc->result = SAM_STAT_CHECK_CONDITION;
                set_driver_byte(sc, DRIVER_SENSE);
        } else
-               sc->result = se_cmd->scsi_status;
+               sc->result = scsi_status;
 
        set_host_byte(sc, DID_OK);
        if ((se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) ||
@@ -591,6 +574,17 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd)
        return 0;
 }
 
+static int tcm_loop_queue_data_in(struct se_cmd *se_cmd)
+{
+       return tcm_loop_queue_data_or_status(__func__, se_cmd, SAM_STAT_GOOD);
+}
+
+static int tcm_loop_queue_status(struct se_cmd *se_cmd)
+{
+       return tcm_loop_queue_data_or_status(__func__,
+                                            se_cmd, se_cmd->scsi_status);
+}
+
 static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
 {
        struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,