]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/qla2xxx/qla_init.c
Merge git://git.infradead.org/mtd-2.6
[linux-2.6-omap-h63xx.git] / drivers / scsi / qla2xxx / qla_init.c
index 880de6f380e96d1d3bd2c9bba24520abf6e1c7a7..b3dac26ddba3e50767c852aecaf07921bf4f363a 100644 (file)
@@ -39,6 +39,8 @@ 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 *ha, fc_port_t *dev);
+
 /****************************************************************************/
 /*                QLogic ISP2x00 Hardware Support Functions.                */
 /****************************************************************************/
@@ -57,9 +59,6 @@ int
 qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 {
        int     rval;
-       uint8_t restart_risc = 0;
-       uint8_t retry;
-       uint32_t wait_time;
 
        /* Clear adapter flags. */
        ha->flags.online = 0;
@@ -89,89 +88,28 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 
        ha->isp_ops.nvram_config(ha);
 
-       qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
-
-       retry = 10;
-       /*
-        * Try to configure the loop.
-        */
-       do {
-               restart_risc = 0;
-
-               /* If firmware needs to be loaded */
-               if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
-                       if ((rval = ha->isp_ops.chip_diag(ha)) == QLA_SUCCESS) {
-                               rval = qla2x00_setup_chip(ha);
-                       }
-               }
-
-               if (rval == QLA_SUCCESS &&
-                   (rval = qla2x00_init_rings(ha)) == QLA_SUCCESS) {
-check_fw_ready_again:
-                       /*
-                        * Wait for a successful LIP up to a maximum
-                        * of (in seconds): RISC login timeout value,
-                        * RISC retry count value, and port down retry
-                        * value OR a minimum of 4 seconds OR If no
-                        * cable, only 5 seconds.
-                        */
-                       rval = qla2x00_fw_ready(ha);
-                       if (rval == QLA_SUCCESS) {
-                               clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-
-                               /* Issue a marker after FW becomes ready. */
-                               qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
-
-                               /*
-                                * Wait at most MAX_TARGET RSCNs for a stable
-                                * link.
-                                */
-                               wait_time = 256;
-                               do {
-                                       clear_bit(LOOP_RESYNC_NEEDED,
-                                           &ha->dpc_flags);
-                                       rval = qla2x00_configure_loop(ha);
-
-                                       if (test_and_clear_bit(ISP_ABORT_NEEDED,
-                                           &ha->dpc_flags)) {
-                                               restart_risc = 1;
-                                               break;
-                                       }
-
-                                       /*
-                                        * If loop state change while we were
-                                        * discoverying devices then wait for
-                                        * LIP to complete
-                                        */
-
-                                       if (atomic_read(&ha->loop_state) !=
-                                           LOOP_READY && retry--) {
-                                               goto check_fw_ready_again;
-                                       }
-                                       wait_time--;
-                               } while (!atomic_read(&ha->loop_down_timer) &&
-                                   retry &&
-                                   wait_time &&
-                                   (test_bit(LOOP_RESYNC_NEEDED,
-                                       &ha->dpc_flags)));
-
-                               if (wait_time == 0)
-                                       rval = QLA_FUNCTION_FAILED;
-                       } else if (ha->device_flags & DFLG_NO_CABLE)
-                               /* If no cable, then all is good. */
-                               rval = QLA_SUCCESS;
-               }
-       } while (restart_risc && retry--);
+       if (ha->flags.disable_serdes) {
+               /* Mask HBA via NVRAM settings? */
+               qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
+                   "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
+                   ha->port_name[0], ha->port_name[1],
+                   ha->port_name[2], ha->port_name[3],
+                   ha->port_name[4], ha->port_name[5],
+                   ha->port_name[6], ha->port_name[7]);
+               return QLA_FUNCTION_FAILED;
+       }
 
-       if (rval == QLA_SUCCESS) {
-               clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-               qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
-               ha->marker_needed = 0;
+       qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
 
-               ha->flags.online = 1;
-       } else {
-               DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+       if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
+               rval = ha->isp_ops.chip_diag(ha);
+               if (rval)
+                       return (rval);
+               rval = qla2x00_setup_chip(ha);
+               if (rval)
+                       return (rval);
        }
