qla2xxx: Check for online flag instead of active reset when transmitting responses
authorDilip Kumar Uppugandla <dilip@purestorage.com>
Thu, 17 Dec 2015 19:57:11 +0000 (14:57 -0500)
committerNicholas Bellinger <nab@linux-iscsi.org>
Thu, 7 Jan 2016 21:57:50 +0000 (13:57 -0800)
Driver has following initialization sequence for Target mode

1. Driver initialization starts

2. ISP Abort is scheduled when the target is enabled.

qla2xxx [0000:04:00.0]-4807:25: ISP abort scheduled
qla2xxx [0000:04:00.0]-00af:25: Performing ISP error recovery - ha=ffff880caa9e0000.

3. DPC thread starts the ISP Abort

4. While DPC is resetting the chip and initializing the firmware, we get
   async events from the firmware about P2P mode, LOOP UP and PORT UPDATE.

5. PRLI from a initiator is delivered to us followed by a PLOGI and then a
   SCSI command which creates a session.

6. If the SCSI command is a WRITE in this case, we issue XFR RDY and it
   gets dropped as can be seen with messages RESET-XFR because ISP Abort
   is still active

qla2xxx [0000:04:00.0]-e902:25: RESET-XFR active/old-count/new-count = 1/1/1.

7. If the SCSI command is a READ, we issue RESPONSE and they get dropped
   as well because Abort is still active.

qla2xxx [0000:04:00.0]-e901:25: RESET-RSP active/old-count/new-count = 1/1/1

8. Now eventually, ISP Abort finishes clearing the DPC flags.

qla2xxx [0000:04:00.0]-8822:25: qla2x00_abort_isp succeeded.
qla2xxx [0000:04:00.0]-4808:25: ISP abort end.

9. Since we dropped SCSI commands silently (without any responses sent
   to the initiator) initiator waits for a SCSI timeout (which is 60
   seconds in our case), Sends an ABTS which fails since there
   no se_cmd found for the tag that ABTS is referencing as the
   commands were cleaned up in Step 6 and 7.

10. Initiator send an IO after the ABTS which succeed fine.

To fix the above case, the following changes have been made:
  - To prevent target from dropping commands silently, use the online flag
    instead to check for an active chip reset. Once the port is online during
    a chip reset phase, we are good to process the commands.
  - Clean up qla2x00_restart_isp to not set the online flag and process ATIO
    as it is unnecessary. During a chip reset, interrupts are enabled only
    after setting the online flag to 1, so ATIO's won't be missed and hence
    no need to process ATIO's after setting the online flag.

Signed-off-by: Dilip Kumar Uppugandla <dilip@purestorage.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_target.c

index 993dd25279ffc11a165602cb949338aa98ae1fd5..52a87657c7dd3e4945aad29e9b3cbf983b94efad 100644 (file)
@@ -3065,6 +3065,26 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
                        atomic_set(&vha->loop_state, LOOP_READY);
                        ql_dbg(ql_dbg_disc, vha, 0x2069,
                            "LOOP READY.\n");
+
+                       /*
+                        * Process any ATIO queue entries that came in
+                        * while we weren't online.
+                        */
+                       if (qla_tgt_mode_enabled(vha)) {
+                               if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
+                                       spin_lock_irqsave(&ha->tgt.atio_lock,
+                                           flags);
+                                       qlt_24xx_process_atio_queue(vha, 0);
+                                       spin_unlock_irqrestore(
+                                           &ha->tgt.atio_lock, flags);
+                               } else {
+                                       spin_lock_irqsave(&ha->hardware_lock,
+                                           flags);
+                                       qlt_24xx_process_atio_queue(vha, 1);
+                                       spin_unlock_irqrestore(
+                                           &ha->hardware_lock, flags);
+                               }
+                       }
                }
        }
 
@@ -4919,7 +4939,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
        struct rsp_que *rsp = ha->rsp_q_map[0];
-       unsigned long flags, flags2;
 
        /* If firmware needs to be loaded */
        if (qla2x00_isp_firmware(vha)) {
@@ -4941,19 +4960,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
                        /* Issue a marker after FW becomes ready. */
                        qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
 
-                       vha->flags.online = 1;
-
-                       /*
-                        * Process any ATIO queue entries that came in
-                        * while we weren't online.
-                        */
-                       spin_lock_irqsave(&ha->hardware_lock, flags);
-                       spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
-                       if (qla_tgt_mode_enabled(vha))
-                               qlt_24xx_process_atio_queue(vha, 1);
-                       spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
-                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
                        set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
                }
 
index da35f51ea2560a2f38425bcc33d963770d52c29b..c7ab9e69c881834efeea0c53ea42bb01ee39da7e 100644 (file)
@@ -229,7 +229,7 @@ static inline void qlt_decr_num_pend_cmds(struct scsi_qla_host *vha)
        spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags);
 }
 
-static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
+static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
        struct atio_from_isp *atio, uint8_t ha_locked)
 {
        ql_dbg(ql_dbg_tgt, vha, 0xe072,
@@ -285,7 +285,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
                break;
        }
 
-       return;
+       return false;
 }
 
 void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
@@ -1738,15 +1738,15 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
-       if (qla2x00_reset_active(vha) || mcmd->reset_count != ha->chip_reset) {
+       if (!vha->flags.online || mcmd->reset_count != ha->chip_reset) {
                /*
-                * Either a chip reset is active or this request was from
+                * Either the port is not online or this request was from
                 * previous life, just abort the processing.
                 */
                ql_dbg(ql_dbg_async, vha, 0xe100,
-                       "RESET-TMR active/old-count/new-count = %d/%d/%d.\n",
-                       qla2x00_reset_active(vha), mcmd->reset_count,
-                       ha->chip_reset);
+                       "RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+                       vha->flags.online, qla2x00_reset_active(vha),
+                       mcmd->reset_count, ha->chip_reset);
                ha->tgt.tgt_ops->free_mcmd(mcmd);
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
                return;
@@ -2693,17 +2693,17 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
        else
                vha->tgt_counters.core_qla_que_buf++;
 
-       if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) {
+       if (!vha->flags.online || cmd->reset_count != ha->chip_reset) {
                /*
-                * Either a chip reset is active or this request was from
+                * Either the port is not online or this request was from
                 * previous life, just abort the processing.
                 */
                cmd->state = QLA_TGT_STATE_PROCESSED;
                qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
                ql_dbg(ql_dbg_async, vha, 0xe101,
-                       "RESET-RSP active/old-count/new-count = %d/%d/%d.\n",
-                       qla2x00_reset_active(vha), cmd->reset_count,
-                       ha->chip_reset);
+                       "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
+                       vha->flags.online, qla2x00_reset_active(vha),
+                       cmd->reset_count, ha->chip_reset);
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
                return 0;
        }
@@ -2834,18 +2834,18 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
-       if (qla2x00_reset_active(vha) || (cmd->reset_count != ha->chip_reset) ||
+       if (!vha->flags.online || (cmd->reset_count != ha->chip_reset) ||
            (cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)) {
                /*
-                * Either a chip reset is active or this request was from
+                * 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);
                ql_dbg(ql_dbg_async, vha, 0xe102,
-                       "RESET-XFR active/old-count/new-count = %d/%d/%d.\n",
-                       qla2x00_reset_active(vha), cmd->reset_count,
-                       ha->chip_reset);
+                       "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+                       vha->flags.online, qla2x00_reset_active(vha),
+                       cmd->reset_count, ha->chip_reset);
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
                return 0;
        }