scsi: qla2xxx: target: Fix offline port handling and host reset handling
authorBart Van Assche <bvanassche@acm.org>
Wed, 17 Apr 2019 21:44:29 +0000 (14:44 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Mon, 29 Apr 2019 21:24:50 +0000 (17:24 -0400)
Remove the function qlt_abort_cmd_on_host_reset() because it can do the
following, all of which can cause a kernel crash:

- DMA unmapping while DMA is in progress.
- Call target_execute_cmd() while DMA is in progress.
- Call transport_generic_free_cmd() while the LIO core owns a command.

Instead of trying to abort a command asynchronously, set the 'aborted' flag
and handle the abort after the hardware has passed control back to the
tcm_qla2xxx driver.

Cc: Arun Easi <arun.easi@qlogic.com>
Cc: Himanshu Madhani <hmadhani@marvell.com>
Cc: Giridhar Malavali <gmalavali@marvell.com>
Fixes: c0cb44967b4a ("qla2xxx: Add Host reset handling in target mode.") # v3.18.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Acked-by: Himanshu Madhani <hmadhani@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/tcm_qla2xxx.c

index 4fc1474c5a261038d6322f60542e55174659a422..a41aaf071b52d24b973ff997c759e50c88869c68 100644 (file)
@@ -1837,15 +1837,10 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
                                        continue;
                                }
                                cmd = (struct qla_tgt_cmd *)sp;
-                               qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
+                               cmd->aborted = 1;
                                break;
                        case TYPE_TGT_TMCMD:
-                               /*
-                                * Currently, only ABTS response gets on the
-                                * outstanding_cmds[]
-                                */
-                               ha->tgt.tgt_ops->free_mcmd(
-                                  (struct qla_tgt_mgmt_cmd *)sp);
+                               /* Skip task management functions. */
                                break;
                        default:
                                break;
index e17ae3b7f0f61c3d901ff58b75e3c11eb289baea..2a021548162f3a86e7504a69412e1c5b3edaab94 100644 (file)
@@ -3268,7 +3268,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
        if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) ||
            (cmd->sess && cmd->sess->deleted)) {
                cmd->state = QLA_TGT_STATE_PROCESSED;
-               qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
                return 0;
        }
 
@@ -3297,7 +3296,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
                 * previous life, just abort the processing.
                 */
                cmd->state = QLA_TGT_STATE_PROCESSED;
-               qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
                ql_dbg_qp(ql_dbg_async, qpair, 0xe101,
                        "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
                        vha->flags.online, qla2x00_reset_active(vha),
@@ -3438,8 +3436,10 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
                 * Either the port is not online or this request was from
                 * previous life, just abort the processing.
                 */
-               cmd->state = QLA_TGT_STATE_NEED_DATA;
-               qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
+               cmd->aborted = 1;
+               cmd->write_data_transferred = 0;
+               cmd->state = QLA_TGT_STATE_DATA_IN;
+               vha->hw->tgt.tgt_ops->handle_data(cmd);
                ql_dbg_qp(ql_dbg_async, qpair, 0xe102,
                        "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
                        vha->flags.online, qla2x00_reset_active(vha),
@@ -3961,39 +3961,6 @@ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
        return cmd;
 }
 
-/* hardware_lock should be held by caller. */
-void
-qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
-{
-       struct qla_hw_data *ha = vha->hw;
-
-       if (cmd->sg_mapped)
-               qlt_unmap_sg(vha, cmd);
-
-       /* TODO: fix debug message type and ids. */
-       if (cmd->state == QLA_TGT_STATE_PROCESSED) {
-               ql_dbg(ql_dbg_io, vha, 0xff00,
-                   "HOST-ABORT: state=PROCESSED.\n");
-       } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) {
-               cmd->write_data_transferred = 0;
-               cmd->state = QLA_TGT_STATE_DATA_IN;
-
-               ql_dbg(ql_dbg_io, vha, 0xff01,
-                   "HOST-ABORT: state=DATA_IN.\n");
-
-               ha->tgt.tgt_ops->handle_data(cmd);
-               return;
-       } else {
-               ql_dbg(ql_dbg_io, vha, 0xff03,
-                   "HOST-ABORT: state=BAD(%d).\n",
-                   cmd->state);
-               dump_stack();
-       }
-
-       cmd->trc_flags |= TRC_FLUSH;
-       ha->tgt.tgt_ops->free_cmd(cmd);
-}
-
 /*
  * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
  */
index 727dd52963c2d96af75d0e020b172b11e5e6ca18..8fb197a4d740c48bd7b981bdcea2ece564fc517f 100644 (file)
@@ -889,9 +889,16 @@ struct qla_tgt_cmd {
        unsigned int term_exchg:1;
        unsigned int cmd_sent_to_fw:1;
        unsigned int cmd_in_wq:1;
-       unsigned int aborted:1;
        unsigned int released:1;
 
+       /*
+        * This variable may be set from outside the LIO and I/O completion
+        * callback functions. Do not declare this member variable as a
+        * bitfield to avoid a read-modify-write operation when this variable
+        * is set.
+        */
+       unsigned int aborted;
+
        struct scatterlist *sg; /* cmd data buffer SG vector */
        int sg_cnt;             /* SG segments count */
        int bufflen;            /* cmd buffer length */
@@ -1101,7 +1108,5 @@ extern void qlt_do_generation_tick(struct scsi_qla_host *, int *);
 
 void qlt_send_resp_ctio(struct qla_qpair *, struct qla_tgt_cmd *, uint8_t,
     uint8_t, uint8_t, uint8_t);
-extern void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *,
-    struct qla_tgt_cmd *);
 
 #endif /* __QLA_TARGET_H */
index aa2de81e2dcca979a15063cde656a91368a28481..9f0642b19c0edfcdd9de8a3027aa58f56e057599 100644 (file)
@@ -504,7 +504,8 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
        if (cmd->aborted) {
                spin_unlock_irqrestore(&cmd->cmd_lock, flags);
 
-               tcm_qla2xxx_free_cmd(cmd);
+               transport_generic_request_failure(&cmd->se_cmd,
+                       TCM_CHECK_CONDITION_ABORT_CMD);
                return;
        }
        spin_unlock_irqrestore(&cmd->cmd_lock, flags);