+       rval = qla2x00_init_rings(ha);
 
        return (rval);
 }
@@ -1262,8 +1200,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha)
                        rval = QLA_FUNCTION_FAILED;
 
                        if (atomic_read(&ha->loop_down_timer) &&
-                           (fw_state >= FSTATE_LOSS_OF_SYNC ||
-                               fw_state == FSTATE_WAIT_AL_PA)) {
+                           fw_state != FSTATE_READY) {
                                /* Loop down. Timeout on min_wait for states
                                 * other than Wait for Login.
                                 */
@@ -1631,6 +1568,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
        /*
         * Set host adapter parameters.
         */
+       if (nv->host_p[0] & BIT_7)
+               ql2xextended_error_logging = 1;
        ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
        /* Always load RISC code on non ISP2[12]00 chips. */
        if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
@@ -1639,6 +1578,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
        ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
        ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
        ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
+       ha->flags.disable_serdes = 0;
 
        ha->operating_mode =
            (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -1777,7 +1717,7 @@ qla2x00_rport_del(void *data)
  *
  * Returns a pointer to the allocated fcport, or NULL, if none available.
  */
-fc_port_t *
+static fc_port_t *
 qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
 {
        fc_port_t *fcport;
@@ -2059,6 +1999,19 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
                        new_fcport->flags &= ~FCF_FABRIC_DEVICE;
                }
 
+               /* Base iIDMA settings on HBA port speed. */
+               switch (ha->link_data_rate) {
+               case PORT_SPEED_1GB:
+                       fcport->fp_speed = cpu_to_be16(BIT_15);
+                       break;
+               case PORT_SPEED_2GB:
+                       fcport->fp_speed = cpu_to_be16(BIT_14);
+                       break;
+               case PORT_SPEED_4GB:
+                       fcport->fp_speed = cpu_to_be16(BIT_13);
+                       break;
+               }
+
                qla2x00_update_fcport(ha, fcport);
 
                found_devs++;
@@ -2094,39 +2047,63 @@ qla2x00_probe_for_all_luns(scsi_qla_host_t *ha)
        }
 }
 
-/*
- * qla2x00_update_fcport
- *     Updates device on list.
- *
- * Input:
- *     ha = adapter block pointer.
- *     fcport = port structure pointer.
- *
- * Return:
- *     0  - Success
- *  BIT_0 - error
- *
- * Context:
- *     Kernel context.
- */
-void
-qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
+static void
+qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
-       fcport->ha = ha;
-       fcport->login_retry = 0;
-       fcport->port_login_retry_count = ha->port_down_retry_count *
-           PORT_RETRY_TIME;
-       atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
-           PORT_RETRY_TIME);
-       fcport->flags &= ~FCF_LOGIN_NEEDED;
+#define LS_UNKNOWN      2
+       static char *link_speeds[5] = { "1", "2", "?", "4" };
+       int rval;
+       uint16_t port_speed, mb[6];
 
-       atomic_set(&fcport->state, FCS_ONLINE);
+       if (!IS_QLA24XX(ha))
+               return;
 
