]> err.no Git - linux-2.6/blobdiff - drivers/scsi/qla2xxx/qla_init.c
[SCSI] qla2xxx: Issue proper ISP callbacks during stop-firmware.
[linux-2.6] / drivers / scsi / qla2xxx / qla_init.c
index d429e2f5c70e10b1fe5849eaab2cec1e7e5b27cd..597ac201969cae91c48c09c12380a8e4ecd3aecf 100644 (file)
@@ -37,6 +37,9 @@ static int qla2x00_restart_isp(scsi_qla_host_t *);
 
 static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev);
 
+static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
+static int qla84xx_init_chip(scsi_qla_host_t *);
+
 /****************************************************************************/
 /*                QLogic ISP2x00 Hardware Support Functions.                */
 /****************************************************************************/
@@ -106,6 +109,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
                rval = qla2x00_setup_chip(ha);
                if (rval)
                        return (rval);
+               qla2xxx_get_flash_info(ha);
+       }
+       if (IS_QLA84XX(ha)) {
+               ha->cs84xx = qla84xx_get_chip(ha);
+               if (!ha->cs84xx) {
+                       qla_printk(KERN_ERR, ha,
+                           "Unable to configure ISP84XX.\n");
+                       return QLA_FUNCTION_FAILED;
+               }
        }
        rval = qla2x00_init_rings(ha);
 
@@ -322,6 +334,8 @@ static int
 qla2x00_isp_firmware(scsi_qla_host_t *ha)
 {
        int  rval;
+       uint16_t loop_id, topo, sw_cap;
+       uint8_t domain, area, al_pa;
 
        /* Assume loading risc code */
        rval = QLA_FUNCTION_FAILED;
@@ -333,6 +347,11 @@ qla2x00_isp_firmware(scsi_qla_host_t *ha)
 
                /* Verify checksum of loaded RISC code. */
                rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address);
+               if (rval == QLA_SUCCESS) {
+                       /* And, verify we are not in ROM code. */
+                       rval = qla2x00_get_adapter_id(ha, &loop_id, &al_pa,
+                           &area, &domain, &topo, &sw_cap);
+               }
        }
 
        if (rval) {
@@ -710,7 +729,7 @@ qla24xx_chip_diag(scsi_qla_host_t *ha)
        /* Perform RISC reset. */
        qla24xx_reset_risc(ha);
 
-       ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
+       ha->fw_transfer_size = REQUEST_ENTRY_SIZE * ha->request_q_length;
 
        rval = qla2x00_mbx_reg_test(ha);
        if (rval) {
@@ -756,42 +775,16 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
                mem_size = (ha->fw_memory_size - 0x100000 + 1) *
                    sizeof(uint32_t);
 
-               /* Allocate memory for Extended Trace Buffer. */
-               tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
-                   GFP_KERNEL);
-               if (!tc) {
-                       qla_printk(KERN_WARNING, ha, "Unable to allocate "
-                           "(%d KB) for EFT.\n", EFT_SIZE / 1024);
-                       goto cont_alloc;
-               }
-
-               memset(tc, 0, EFT_SIZE);
-               rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
-               if (rval) {
-                       qla_printk(KERN_WARNING, ha, "Unable to initialize "
-                           "EFT (%d).\n", rval);
-                       dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
-                           tc_dma);
-                       goto cont_alloc;
-               }
-
-               qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
-                   EFT_SIZE / 1024);
-
-               eft_size = EFT_SIZE;
-               ha->eft_dma = tc_dma;
-               ha->eft = tc;
-
                /* Allocate memory for Fibre Channel Event Buffer. */
                if (!IS_QLA25XX(ha))
-                       goto cont_alloc;
+                       goto try_eft;
 
                tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
                    GFP_KERNEL);
                if (!tc) {
                        qla_printk(KERN_WARNING, ha, "Unable to allocate "
                            "(%d KB) for FCE.\n", FCE_SIZE / 1024);
-                       goto cont_alloc;
+                       goto try_eft;
                }
 
                memset(tc, 0, FCE_SIZE);
@@ -803,7 +796,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
                        dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
                            tc_dma);
                        ha->flags.fce_enabled = 0;
-                       goto cont_alloc;
+                       goto try_eft;
                }
 
                qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
@@ -813,6 +806,32 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
                ha->flags.fce_enabled = 1;
                ha->fce_dma = tc_dma;
                ha->fce = tc;
