[SCSI] qla2xxx: Add ISP84XX support.
Harihara Kadayam [Thu, 3 Apr 2008 20:13:26 +0000 (13:13 -0700)]
Signed-off-by: Ravi Anand <ravi.anand@qlogic.com>
Additional cleanups and
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_dbg.h
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c

index 798cc61..413d8cd 100644 (file)
@@ -1291,7 +1291,7 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha)
        if (IS_QLA25XX(ha))
                speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
                    FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
-       else if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+       else if (IS_QLA24XX_TYPE(ha))
                speed = FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT |
                    FC_PORTSPEED_1GBIT;
        else if (IS_QLA23XX(ha))
index 2a4043b..2e9c0c0 100644 (file)
@@ -22,6 +22,7 @@
 /* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */
 /* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
 /* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */
+/* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */
 
 /*
 * Macros use for debugging the driver.
@@ -41,6 +42,7 @@
 #define DEBUG2_9_10(x) do { if (ql2xextended_error_logging) { x; } } while (0)
 #define DEBUG2_11(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
 #define DEBUG2_13(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
+#define DEBUG2_16(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
 
 #if defined(QL_DEBUG_LEVEL_3)
 #define DEBUG3(x)      do {x;} while (0)
 #define DEBUG15(x)     do {} while (0)
 #endif
 
+#if defined(QL_DEBUG_LEVEL_16)
+#define DEBUG16(x)     do {x;} while (0)
+#else
+#define DEBUG16(x)     do {} while (0)
+#endif
+
 /*
  * Firmware Dump structure definition
  */
index f7919d3..b2f0764 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/workqueue.h>
 #include <linux/firmware.h>
 #include <linux/aer.h>
+#include <linux/mutex.h>
 #include <asm/semaphore.h>
 
 #include <scsi/scsi.h>
@@ -2142,6 +2143,21 @@ struct qla_work_evt {
        } u;
 };
 
+struct qla_chip_state_84xx {
+       struct list_head list;
+       struct kref kref;
+
+       void *bus;
+       spinlock_t access_lock;
+       struct mutex fw_update_mutex;
+       uint32_t fw_update;
+       uint32_t op_fw_version;
+       uint32_t op_fw_size;
+       uint32_t op_fw_seq_size;
+       uint32_t diag_fw_version;
+       uint32_t gold_fw_version;
+};
+
 /*
  * Linux Host Adapter structure
  */