-       if (ha->flags.init_done)
-               qla2x00_reg_remote_port(ha, fcport);
+       switch (be16_to_cpu(fcport->fp_speed)) {
+       case BIT_15:
+               port_speed = PORT_SPEED_1GB;
+               break;
+       case BIT_14:
+               port_speed = PORT_SPEED_2GB;
+               break;
+       case BIT_13:
+               port_speed = PORT_SPEED_4GB;
+               break;
+       default:
+               DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
+                   "unsupported FM port operating speed (%04x).\n",
+                   ha->host_no, fcport->port_name[0], fcport->port_name[1],
+                   fcport->port_name[2], fcport->port_name[3],
+                   fcport->port_name[4], fcport->port_name[5],
+                   fcport->port_name[6], fcport->port_name[7],
+                   be16_to_cpu(fcport->fp_speed)));
+               port_speed = PORT_SPEED_UNKNOWN;
+               break;
+       }
+       if (port_speed == PORT_SPEED_UNKNOWN)
+               return;
+
+       rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
+                   "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
+                   ha->host_no, fcport->port_name[0], fcport->port_name[1],
+                   fcport->port_name[2], fcport->port_name[3],
+                   fcport->port_name[4], fcport->port_name[5],
+                   fcport->port_name[6], fcport->port_name[7], rval,
+                   port_speed, mb[0], mb[1]));
+       } else {
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "iIDMA adjusted to %s GB/s on "
+                   "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
+                   link_speeds[port_speed], fcport->port_name[0],
+                   fcport->port_name[1], fcport->port_name[2],
+                   fcport->port_name[3], fcport->port_name[4],
+                   fcport->port_name[5], fcport->port_name[6],
+                   fcport->port_name[7]));
+       }
 }
 
-void
+static void
 qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
        struct fc_rport_identifiers rport_ids;
@@ -2168,6 +2145,39 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
                fcport->os_target_id = rport->scsi_target_id;
 }
 
+/*
+ * qla2x00_update_fcport
+ *     Updates device on list.
+ *
+ * Input:
+ *     ha = adapter block pointer.
+ *     fcport = port structure pointer.
+ *
+ * Return:
+ *     0  - Success
+ *  BIT_0 - error
+ *
+ * Context:
+ *     Kernel context.
+ */
+void
+qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+       fcport->ha = ha;
+       fcport->login_retry = 0;
+       fcport->port_login_retry_count = ha->port_down_retry_count *
+           PORT_RETRY_TIME;
+       atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
+           PORT_RETRY_TIME);
+       fcport->flags &= ~FCF_LOGIN_NEEDED;
+
+       qla2x00_iidma_fcport(ha, fcport);
+
+       atomic_set(&fcport->state, FCS_ONLINE);
+
+       qla2x00_reg_remote_port(ha, fcport);
+}
+
 /*
  * qla2x00_configure_fabric
  *      Setup SNS devices with loop ID's.
@@ -2194,7 +2204,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
                loop_id = NPH_F_PORT;
        else
                loop_id = SNS_FL_PORT;
-       rval = qla2x00_get_port_name(ha, loop_id, NULL, 0);
+       rval = qla2x00_get_port_name(ha, loop_id, ha->fabric_node_name, 1);
        if (rval != QLA_SUCCESS) {
                DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
                    "Port\n", ha->host_no));
@@ -2202,6 +2212,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
                ha->device_flags &= ~SWITCH_FOUND;
                return (QLA_SUCCESS);
        }
+       ha->device_flags |= SWITCH_FOUND;
 
        /* Mark devices that need re-synchronization. */
        rval2 = qla2x00_device_resync(ha);
@@ -2334,8 +2345,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
                        }
 
                        /* Remove device from the new list and add it to DB */
-                       list_del(&fcport->list);
-                       list_add_tail(&fcport->list, &ha->fcports);
+                       list_move_tail(&fcport->list, &ha->fcports);
 
                        /* Login and update database */
                        qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
@@ -2402,6 +2412,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) {
+                       qla2x00_gpsc(ha, swl);
                }
        }
        swl_idx = 0;
@@ -2436,6 +2448,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
                                    swl[swl_idx].node_name, WWN_SIZE);
                                memcpy(new_fcport->port_name,
                                    swl[swl_idx].port_name, WWN_SIZE);
+                               memcpy(new_fcport->fabric_port_name,
+                                   swl[swl_idx].fabric_port_name, WWN_SIZE);
+                               new_fcport->fp_speed = swl[swl_idx].fp_speed;
 
                                if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
                                        last_dev = 1;
@@ -2493,6 +2508,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
 
                        found++;
 
+                       /* Update port state. */
+                       memcpy(fcport->fabric_port_name,
+                           new_fcport->fabric_port_name, WWN_SIZE);
+                       fcport->fp_speed = new_fcport->fp_speed;
+
                        /*
                         * If address the same and state FCS_ONLINE, nothing
                         * changed.
@@ -2574,7 +2594,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
  * Context:
  *     Kernel context.
  */