+try_eft:
+               /* Allocate memory for Extended Trace Buffer. */
+               tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
+                   GFP_KERNEL);
+               if (!tc) {
+                       qla_printk(KERN_WARNING, ha, "Unable to allocate "
+                           "(%d KB) for EFT.\n", EFT_SIZE / 1024);
+                       goto cont_alloc;
+               }
+
+               memset(tc, 0, EFT_SIZE);
+               rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
+               if (rval) {
+                       qla_printk(KERN_WARNING, ha, "Unable to initialize "
+                           "EFT (%d).\n", rval);
+                       dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
+                           tc_dma);
+                       goto cont_alloc;
+               }
+
+               qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
+                   EFT_SIZE / 1024);
+
+               eft_size = EFT_SIZE;
+               ha->eft_dma = tc_dma;
+               ha->eft = tc;
        }
 cont_alloc:
        req_q_size = ha->request_q_length * sizeof(request_t);
@@ -1242,10 +1261,10 @@ static int
 qla2x00_fw_ready(scsi_qla_host_t *ha)
 {
        int             rval;
-       unsigned long   wtime, mtime;
+       unsigned long   wtime, mtime, cs84xx_time;
        uint16_t        min_wait;       /* Minimum wait time if loop is down */
        uint16_t        wait_time;      /* Wait time if loop is coming ready */
-       uint16_t        fw_state;
+       uint16_t        state[3];
 
        rval = QLA_SUCCESS;
 
@@ -1274,12 +1293,34 @@ qla2x00_fw_ready(scsi_qla_host_t *ha)
            ha->host_no));
 
        do {
-               rval = qla2x00_get_firmware_state(ha, &fw_state);
+               rval = qla2x00_get_firmware_state(ha, state);
                if (rval == QLA_SUCCESS) {
-                       if (fw_state < FSTATE_LOSS_OF_SYNC) {
+                       if (state[0] < FSTATE_LOSS_OF_SYNC) {
                                ha->device_flags &= ~DFLG_NO_CABLE;
                        }
-                       if (fw_state == FSTATE_READY) {
+                       if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) {
+                               DEBUG16(printk("scsi(%ld): fw_state=%x "
+                                   "84xx=%x.\n", ha->host_no, state[0],
+                                   state[2]));
+                               if ((state[2] & FSTATE_LOGGED_IN) &&
+                                    (state[2] & FSTATE_WAITING_FOR_VERIFY)) {
+                                       DEBUG16(printk("scsi(%ld): Sending "
+                                           "verify iocb.\n", ha->host_no));
+
+                                       cs84xx_time = jiffies;
+                                       rval = qla84xx_init_chip(ha);
+                                       if (rval != QLA_SUCCESS)
+                                               break;
+
+                                       /* Add time taken to initialize. */
+                                       cs84xx_time = jiffies - cs84xx_time;
+                                       wtime += cs84xx_time;
+                                       mtime += cs84xx_time;
+                                       DEBUG16(printk("scsi(%ld): Increasing "
+                                           "wait time by %ld. New time %ld\n",
+                                           ha->host_no, cs84xx_time, wtime));
+                               }
+                       } else if (state[0] == FSTATE_READY) {
                                DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
                                    ha->host_no));
 
@@ -1293,7 +1334,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha)
                        rval = QLA_FUNCTION_FAILED;
 
                        if (atomic_read(&ha->loop_down_timer) &&
-                           fw_state != FSTATE_READY) {
+                           state[0] != FSTATE_READY) {
                                /* Loop down. Timeout on min_wait for states
                                 * other than Wait for Login.
                                 */
@@ -1318,11 +1359,11 @@ qla2x00_fw_ready(scsi_qla_host_t *ha)
                msleep(500);
 
                DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
-                   ha->host_no, fw_state, jiffies));
+                   ha->host_no, state[0], jiffies));
        } while (1);
 
        DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
-           ha->host_no, fw_state, jiffies));
+           ha->host_no, state[0], jiffies));
 
        if (rval) {
                DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
@@ -1467,18 +1508,25 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
                index = (ha->pdev->subsystem_device & 0xff);
                if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
                    index < QLA_MODEL_NAMES)
-                       ha->model_desc = qla2x00_model_name[index * 2 + 1];
+                       strncpy(ha->model_desc,
+                           qla2x00_model_name[index * 2 + 1],
+                           sizeof(ha->model_desc) - 1);
        } else {
                index = (ha->pdev->subsystem_device & 0xff);
                if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
                    index < QLA_MODEL_NAMES) {
                        strcpy(ha->model_number,
                            qla2x00_model_name[index * 2]);
-                       ha->model_desc = qla2x00_model_name[index * 2 + 1];
+                       strncpy(ha->model_desc,
+                           qla2x00_model_name[index * 2 + 1],
+                           sizeof(ha->model_desc) - 1);
                } else {
                        strcpy(ha->model_number, def);
                }
        }