@@ -2230,6 +2246,7 @@ typedef struct scsi_qla_host {
 #define        DFLG_NO_CABLE                   BIT_4
 
 #define PCI_DEVICE_ID_QLOGIC_ISP2532   0x2532
+#define PCI_DEVICE_ID_QLOGIC_ISP8432   0x8432
        uint32_t        device_type;
 #define DT_ISP2100                     BIT_0
 #define DT_ISP2200                     BIT_1
@@ -2243,7 +2260,8 @@ typedef struct scsi_qla_host {
 #define DT_ISP5422                     BIT_9
 #define DT_ISP5432                     BIT_10
 #define DT_ISP2532                     BIT_11
-#define DT_ISP_LAST                    (DT_ISP2532 << 1)
+#define DT_ISP8432                     BIT_12
+#define DT_ISP_LAST                    (DT_ISP8432 << 1)
 
 #define DT_IIDMA                       BIT_26
 #define DT_FWI2                                BIT_27
@@ -2265,12 +2283,16 @@ typedef struct scsi_qla_host {
 #define IS_QLA5422(ha) (DT_MASK(ha) & DT_ISP5422)
 #define IS_QLA5432(ha) (DT_MASK(ha) & DT_ISP5432)
 #define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532)
+#define IS_QLA8432(ha) (DT_MASK(ha) & DT_ISP8432)
 
 #define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
                         IS_QLA6312(ha) || IS_QLA6322(ha))
 #define IS_QLA24XX(ha) (IS_QLA2422(ha) || IS_QLA2432(ha))
 #define IS_QLA54XX(ha) (IS_QLA5422(ha) || IS_QLA5432(ha))
 #define IS_QLA25XX(ha) (IS_QLA2532(ha))
+#define IS_QLA84XX(ha) (IS_QLA8432(ha))
+#define IS_QLA24XX_TYPE(ha)    (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
+                       IS_QLA84XX(ha))
 
 #define IS_IIDMA_CAPABLE(ha)   ((ha)->device_type & DT_IIDMA)
 #define IS_FWI2_CAPABLE(ha)    ((ha)->device_type & DT_FWI2)
@@ -2575,6 +2597,8 @@ typedef struct scsi_qla_host {
 #define VP_ERR_ADAP_NORESOURCES        5
        uint16_t        max_npiv_vports;        /* 63 or 125 per topoloty */
        int             cur_vport_count;
+
+       struct qla_chip_state_84xx *cs84xx;
 } scsi_qla_host_t;
 
 
index c6a5e49..078f2a1 100644 (file)
@@ -1218,4 +1218,127 @@ struct qla_fdt_layout {
        uint8_t protect_sec_cmd;
        uint8_t unused2[65];
 };
+
+/* 84XX Support **************************************************************/
+
+#define MBA_ISP84XX_ALERT      0x800f  /* Alert Notification. */
+#define A84_PANIC_RECOVERY     0x1
+#define A84_OP_LOGIN_COMPLETE  0x2
+#define A84_DIAG_LOGIN_COMPLETE        0x3
+#define A84_GOLD_LOGIN_COMPLETE        0x4
+
+#define MBC_ISP84XX_RESET      0x3a    /* Reset. */
+
+#define FSTATE_REMOTE_FC_DOWN  BIT_0
+#define FSTATE_NSL_LINK_DOWN   BIT_1
+#define FSTATE_IS_DIAG_FW      BIT_2
+#define FSTATE_LOGGED_IN       BIT_3
+#define FSTATE_WAITING_FOR_VERIFY      BIT_4
+
+#define VERIFY_CHIP_IOCB_TYPE  0x1B
+struct verify_chip_entry_84xx {
+       uint8_t entry_type;
+       uint8_t entry_count;
+       uint8_t sys_defined;
+       uint8_t entry_status;
+
+       uint32_t handle;
+
+       uint16_t options;
+#define VCO_DONT_UPDATE_FW     BIT_0
+#define VCO_FORCE_UPDATE       BIT_1
+#define VCO_DONT_RESET_UPDATE  BIT_2
+#define VCO_DIAG_FW            BIT_3
+#define VCO_END_OF_DATA                BIT_14
+#define VCO_ENABLE_DSD         BIT_15
+
+       uint16_t reserved_1;
+
+       uint16_t data_seg_cnt;
+       uint16_t reserved_2[3];
+
+       uint32_t fw_ver;
+       uint32_t exchange_address;
+
+       uint32_t reserved_3[3];
+       uint32_t fw_size;
+       uint32_t fw_seq_size;
+       uint32_t relative_offset;
+
+       uint32_t dseg_address[2];
+       uint32_t dseg_length;
+};
+
+struct verify_chip_rsp_84xx {
+       uint8_t entry_type;
+       uint8_t entry_count;
+       uint8_t sys_defined;
+       uint8_t entry_status;
+
+       uint32_t handle;
+
+       uint16_t comp_status;
+#define CS_VCS_CHIP_FAILURE    0x3
+#define CS_VCS_BAD_EXCHANGE    0x8
+#define CS_VCS_SEQ_COMPLETEi   0x40
+
+       uint16_t failure_code;
+#define VFC_CHECKSUM_ERROR     0x1
+#define VFC_INVALID_LEN                0x2
+#define VFC_ALREADY_IN_PROGRESS        0x8
+
+       uint16_t reserved_1[4];
+
+       uint32_t fw_ver;
+       uint32_t exchange_address;
+
+       uint32_t reserved_2[6];
+};
+
+#define ACCESS_CHIP_IOCB_TYPE  0x2B
+struct access_chip_84xx {
+       uint8_t entry_type;
+       uint8_t entry_count;
+       uint8_t sys_defined;
+       uint8_t entry_status;
+
+       uint32_t handle;
+
+       uint16_t options;
+#define ACO_DUMP_MEMORY                0x0
+#define ACO_LOAD_MEMORY                0x1
+#define ACO_CHANGE_CONFIG_PARAM        0x2
+#define ACO_REQUEST_INFO       0x3
+
+       uint16_t reserved1;
+
+       uint16_t dseg_count;
+       uint16_t reserved2[3];
+
+       uint32_t parameter1;
+       uint32_t parameter2;
+       uint32_t parameter3;
+
+       uint32_t reserved3[3];
+       uint32_t total_byte_cnt;
+       uint32_t reserved4;
+
+       uint32_t dseg_address[2];
+       uint32_t dseg_length;
+};
+
+struct access_chip_rsp_84xx {
+       uint8_t entry_type;
+       uint8_t entry_count;
+       uint8_t sys_defined;
+       uint8_t entry_status;
+
+       uint32_t handle;
+
+       uint16_t comp_status;
+       uint16_t failure_code;
+       uint32_t residual_count;
+
+       uint32_t reserved[12];
+};
 #endif
index f213364..a9571c2 100644 (file)
@@ -47,6 +47,8 @@ extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
 extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *);
 extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
 