-int
+static int
 qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
 {
        int     rval;
@@ -3049,6 +3069,7 @@ qla2x00_update_fcports(scsi_qla_host_t *ha)
 int
 qla2x00_abort_isp(scsi_qla_host_t *ha)
 {
+       int rval;
        unsigned long flags = 0;
        uint16_t       cnt;
        srb_t          *sp;
@@ -3105,6 +3126,16 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 
                        ha->isp_abort_cnt = 0;
                        clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
+
+                       if (ha->eft) {
+                               rval = qla2x00_trace_control(ha, TC_ENABLE,
+                                   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)) {
@@ -3125,14 +3156,14 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
                                        ha->isp_abort_cnt--;
                                        DEBUG(printk("qla%ld: ISP abort - "
                                            "retry remaining %d\n",
-                                           ha->host_no, ha->isp_abort_cnt);)
+                                           ha->host_no, ha->isp_abort_cnt));
                                        status = 1;
                                }
                        } else {
                                ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
                                DEBUG(printk("qla2x00(%ld): ISP error recovery "
                                    "- retrying (%d) more times\n",
-                                   ha->host_no, ha->isp_abort_cnt);)
+                                   ha->host_no, ha->isp_abort_cnt));
                                set_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
                                status = 1;
                        }
@@ -3146,7 +3177,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
        } else {
                DEBUG(printk(KERN_INFO
                                "qla2x00_abort_isp(%ld): exiting.\n",
-                               ha->host_no);)
+                               ha->host_no));
        }
 
        return(status);
@@ -3222,7 +3253,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
                clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
                if (!(status = qla2x00_fw_ready(ha))) {
                        DEBUG(printk("%s(): Start configure loop, "
-                           "status = %d\n", __func__, status);)
+                           "status = %d\n", __func__, status));
 
                        /* Issue a marker after FW becomes ready. */
                        qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
@@ -3246,7 +3277,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
 
                DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
                                __func__,
-                               status);)
+                               status));
        }
        return (status);
 }
@@ -3366,7 +3397,6 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
                nv->node_name[6] = 0x55;
                nv->node_name[7] = 0x86;
                nv->login_retry_count = __constant_cpu_to_le16(8);
-               nv->link_down_timeout = __constant_cpu_to_le16(200);
                nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
                nv->login_timeout = __constant_cpu_to_le16(0);
                nv->firmware_options_1 =
@@ -3395,7 +3425,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
                *dptr1++ = *dptr2++;
 
        icb->login_retry_count = nv->login_retry_count;
-       icb->link_down_timeout = nv->link_down_timeout;
+       icb->link_down_on_nos = nv->link_down_on_nos;
 
        /* Copy 2nd segment. */
        dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
@@ -3446,10 +3476,13 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
 
        /* Set host adapter parameters. */
        ha->flags.disable_risc_code_load = 0;
-       ha->flags.enable_lip_reset = 1;
-       ha->flags.enable_lip_full_login = 1;
-       ha->flags.enable_target_reset = 1;
+       ha->flags.enable_lip_reset = 0;
+       ha->flags.enable_lip_full_login =
+           le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
+       ha->flags.enable_target_reset =
+           le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
        ha->flags.enable_led_scheme = 0;
+       ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
 
        ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
            (BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -3549,7 +3582,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
        return (rval);
 }
 
-int
+static int
 qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
 {
        int     rval;
@@ -3841,3 +3874,24 @@ qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
 fail_fw_integrity:
        return QLA_FUNCTION_FAILED;
 }
+
+void
+qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
+{
+       int ret, retries;
+
+       if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+               return;
+
+       ret = qla2x00_stop_firmware(ha);
+       for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
+               qla2x00_reset_chip(ha);
+               if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
+                       continue;
+               if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
+                       continue;
+               qla_printk(KERN_INFO, ha,
+                   "Attempting retry of stop-firmware command...\n");
+               ret = qla2x00_stop_firmware(ha);
+       }
+}