+       if (IS_FWI2_CAPABLE(ha))
+               qla2xxx_get_vpd_field(ha, "\x82", ha->model_desc,
+                   sizeof(ha->model_desc));
 }
 
 /* On sparc systems, obtain port and node WWN from firmware
@@ -1830,12 +1878,11 @@ qla2x00_rport_del(void *data)
 {
        fc_port_t *fcport = data;
        struct fc_rport *rport;
-       unsigned long flags;
 
-       spin_lock_irqsave(&fcport->rport_lock, flags);
+       spin_lock_irq(fcport->ha->host->host_lock);
        rport = fcport->drport;
        fcport->drport = NULL;
-       spin_unlock_irqrestore(&fcport->rport_lock, flags);
+       spin_unlock_irq(fcport->ha->host->host_lock);
        if (rport)
                fc_remote_port_delete(rport);
 }
@@ -1864,7 +1911,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
        atomic_set(&fcport->state, FCS_UNCONFIGURED);
        fcport->flags = FCF_RLC_SUPPORT;
        fcport->supported_classes = FC_COS_UNSPECIFIED;
-       spin_lock_init(&fcport->rport_lock);
 
        return fcport;
 }
@@ -1973,8 +2019,10 @@ qla2x00_configure_loop(scsi_qla_host_t *ha)
        if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
                if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
                        set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
-               if (test_bit(RSCN_UPDATE, &save_flags))
+               if (test_bit(RSCN_UPDATE, &save_flags)) {
+                       ha->flags.rscn_queue_overflow = 1;
                        set_bit(RSCN_UPDATE, &ha->dpc_flags);
+               }
        }
 
        return (rval);
@@ -2209,28 +2257,24 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
        struct fc_rport_identifiers rport_ids;
        struct fc_rport *rport;
-       unsigned long flags;
 
        if (fcport->drport)
                qla2x00_rport_del(fcport);
-       if (fcport->rport)
-               return;
 
        rport_ids.node_name = wwn_to_u64(fcport->node_name);
        rport_ids.port_name = wwn_to_u64(fcport->port_name);
        rport_ids.port_id = fcport->d_id.b.domain << 16 |
            fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
-       rport = fc_remote_port_add(ha->host, 0, &rport_ids);
+       fcport->rport = rport = fc_remote_port_add(ha->host, 0, &rport_ids);
        if (!rport) {
                qla_printk(KERN_WARNING, ha,
                    "Unable to allocate fc remote port!\n");
                return;
        }
-       spin_lock_irqsave(&fcport->rport_lock, flags);
-       fcport->rport = rport;
+       spin_lock_irq(fcport->ha->host->host_lock);
        *((fc_port_t **)rport->dd_data) = fcport;
-       spin_unlock_irqrestore(&fcport->rport_lock, flags);
+       spin_unlock_irq(fcport->ha->host->host_lock);
 
        rport->supported_classes = fcport->supported_classes;
 
@@ -2419,7 +2463,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
 
                        if (fcport->loop_id == FC_NO_LOOP_ID) {
                                fcport->loop_id = next_loopid;
-                               rval = qla2x00_find_new_loop_id(ha, fcport);
+                               rval = qla2x00_find_new_loop_id(
+                                   to_qla_parent(ha), fcport);
                                if (rval != QLA_SUCCESS) {
                                        /* Ran out of IDs to use */
                                        break;
@@ -2444,7 +2489,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
 
                        /* Find a new loop ID to use. */
                        fcport->loop_id = next_loopid;
-                       rval = qla2x00_find_new_loop_id(ha, fcport);
+                       rval = qla2x00_find_new_loop_id(to_qla_parent(ha),
+                           fcport);
                        if (rval != QLA_SUCCESS) {
                                /* Ran out of IDs to use */
                                break;
@@ -2529,7 +2575,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
                } else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
                        kfree(swl);
                        swl = NULL;
-               } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
+               } else if (ql2xiidmaenable &&
+                   qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
                        qla2x00_gpsc(ha, swl);
                }
        }