+extern void qla84xx_put_chip(struct scsi_qla_host *);
+
 /*
  * Global Data in qla_os.c source file.
  */
@@ -150,6 +152,10 @@ extern int
 qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t);
 
 extern int
+qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, dma_addr_t, size_t,
+    uint32_t);
+
+extern int
 qla2x00_abort_command(scsi_qla_host_t *, srb_t *);
 
 extern int
@@ -249,6 +255,8 @@ qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
 extern int
 qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
 
+extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *);
+
 /*
  * Global Function Prototypes in qla_isr.c source file.
  */
index 980ccb3..750d7ef 100644 (file)
@@ -1532,7 +1532,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
                eiter->a.sup_speed = __constant_cpu_to_be32(
                    FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
                    FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB);
-       else if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+       else if (IS_QLA24XX_TYPE(ha))
                eiter->a.sup_speed = __constant_cpu_to_be32(
                    FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
                    FDMI_PORT_SPEED_4GB);
index 10e6995..916462e 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.                */
 /****************************************************************************/
@@ -108,6 +111,14 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
                        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);
 
        return (rval);
@@ -1243,10 +1254,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;
 
@@ -1275,12 +1286,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));
 
@@ -1294,7 +1327,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.
                                 */
@@ -1319,11 +1352,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",
@@ -4038,3 +4071,73 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha)
 
        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;
+}
index e886000..360af4e 100644 (file)
@@ -271,6 +271,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
        uint32_t        rscn_entry, host_pid;
        uint8_t         rscn_queue_index;
+       unsigned long   flags;
 
        /* Setup to process RIO completion. */
        handle_cnt = 0;
@@ -432,9 +433,10 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                break;
 
        case MBA_LOOP_DOWN:             /* Loop Down Event */
-               DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN (%x).\n",
-                   ha->host_no, mb[1]));
-               qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x).\n", mb[1]);
+               DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
+                   "(%x %x %x).\n", ha->host_no, mb[1], mb[2], mb[3]));
+               qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x %x %x).\n",
+                   mb[1], mb[2], mb[3]);
 
                if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
                        atomic_set(&ha->loop_state, LOOP_DOWN);
@@ -640,6 +642,42 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
                ha->host_no, mb[1], mb[2]));
                break;
+
+       case MBA_ISP84XX_ALERT:
+               DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
+                   "%04x %04x %04x\n", ha->host_no, mb[1], mb[2], mb[3]));
+
+               spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
+               switch (mb[1]) {
+               case A84_PANIC_RECOVERY:
+                       qla_printk(KERN_INFO, ha, "Alert 84XX: panic recovery "
+                           "%04x %04x\n", mb[2], mb[3]);
+                       break;
+               case A84_OP_LOGIN_COMPLETE:
+                       ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
+                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
+                           "firmware version %x\n", ha->cs84xx->op_fw_version));
+                       break;
+               case A84_DIAG_LOGIN_COMPLETE:
+                       ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
+                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
+                           "diagnostic firmware version %x\n",
+                           ha->cs84xx->diag_fw_version));
+                       break;
+               case A84_GOLD_LOGIN_COMPLETE:
+                       ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
+                       ha->cs84xx->fw_update = 1;
+                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX: gold "
+                           "firmware version %x\n",
+                           ha->cs84xx->gold_fw_version));
+                       break;
+               default:
+                       qla_printk(KERN_ERR, ha,
+                           "Alert 84xx: Invalid Alert %04x %04x %04x\n",
+                           mb[1], mb[2], mb[3]);
+               }
+               spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
+               break;
        }
 
        if (!ha->parent && ha->num_vhosts)
@@ -1747,7 +1785,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
        device_reg_t __iomem *reg = ha->iobase;
 
        /* If possible, enable MSI-X. */
-       if (!IS_QLA2432(ha) && !IS_QLA2532(ha))
+       if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha))
                goto skip_msix;
 
         if (IS_QLA2432(ha) && (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
@@ -1782,7 +1820,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
            "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
 skip_msix:
 
-       if (!IS_QLA24XX(ha) && !IS_QLA2532(ha))
+       if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha))
                goto skip_msi;
 
        ret = pci_enable_msi(ha->pdev);
