[SCSI] qla2xxx: Verify login-state has transitioned to PRLI-completed.
[deliverable/linux.git] / drivers / scsi / qla2xxx / qla_init.c
index d9479c3fe5f81d17d5cce2c89663618da2697757..d31ac9bd81d98856f76676dd58dd55270f63854e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * QLogic Fibre Channel HBA Driver
- * Copyright (c)  2003-2010 QLogic Corporation
+ * Copyright (c)  2003-2011 QLogic Corporation
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
@@ -35,8 +35,6 @@ static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
 
 static int qla2x00_restart_isp(scsi_qla_host_t *);
 
-static int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
-
 static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
 static int qla84xx_init_chip(scsi_qla_host_t *);
 static int qla25xx_init_queues(struct qla_hw_data *);
@@ -385,8 +383,18 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
 
        switch (data[0]) {
        case MBS_COMMAND_COMPLETE:
+               /*
+                * Driver must validate login state - If PRLI not complete,
+                * force a relogin attempt via implicit LOGO, PLOGI, and PRLI
+                * requests.
+                */
+               rval = qla2x00_get_port_database(vha, fcport, 0);
+               if (rval != QLA_SUCCESS) {
+                       qla2x00_post_async_logout_work(vha, fcport, NULL);
+                       qla2x00_post_async_login_work(vha, fcport, NULL);
+                       break;
+               }
                if (fcport->flags & FCF_FCP2_DEVICE) {
-                       fcport->flags |= FCF_ASYNC_SENT;
                        qla2x00_post_async_adisc_work(vha, fcport, data);
                        break;
                }
@@ -397,7 +405,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
                if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
                        set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
                else
-                       qla2x00_mark_device_lost(vha, fcport, 1, 1);
+                       qla2x00_mark_device_lost(vha, fcport, 1, 0);
                break;
        case MBS_PORT_ID_USED:
                fcport->loop_id = data[1];
@@ -409,7 +417,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
                rval = qla2x00_find_new_loop_id(vha, fcport);
                if (rval != QLA_SUCCESS) {
                        fcport->flags &= ~FCF_ASYNC_SENT;
-                       qla2x00_mark_device_lost(vha, fcport, 1, 1);
+                       qla2x00_mark_device_lost(vha, fcport, 1, 0);
                        break;
                }
                qla2x00_post_async_login_work(vha, fcport, NULL);
@@ -441,7 +449,7 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
        if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
                set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
        else
-               qla2x00_mark_device_lost(vha, fcport, 1, 1);
+               qla2x00_mark_device_lost(vha, fcport, 1, 0);
 
        return;
 }
@@ -1967,7 +1975,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
                } else {
                        /* Mailbox cmd failed. Timeout on min_wait. */
                        if (time_after_eq(jiffies, mtime) ||
-                           (IS_QLA82XX(ha) && ha->flags.fw_hung))
+                               ha->flags.isp82xx_fw_hung)
                                break;
                }
 
@@ -3391,7 +3399,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
  * Context:
  *     Kernel context.
  */
-static int
+int
 qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev)
 {
        int     rval;
@@ -3945,8 +3953,13 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *vp;
        unsigned long flags;
+       fc_port_t *fcport;
 
-       vha->flags.online = 0;
+       /* For ISP82XX, driver waits for completion of the commands.
+        * online flag should be set.
+        */
+       if (!IS_QLA82XX(ha))
+               vha->flags.online = 0;
        ha->flags.chip_reset_done = 0;
        clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
        ha->qla_stats.total_isp_aborts++;
@@ -3954,7 +3967,10 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
        qla_printk(KERN_INFO, ha,
            "Performing ISP error recovery - ha= %p.\n", ha);
 
-       /* Chip reset does not apply to 82XX */
+       /* For ISP82XX, reset_chip is just disabling interrupts.
+        * Driver waits for the completion of the commands.
+        * the interrupts need to be enabled.
+        */
        if (!IS_QLA82XX(ha))
                ha->isp_ops->reset_chip(vha);
 
@@ -3980,14 +3996,31 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
                            LOOP_DOWN_TIME);
        }
 
+       /* Clear all async request states across all VPs. */
+       list_for_each_entry(fcport, &vha->vp_fcports, list)
+               fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
+       spin_lock_irqsave(&ha->vport_slock, flags);
+       list_for_each_entry(vp, &ha->vp_list, list) {
+               atomic_inc(&vp->vref_count);
+               spin_unlock_irqrestore(&ha->vport_slock, flags);
+
+               list_for_each_entry(fcport, &vp->vp_fcports, list)
+                       fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
+
+               spin_lock_irqsave(&ha->vport_slock, flags);
+               atomic_dec(&vp->vref_count);
+       }
+       spin_unlock_irqrestore(&ha->vport_slock, flags);
+
        if (!ha->flags.eeh_busy) {
                /* Make sure for ISP 82XX IO DMA is complete */
                if (IS_QLA82XX(ha)) {
-                       if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
-                               WAIT_HOST) == QLA_SUCCESS) {
-                               DEBUG2(qla_printk(KERN_INFO, ha,
-                               "Done wait for pending commands\n"));
-                       }
+                       qla82xx_chip_reset_cleanup(vha);
+
+                       /* Done waiting for pending commands.
+                        * Reset the online flag.
+                        */
+                       vha->flags.online = 0;
                }
 
                /* Requeue all commands in outstanding command list. */
@@ -5483,26 +5516,26 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha)
  *
  * Return:
  *     non-zero (if found)
- *     0 (if not found)
+ *     -1 (if not found)
  *
  * Context:
  *     Kernel context
  */
-uint8_t
+static int
 qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
 {
        int i, entries;
        uint8_t pid_match, wwn_match;
-       uint8_t priority;
+       int priority;
        uint32_t pid1, pid2;
        uint64_t wwn1, wwn2;
        struct qla_fcp_prio_entry *pri_entry;
        struct qla_hw_data *ha = vha->hw;
 
        if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled)
-               return 0;
+               return -1;
 
-       priority = 0;
+       priority = -1;
        entries = ha->fcp_prio_cfg->num_entries;
        pri_entry = &ha->fcp_prio_cfg->entry[0];
 
@@ -5585,7 +5618,7 @@ int
 qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
 {
        int ret;
-       uint8_t priority;
+       int priority;
        uint16_t mb[5];
 
        if (fcport->port_type != FCT_TARGET ||
@@ -5593,6 +5626,9 @@ qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
                return QLA_FUNCTION_FAILED;
 
        priority = qla24xx_get_fcp_prio(vha, fcport);
+       if (priority < 0)
+               return QLA_FUNCTION_FAILED;
+
        ret = qla24xx_set_fcp_prio(vha, fcport->loop_id, priority, mb);
        if (ret == QLA_SUCCESS)
                fcport->fcp_prio = priority;
This page took 0.03764 seconds and 5 git commands to generate.