@@ -3207,6 +3254,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
        if (ha->flags.online) {
                ha->flags.online = 0;
                clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+               ha->qla_stats.total_isp_aborts++;
 
                qla_printk(KERN_INFO, ha,
                    "Performing ISP error recovery - ha= %p.\n", ha);
@@ -3247,17 +3295,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
                        ha->isp_abort_cnt = 0;
                        clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
 
-                       if (ha->eft) {
-                               memset(ha->eft, 0, EFT_SIZE);
-                               rval = qla2x00_enable_eft_trace(ha,
-                                   ha->eft_dma, EFT_NUM_BUFFERS);
-                               if (rval) {
-                                       qla_printk(KERN_WARNING, ha,
-                                           "Unable to reinitialize EFT "
-                                           "(%d).\n", rval);
-                               }
-                       }
-
                        if (ha->fce) {
                                ha->flags.fce_enabled = 1;
                                memset(ha->fce, 0,
@@ -3272,6 +3309,17 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
                                        ha->flags.fce_enabled = 0;
                                }
                        }
+
+                       if (ha->eft) {
+                               memset(ha->eft, 0, EFT_SIZE);
+                               rval = qla2x00_enable_eft_trace(ha,
+                                   ha->eft_dma, EFT_NUM_BUFFERS);
+                               if (rval) {
+                                       qla_printk(KERN_WARNING, ha,
+                                           "Unable to reinitialize EFT "
+                                           "(%d).\n", rval);
+                               }
+                       }
                } else {        /* failed the ISP abort */
                        ha->flags.online = 1;
                        if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
@@ -3609,7 +3657,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
        if (le16_to_cpu(nv->login_timeout) < 4)
                nv->login_timeout = __constant_cpu_to_le16(4);
        ha->login_timeout = le16_to_cpu(nv->login_timeout);
-       icb->login_timeout = cpu_to_le16(nv->login_timeout);
+       icb->login_timeout = nv->login_timeout;
 
        /* Set minimum RATOV to 100 tenths of a second. */
        ha->r_a_tov = 100;
@@ -3990,8 +4038,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
        ret = qla2x00_stop_firmware(ha);
        for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
            retries ; retries--) {
-               qla2x00_reset_chip(ha);
-               if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
+               ha->isp_ops->reset_chip(ha);
+               if (ha->isp_ops->chip_diag(ha) != QLA_SUCCESS)
                        continue;
                if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
                        continue;
@@ -4010,7 +4058,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha)
        if (!ha->parent)
                return -EINVAL;
 
-       rval = qla2x00_fw_ready(ha);
+       rval = qla2x00_fw_ready(ha->parent);
        if (rval == QLA_SUCCESS) {
                clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
                qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
@@ -4019,7 +4067,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha)
        ha->flags.management_server_logged_in = 0;
 
        /* Login to SNS first */
-       qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc,
+       qla24xx_login_fabric(ha->parent, NPH_SNS, 0xff, 0xff, 0xfc,
            mb, BIT_1);
        if (mb[0] != MBS_COMMAND_COMPLETE) {
                DEBUG15(qla_printk(KERN_INFO, ha,
@@ -4033,7 +4081,77 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha)
        atomic_set(&ha->loop_state, LOOP_UP);
        set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
        set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
-       rval = qla2x00_loop_resync(ha);
+       rval = qla2x00_loop_resync(ha->parent);
 
        return rval;
 }
+
+/* 84XX Support **************************************************************/
+
+static LIST_HEAD(qla_cs84xx_list);
+static DEFINE_MUTEX(qla_cs84xx_mutex);
+
+static struct qla_chip_state_84xx *
+qla84xx_get_chip(struct scsi_qla_host *ha)
+{
+       struct qla_chip_state_84xx *cs84xx;
+
+       mutex_lock(&qla_cs84xx_mutex);
+
+       /* Find any shared 84xx chip. */
+       list_for_each_entry(cs84xx, &qla_cs84xx_list, list) {
+               if (cs84xx->bus == ha->pdev->bus) {
+                       kref_get(&cs84xx->kref);
+                       goto done;
+               }
+       }
+
+       cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL);
+       if (!cs84xx)
+               goto done;
+
+       kref_init(&cs84xx->kref);
+       spin_lock_init(&cs84xx->access_lock);
+       mutex_init(&cs84xx->fw_update_mutex);
+       cs84xx->bus = ha->pdev->bus;
+
+       list_add_tail(&cs84xx->list, &qla_cs84xx_list);
+done:
+       mutex_unlock(&qla_cs84xx_mutex);
+       return cs84xx;
+}
+
+static void
+__qla84xx_chip_release(struct kref *kref)
+{
+       struct qla_chip_state_84xx *cs84xx =
+           container_of(kref, struct qla_chip_state_84xx, kref);
+
+       mutex_lock(&qla_cs84xx_mutex);
+       list_del(&cs84xx->list);
+       mutex_unlock(&qla_cs84xx_mutex);
+       kfree(cs84xx);
+}
+
+void
+qla84xx_put_chip(struct scsi_qla_host *ha)
+{
+       if (ha->cs84xx)
+               kref_put(&ha->cs84xx->kref, __qla84xx_chip_release);
+}
+
+static int
+qla84xx_init_chip(scsi_qla_host_t *ha)
+{
+       int rval;
+       uint16_t status[2];
+
+       mutex_lock(&ha->cs84xx->fw_update_mutex);
+
+       rval = qla84xx_verify_chip(ha, status);
+
+       mutex_unlock(&ha->cs84xx->fw_update_mutex);
+
+       return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED:
+           QLA_SUCCESS;
+}