index beff743..7d0a8a4 100644 (file)
@@ -682,8 +682,8 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
  *     Kernel context.
  */
 int
-qla2x00_issue_iocb(scsi_qla_host_t *ha, void*  buffer, dma_addr_t phys_addr,
-    size_t size)
+qla2x00_issue_iocb_timeout(scsi_qla_host_t *ha, void *buffer,
+    dma_addr_t phys_addr, size_t size, uint32_t tov)
 {
        int             rval;
        mbx_cmd_t       mc;
@@ -697,7 +697,7 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void*  buffer, dma_addr_t phys_addr,
        mcp->mb[7] = LSW(MSD(phys_addr));
        mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->in_mb = MBX_2|MBX_0;
-       mcp->tov = MBX_TOV_SECONDS;
+       mcp->tov = tov;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(ha, mcp);
 
@@ -718,6 +718,14 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void*  buffer, dma_addr_t phys_addr,
        return rval;
 }
 
+int
+qla2x00_issue_iocb(scsi_qla_host_t *ha, void *buffer, dma_addr_t phys_addr,
+    size_t size)
+{
+       return qla2x00_issue_iocb_timeout(ha, buffer, phys_addr, size,
+           MBX_TOV_SECONDS);
+}
+
 /*
  * qla2x00_abort_command
  *     Abort command aborts a specified IOCB.
@@ -1208,7 +1216,7 @@ gpd_error_out:
  *     Kernel context.
  */
 int
-qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr)
+qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *states)
 {
        int rval;
        mbx_cmd_t mc;
@@ -1219,13 +1227,15 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr)
 
        mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
        mcp->out_mb = MBX_0;
-       mcp->in_mb = MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
        mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(ha, mcp);
 
-       /* Return firmware state. */
-       *dptr = mcp->mb[1];
+       /* Return firmware states. */
+       states[0] = mcp->mb[1];
+       states[1] = mcp->mb[2];
+       states[2] = mcp->mb[3];
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
@@ -2937,3 +2947,104 @@ qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr,
 
        return rval;
 }
+
+/* 84XX Support **************************************************************/
+
+struct cs84xx_mgmt_cmd {
+       union {
+               struct verify_chip_entry_84xx req;
+               struct verify_chip_rsp_84xx rsp;
+       } p;
+};
+
+int
+qla84xx_verify_chip(struct scsi_qla_host *ha, uint16_t *status)
+{
+       int rval, retry;
+       struct cs84xx_mgmt_cmd *mn;
+       dma_addr_t mn_dma;
+       uint16_t options;
+       unsigned long flags;
+
+       DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+       mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
+       if (mn == NULL) {
+               DEBUG2_3(printk("%s(%ld): failed to allocate Verify ISP84XX "
+                   "IOCB.\n", __func__, ha->host_no));
+               return QLA_MEMORY_ALLOC_FAILED;
+       }
+
+       /* Force Update? */
+       options = ha->cs84xx->fw_update ? VCO_FORCE_UPDATE : 0;
+       /* Diagnostic firmware? */
+       /* options |= MENLO_DIAG_FW; */
+       /* We update the firmware with only one data sequence. */
+       options |= VCO_END_OF_DATA;
+
+       retry = 0;
+       do {
+               memset(mn, 0, sizeof(*mn));
+               mn->p.req.entry_type = VERIFY_CHIP_IOCB_TYPE;
+               mn->p.req.entry_count = 1;
+               mn->p.req.options = cpu_to_le16(options);
+
+               DEBUG16(printk("%s(%ld): Dump of Verify Request.\n", __func__,
+                   ha->host_no));
+               DEBUG16(qla2x00_dump_buffer((uint8_t *)mn,
+                   sizeof(*mn)));
+
+               rval = qla2x00_issue_iocb_timeout(ha, mn, mn_dma, 0, 120);
+               if (rval != QLA_SUCCESS) {
+                       DEBUG2_16(printk("%s(%ld): failed to issue Verify "
+                           "IOCB (%x).\n", __func__, ha->host_no, rval));
+                       goto verify_done;
+               }
+
+               DEBUG16(printk("%s(%ld): Dump of Verify Response.\n", __func__,
+                   ha->host_no));
+               DEBUG16(qla2x00_dump_buffer((uint8_t *)mn,
+                   sizeof(*mn)));
+
+               status[0] = le16_to_cpu(mn->p.rsp.comp_status);
+               status[1] = status[0] == CS_VCS_CHIP_FAILURE ?
+                   le16_to_cpu(mn->p.rsp.failure_code) : 0;
+               DEBUG2_16(printk("%s(%ld): cs=%x fc=%x\n", __func__,
+                   ha->host_no, status[0], status[1]));
+
+               if (status[0] != CS_COMPLETE) {
+                       rval = QLA_FUNCTION_FAILED;
+                       if (!(options & VCO_DONT_UPDATE_FW)) {
+                               DEBUG2_16(printk("%s(%ld): Firmware update "
+                                   "failed. Retrying without update "
+                                   "firmware.\n", __func__, ha->host_no));
+                               options |= VCO_DONT_UPDATE_FW;
+                               options &= ~VCO_FORCE_UPDATE;
+                               retry = 1;
+                       }
+               } else {
+                       DEBUG2_16(printk("%s(%ld): firmware updated to %x.\n",
+                           __func__, ha->host_no,
+                           le32_to_cpu(mn->p.rsp.fw_ver)));
+
+                       /* NOTE: we only update OP firmware. */
+                       spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
+                       ha->cs84xx->op_fw_version =
+                           le32_to_cpu(mn->p.rsp.fw_ver);
+                       spin_unlock_irqrestore(&ha->cs84xx->access_lock,
+                           flags);
+               }
+       } while (retry);
+
+verify_done:
+       dma_pool_free(ha->s_dma_pool, mn, mn_dma);
+
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_16(printk("%s(%ld): failed=%x.\n", __func__,
+                   ha->host_no, rval));
+       } else {
+               DEBUG16(printk("%s(%ld): done.\n", __func__, ha->host_no));
+       }
+
+       return rval;
+}
index 5cddc50..4c50b9b 100644 (file)
@@ -339,6 +339,8 @@ qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str)
                strcat(str, "[T10 CRC] ");
        if (ha->fw_attributes & BIT_5)
                strcat(str, "[VI] ");
+       if (ha->fw_attributes & BIT_10)
+               strcat(str, "[84XX] ");
        if (ha->fw_attributes & BIT_13)
                strcat(str, "[Experimental]");
        return str;
@@ -1378,6 +1380,13 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha)
                ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
+       case PCI_DEVICE_ID_QLOGIC_ISP8432:
+               ha->device_type |= DT_ISP8432;
+               ha->device_type |= DT_ZIO_SUPPORTED;
+               ha->device_type |= DT_FWI2;
+               ha->device_type |= DT_IIDMA;
+               ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+               break;
        case PCI_DEVICE_ID_QLOGIC_ISP5422:
                ha->device_type |= DT_ISP5422;
                ha->device_type |= DT_FWI2;
@@ -1501,6 +1510,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        sht = &qla2x00_driver_template;
        if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
+           pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
@@ -1591,7 +1601,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                if (IS_QLA2322(ha) || IS_QLA6322(ha))
                        ha->optrom_size = OPTROM_SIZE_2322;
                ha->isp_ops = &qla2300_isp_ops;
-       } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+       } else if (IS_QLA24XX_TYPE(ha)) {
                host->max_id = MAX_TARGETS_2200;
                ha->mbx_count = MAILBOX_REGISTER_COUNT;
                ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
@@ -1736,6 +1746,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
 
        qla2x00_dfs_remove(ha);
 
+       qla84xx_put_chip(ha);
+
        qla2x00_free_sysfs_attr(ha);
 
        fc_remove_host(ha->host);
@@ -2642,7 +2654,7 @@ qla2x00_request_firmware(scsi_qla_host_t *ha)
                blob = &qla_fw_blobs[FW_ISP2300];
        } else if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
                blob = &qla_fw_blobs[FW_ISP2322];
-       } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+       } else if (IS_QLA24XX_TYPE(ha)) {
                blob = &qla_fw_blobs[FW_ISP24XX];
        } else if (IS_QLA25XX(ha)) {
                blob = &qla_fw_blobs[FW_ISP25XX];
@@ -2792,6 +2804,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6322) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2422) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) },
+       { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8432) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
index eda11f6..1728ab3 100644 (file)
@@ -553,7 +553,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *ha)
        struct qla_fdt_layout *fdt;
        uint8_t man_id, flash_id;
 
-       if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha))
+       if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
                return;
 
        wptr = (uint16_t *)ha->request_ring;