Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb...
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / qla4xxx / ql4_os.c
index 79243b76d17ef9c7a72ed404dabf2cbeb1f941f5..fbc546e893ac2bcad8ea7a42d430096ea2905429 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2010 QLogic Corporation
+ * Copyright (c)  2003-2012 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -18,6 +18,7 @@
 #include "ql4_glbl.h"
 #include "ql4_dbg.h"
 #include "ql4_inline.h"
+#include "ql4_83xx.h"
 
 /*
  * Driver version
@@ -160,7 +161,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
 static int qla4xxx_slave_alloc(struct scsi_device *device);
 static int qla4xxx_slave_configure(struct scsi_device *device);
 static void qla4xxx_slave_destroy(struct scsi_device *sdev);
-static umode_t ql4_attr_is_visible(int param_type, int param);
+static umode_t qla4_attr_is_visible(int param_type, int param);
 static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
 static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
                                      int reason);
@@ -203,7 +204,7 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
                                  CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST |
                                  CAP_DATADGST | CAP_LOGIN_OFFLOAD |
                                  CAP_MULTI_R2T,
-       .attr_is_visible        = ql4_attr_is_visible,
+       .attr_is_visible        = qla4_attr_is_visible,
        .create_session         = qla4xxx_session_create,
        .destroy_session        = qla4xxx_session_destroy,
        .start_conn             = qla4xxx_conn_start,
@@ -315,7 +316,7 @@ exit_send_ping:
        return rval;
 }
 
-static umode_t ql4_attr_is_visible(int param_type, int param)
+static umode_t qla4_attr_is_visible(int param_type, int param)
 {
        switch (param_type) {
        case ISCSI_HOST_PARAM:
@@ -1366,7 +1367,7 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn,
 
        conn = cls_conn->dd_data;
        qla_conn = conn->dd_data;
-       dst_addr = &qla_conn->qla_ep->dst_addr;
+       dst_addr = (struct sockaddr *)&qla_conn->qla_ep->dst_addr;
 
        switch (param) {
        case ISCSI_PARAM_CONN_PORT:
@@ -2315,8 +2316,17 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha)
                if (ha->nx_pcibase)
                        iounmap(
                            (struct device_reg_82xx __iomem *)ha->nx_pcibase);
-       } else if (ha->reg)
+       } else if (is_qla8032(ha)) {
+               if (ha->nx_pcibase)
+                       iounmap(
+                           (struct device_reg_83xx __iomem *)ha->nx_pcibase);
+       } else if (ha->reg) {
                iounmap(ha->reg);
+       }
+
+       if (ha->reset_tmplt.buff)
+               vfree(ha->reset_tmplt.buff);
+
        pci_release_regions(ha->pdev);
 }
 
@@ -2420,7 +2430,7 @@ static int qla4_8xxx_check_temp(struct scsi_qla_host *ha)
        uint32_t temp, temp_state, temp_val;
        int status = QLA_SUCCESS;
 
-       temp = qla4_8xxx_rd_32(ha, CRB_TEMP_STATE);
+       temp = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_TEMP_STATE);
 
        temp_state = qla82xx_get_temp_state(temp);
        temp_val = qla82xx_get_temp_val(temp);
@@ -2456,7 +2466,8 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
        uint32_t fw_heartbeat_counter;
        int status = QLA_SUCCESS;
 
-       fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+       fw_heartbeat_counter = qla4_8xxx_rd_direct(ha,
+                                                  QLA8XXX_PEG_ALIVE_COUNTER);
        /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */
        if (fw_heartbeat_counter == 0xffffffff) {
                DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen "
@@ -2470,28 +2481,7 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
                /* FW not alive after 2 seconds */
                if (ha->seconds_since_last_heartbeat == 2) {
                        ha->seconds_since_last_heartbeat = 0;
-
-                       ql4_printk(KERN_INFO, ha,
-                                  "scsi(%ld): %s, Dumping hw/fw registers:\n "
-                                  " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:"
-                                  " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:"
-                                  " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:"
-                                  " 0x%x,\n PEG_NET_4_PC: 0x%x\n",
-                                  ha->host_no, __func__,
-                                  qla4_8xxx_rd_32(ha,
-                                                  QLA82XX_PEG_HALT_STATUS1),
-                                  qla4_8xxx_rd_32(ha,
-                                                  QLA82XX_PEG_HALT_STATUS2),
-                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 +
-                                                  0x3c),
-                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 +
-                                                  0x3c),
-                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 +
-                                                  0x3c),
-                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 +
-                                                  0x3c),
-                                  qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 +
-                                                  0x3c));
+                       qla4_8xxx_dump_peg_reg(ha);
                        status = QLA_ERROR;
                }
        } else
@@ -2501,6 +2491,48 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
        return status;
 }
 
+static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha)
+{
+       uint32_t halt_status;
+       int halt_status_unrecoverable = 0;
+
+       halt_status = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1);
+
+       if (is_qla8022(ha)) {
+               ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
+                          __func__);
+               qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
+                               CRB_NIU_XG_PAUSE_CTL_P0 |
+                               CRB_NIU_XG_PAUSE_CTL_P1);
+
+               if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
+                       ql4_printk(KERN_ERR, ha, "%s: Firmware aborted with error code 0x00006700. Device is being reset\n",
+                                  __func__);
+               if (halt_status & HALT_STATUS_UNRECOVERABLE)
+                       halt_status_unrecoverable = 1;
+       } else if (is_qla8032(ha)) {
+               if (halt_status & QLA83XX_HALT_STATUS_FW_RESET)
+                       ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n",
+                                  __func__);
+               else if (halt_status & QLA83XX_HALT_STATUS_UNRECOVERABLE)
+                       halt_status_unrecoverable = 1;
+       }
+
+       /*
+        * Since we cannot change dev_state in interrupt context,
+        * set appropriate DPC flag then wakeup DPC
+        */
+       if (halt_status_unrecoverable) {
+               set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
+       } else {
+               ql4_printk(KERN_INFO, ha, "%s: detect abort needed!\n",
+                          __func__);
+               set_bit(DPC_RESET_HA, &ha->dpc_flags);
+       }
+       qla4xxx_mailbox_premature_completion(ha);
+       qla4xxx_wake_dpc(ha);
+}
+
 /**
  * qla4_8xxx_watchdog - Poll dev state
  * @ha: Pointer to host adapter structure.
@@ -2509,31 +2541,33 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
  **/
 void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
 {
-       uint32_t dev_state, halt_status;
+       uint32_t dev_state;
 
        /* don't poll if reset is going on */
        if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
            test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
            test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) {
-               dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+               dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
 
                if (qla4_8xxx_check_temp(ha)) {
-                       ql4_printk(KERN_INFO, ha, "disabling pause"
-                                  " transmit on port 0 & 1.\n");
-                       qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
-                                       CRB_NIU_XG_PAUSE_CTL_P0 |
-                                       CRB_NIU_XG_PAUSE_CTL_P1);
+                       if (is_qla8022(ha)) {
+                               ql4_printk(KERN_INFO, ha, "disabling pause transmit on port 0 & 1.\n");
+                               qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
+                                               CRB_NIU_XG_PAUSE_CTL_P0 |
+                                               CRB_NIU_XG_PAUSE_CTL_P1);
+                       }
                        set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
                        qla4xxx_wake_dpc(ha);
-               } else if (dev_state == QLA82XX_DEV_NEED_RESET &&
-                   !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
-                       if (!ql4xdontresethba) {
+               } else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
+                          !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+                       if (is_qla8032(ha) ||
+                           (is_qla8022(ha) && !ql4xdontresethba)) {
                                ql4_printk(KERN_INFO, ha, "%s: HW State: "
                                    "NEED RESET!\n", __func__);
                                set_bit(DPC_RESET_HA, &ha->dpc_flags);
                                qla4xxx_wake_dpc(ha);
                        }
-               } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
+               } else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
                    !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
                        ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n",
                            __func__);
@@ -2541,36 +2575,8 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
                        qla4xxx_wake_dpc(ha);
                } else  {
                        /* Check firmware health */
-                       if (qla4_8xxx_check_fw_alive(ha)) {
-                               ql4_printk(KERN_INFO, ha, "disabling pause"
-                                          " transmit on port 0 & 1.\n");
-                               qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
-                                               CRB_NIU_XG_PAUSE_CTL_P0 |
-                                               CRB_NIU_XG_PAUSE_CTL_P1);
-                               halt_status = qla4_8xxx_rd_32(ha,
-                                               QLA82XX_PEG_HALT_STATUS1);
-
-                               if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
-                                       ql4_printk(KERN_ERR, ha, "%s:"
-                                                  " Firmware aborted with"
-                                                  " error code 0x00006700."
-                                                  " Device is being reset\n",
-                                                  __func__);
-
-                               /* Since we cannot change dev_state in interrupt
-                                * context, set appropriate DPC flag then wakeup
-                                * DPC */
-                               if (halt_status & HALT_STATUS_UNRECOVERABLE)
-                                       set_bit(DPC_HA_UNRECOVERABLE,
-                                               &ha->dpc_flags);
-                               else {
-                                       ql4_printk(KERN_INFO, ha, "%s: detect "
-                                                  "abort needed!\n", __func__);
-                                       set_bit(DPC_RESET_HA, &ha->dpc_flags);
-                               }
-                               qla4xxx_mailbox_premature_completion(ha);
-                               qla4xxx_wake_dpc(ha);
-                       }
+                       if (qla4_8xxx_check_fw_alive(ha))
+                               qla4_8xxx_process_fw_error(ha);
                }
        }
 }
@@ -2652,11 +2658,10 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
        if (!pci_channel_offline(ha->pdev))
                pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
 
-       if (is_qla8022(ha)) {
+       if (is_qla80XX(ha))
                qla4_8xxx_watchdog(ha);
-       }
 
-       if (!is_qla8022(ha)) {
+       if (is_qla40XX(ha)) {
                /* Check for heartbeat interval. */
                if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
                    ha->heartbeat_interval != 0) {
@@ -2941,6 +2946,14 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
 
        set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
 
+       if (is_qla8032(ha) &&
+           !test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
+               ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
+                          __func__);
+               /* disable pause frame for ISP83xx */
+               qla4_83xx_disable_pause(ha);
+       }
+
        iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
 
        if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
@@ -2953,9 +2966,9 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
                goto recover_ha_init_adapter;
        }
 
-       /* For the ISP-82xx adapter, issue a stop_firmware if invoked
+       /* For the ISP-8xxx adapter, issue a stop_firmware if invoked
         * from eh_host_reset or ioctl module */
-       if (is_qla8022(ha) && !reset_chip &&
+       if (is_qla80XX(ha) && !reset_chip &&
            test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
 
                DEBUG2(ql4_printk(KERN_INFO, ha,
@@ -2978,13 +2991,13 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
        }
 
        /* Issue full chip reset if recovering from a catastrophic error,
-        * or if stop_firmware fails for ISP-82xx.
+        * or if stop_firmware fails for ISP-8xxx.
         * This is the default case for ISP-4xxx */
-       if (!is_qla8022(ha) || reset_chip) {
-               if (!is_qla8022(ha))
+       if (is_qla40XX(ha) || reset_chip) {
+               if (is_qla40XX(ha))
                        goto chip_reset;
 
-               /* Check if 82XX firmware is alive or not
+               /* Check if 8XXX firmware is alive or not
                 * We may have arrived here from NEED_RESET
                 * detection only */
                if (test_bit(AF_FW_RECOVERY, &ha->flags))
@@ -3000,10 +3013,10 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        schedule_timeout(HZ);
                }
-
+chip_reset:
                if (!test_bit(AF_FW_RECOVERY, &ha->flags))
                        qla4xxx_cmd_wait(ha);
-chip_reset:
+
                qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
                qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
                DEBUG2(ql4_printk(KERN_INFO, ha,
@@ -3021,7 +3034,7 @@ recover_ha_init_adapter:
                /* For ISP-4xxx, force function 1 to always initialize
                 * before function 3 to prevent both funcions from
                 * stepping on top of the other */
-               if (!is_qla8022(ha) && (ha->mac_index == 3))
+               if (is_qla40XX(ha) && (ha->mac_index == 3))
                        ssleep(6);
 
                /* NOTE: AF_ONLINE flag set upon successful completion of
@@ -3039,11 +3052,12 @@ recover_ha_init_adapter:
                 * Since we don't want to block the DPC for too long
                 * with multiple resets in the same thread,
                 * utilize DPC to retry */
-               if (is_qla8022(ha)) {
-                       qla4_8xxx_idc_lock(ha);
-                       dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
-                       qla4_8xxx_idc_unlock(ha);
-                       if (dev_state == QLA82XX_DEV_FAILED) {
+               if (is_qla80XX(ha)) {
+                       ha->isp_ops->idc_lock(ha);
+                       dev_state = qla4_8xxx_rd_direct(ha,
+                                                       QLA8XXX_CRB_DEV_STATE);
+                       ha->isp_ops->idc_unlock(ha);
+                       if (dev_state == QLA8XXX_DEV_FAILED) {
                                ql4_printk(KERN_INFO, ha, "%s: don't retry "
                                           "recover adapter. H/W is in Failed "
                                           "state\n", __func__);
@@ -3168,6 +3182,7 @@ int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session)
        struct iscsi_session *sess;
        struct ddb_entry *ddb_entry;
        struct scsi_qla_host *ha;
+       int status = QLA_SUCCESS;
 
        sess = cls_session->dd_data;
        ddb_entry = sess->dd_data;
@@ -3175,11 +3190,20 @@ int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session)
        ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
                   " unblock user space session\n", ha->host_no, __func__,
                   ddb_entry->fw_ddb_index);
-       iscsi_conn_start(ddb_entry->conn);
-       iscsi_conn_login_event(ddb_entry->conn,
-                              ISCSI_CONN_STATE_LOGGED_IN);
 
-       return QLA_SUCCESS;
+       if (!iscsi_is_session_online(cls_session)) {
+               iscsi_conn_start(ddb_entry->conn);
+               iscsi_conn_login_event(ddb_entry->conn,
+                                      ISCSI_CONN_STATE_LOGGED_IN);
+       } else {
+               ql4_printk(KERN_INFO, ha,
+                          "scsi%ld: %s: ddb[%d] session [%d] already logged in\n",
+                          ha->host_no, __func__, ddb_entry->fw_ddb_index,
+                          cls_session->sid);
+               status = QLA_ERROR;
+       }
+
+       return status;
 }
 
 static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha)
@@ -3373,15 +3397,26 @@ static void qla4xxx_do_dpc(struct work_struct *work)
        /* post events to application */
        qla4xxx_do_work(ha);
 
-       if (is_qla8022(ha)) {
+       if (is_qla80XX(ha)) {
                if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
-                       qla4_8xxx_idc_lock(ha);
-                       qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                           QLA82XX_DEV_FAILED);
-                       qla4_8xxx_idc_unlock(ha);
+                       if (is_qla8032(ha)) {
+                               ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
+                                          __func__);
+                               /* disable pause frame for ISP83xx */
+                               qla4_83xx_disable_pause(ha);
+                       }
+
+                       ha->isp_ops->idc_lock(ha);
+                       qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
+                                           QLA8XXX_DEV_FAILED);
+                       ha->isp_ops->idc_unlock(ha);
                        ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
                        qla4_8xxx_device_state_handler(ha);
                }
+
+               if (test_and_clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags))
+                       qla4_83xx_post_idc_ack(ha);
+
                if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
                        qla4_8xxx_need_qsnt_handler(ha);
                }
@@ -3391,7 +3426,8 @@ static void qla4xxx_do_dpc(struct work_struct *work)
            (test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
            test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
            test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
-               if (ql4xdontresethba) {
+               if ((is_qla8022(ha) && ql4xdontresethba) ||
+                   (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
                        DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
                            ha->host_no, __func__));
                        clear_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -3477,6 +3513,18 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
                ha->isp_ops->disable_intrs(ha);
        }
 
+       if (is_qla40XX(ha)) {
+               writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
+                      &ha->reg->ctrl_status);
+               readl(&ha->reg->ctrl_status);
+       } else if (is_qla8022(ha)) {
+               writel(0, &ha->qla4_82xx_reg->host_int);
+               readl(&ha->qla4_82xx_reg->host_int);
+       } else if (is_qla8032(ha)) {
+               writel(0, &ha->qla4_83xx_reg->risc_intr);
+               readl(&ha->qla4_83xx_reg->risc_intr);
+       }
+
        /* Remove timer thread, if present */
        if (ha->timer_active)
                qla4xxx_stop_timer(ha);
@@ -3492,10 +3540,10 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
        /* Put firmware in known state */
        ha->isp_ops->reset_firmware(ha);
 
-       if (is_qla8022(ha)) {
-               qla4_8xxx_idc_lock(ha);
+       if (is_qla80XX(ha)) {
+               ha->isp_ops->idc_lock(ha);
                qla4_8xxx_clear_drv_active(ha);
-               qla4_8xxx_idc_unlock(ha);
+               ha->isp_ops->idc_unlock(ha);
        }
 
        /* Detach interrupts */
@@ -3542,16 +3590,20 @@ int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
        /* Mapping of IO base pointer, door bell read and write pointer */
 
        /* mapping of IO base pointer */
-       ha->qla4_8xxx_reg =
-           (struct device_reg_82xx  __iomem *)((uint8_t *)ha->nx_pcibase +
-           0xbc000 + (ha->pdev->devfn << 11));
+       if (is_qla8022(ha)) {
+               ha->qla4_82xx_reg = (struct device_reg_82xx  __iomem *)
+                                   ((uint8_t *)ha->nx_pcibase + 0xbc000 +
+                                    (ha->pdev->devfn << 11));
+               ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
+                                   QLA82XX_CAM_RAM_DB2);
+       } else if (is_qla8032(ha)) {
+               ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *)
+                                   ((uint8_t *)ha->nx_pcibase);
+       }
 
        db_base = pci_resource_start(pdev, 4);  /* doorbell is on bar 4 */
        db_len = pci_resource_len(pdev, 4);
 
-       ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
-           QLA82XX_CAM_RAM_DB2);
-
        return 0;
 iospace_error_exit:
        return -ENOMEM;
@@ -3639,23 +3691,64 @@ static struct isp_operations qla4xxx_isp_ops = {
        .rd_shdw_req_q_out      = qla4xxx_rd_shdw_req_q_out,
        .rd_shdw_rsp_q_in       = qla4xxx_rd_shdw_rsp_q_in,
        .get_sys_info           = qla4xxx_get_sys_info,
+       .queue_mailbox_command  = qla4xxx_queue_mbox_cmd,
+       .process_mailbox_interrupt = qla4xxx_process_mbox_intr,
 };
 
-static struct isp_operations qla4_8xxx_isp_ops = {
+static struct isp_operations qla4_82xx_isp_ops = {
        .iospace_config         = qla4_8xxx_iospace_config,
        .pci_config             = qla4_8xxx_pci_config,
-       .disable_intrs          = qla4_8xxx_disable_intrs,
-       .enable_intrs           = qla4_8xxx_enable_intrs,
+       .disable_intrs          = qla4_82xx_disable_intrs,
+       .enable_intrs           = qla4_82xx_enable_intrs,
        .start_firmware         = qla4_8xxx_load_risc,
-       .intr_handler           = qla4_8xxx_intr_handler,
-       .interrupt_service_routine = qla4_8xxx_interrupt_service_routine,
-       .reset_chip             = qla4_8xxx_isp_reset,
+       .restart_firmware       = qla4_82xx_try_start_fw,
+       .intr_handler           = qla4_82xx_intr_handler,
+       .interrupt_service_routine = qla4_82xx_interrupt_service_routine,
+       .need_reset             = qla4_8xxx_need_reset,
+       .reset_chip             = qla4_82xx_isp_reset,
        .reset_firmware         = qla4_8xxx_stop_firmware,
-       .queue_iocb             = qla4_8xxx_queue_iocb,
-       .complete_iocb          = qla4_8xxx_complete_iocb,
-       .rd_shdw_req_q_out      = qla4_8xxx_rd_shdw_req_q_out,
-       .rd_shdw_rsp_q_in       = qla4_8xxx_rd_shdw_rsp_q_in,
+       .queue_iocb             = qla4_82xx_queue_iocb,
+       .complete_iocb          = qla4_82xx_complete_iocb,
+       .rd_shdw_req_q_out      = qla4_82xx_rd_shdw_req_q_out,
+       .rd_shdw_rsp_q_in       = qla4_82xx_rd_shdw_rsp_q_in,
        .get_sys_info           = qla4_8xxx_get_sys_info,
+       .rd_reg_direct          = qla4_82xx_rd_32,
+       .wr_reg_direct          = qla4_82xx_wr_32,
+       .rd_reg_indirect        = qla4_82xx_md_rd_32,
+       .wr_reg_indirect        = qla4_82xx_md_wr_32,
+       .idc_lock               = qla4_82xx_idc_lock,
+       .idc_unlock             = qla4_82xx_idc_unlock,
+       .rom_lock_recovery      = qla4_82xx_rom_lock_recovery,
+       .queue_mailbox_command  = qla4_82xx_queue_mbox_cmd,
+       .process_mailbox_interrupt = qla4_82xx_process_mbox_intr,
+};
+
+static struct isp_operations qla4_83xx_isp_ops = {
+       .iospace_config         = qla4_8xxx_iospace_config,
+       .pci_config             = qla4_8xxx_pci_config,
+       .disable_intrs          = qla4_83xx_disable_intrs,
+       .enable_intrs           = qla4_83xx_enable_intrs,
+       .start_firmware         = qla4_8xxx_load_risc,
+       .restart_firmware       = qla4_83xx_start_firmware,
+       .intr_handler           = qla4_83xx_intr_handler,
+       .interrupt_service_routine = qla4_83xx_interrupt_service_routine,
+       .need_reset             = qla4_8xxx_need_reset,
+       .reset_chip             = qla4_83xx_isp_reset,
+       .reset_firmware         = qla4_8xxx_stop_firmware,
+       .queue_iocb             = qla4_83xx_queue_iocb,
+       .complete_iocb          = qla4_83xx_complete_iocb,
+       .rd_shdw_req_q_out      = qla4_83xx_rd_shdw_req_q_out,
+       .rd_shdw_rsp_q_in       = qla4_83xx_rd_shdw_rsp_q_in,
+       .get_sys_info           = qla4_8xxx_get_sys_info,
+       .rd_reg_direct          = qla4_83xx_rd_reg,
+       .wr_reg_direct          = qla4_83xx_wr_reg,
+       .rd_reg_indirect        = qla4_83xx_rd_reg_indirect,
+       .wr_reg_indirect        = qla4_83xx_wr_reg_indirect,
+       .idc_lock               = qla4_83xx_drv_lock,
+       .idc_unlock             = qla4_83xx_drv_unlock,
+       .rom_lock_recovery      = qla4_83xx_rom_lock_recovery,
+       .queue_mailbox_command  = qla4_83xx_queue_mbox_cmd,
+       .process_mailbox_interrupt = qla4_83xx_process_mbox_intr,
 };
 
 uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
@@ -3663,9 +3756,14 @@ uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
        return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out);
 }
 
-uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
+uint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
 {
-       return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out));
+       return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out));
+}
+
+uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
+{
+       return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->req_q_out));
 }
 
 uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
@@ -3673,9 +3771,14 @@ uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
        return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
 }
 
-uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
+uint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
 {
-       return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in));
+       return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in));
+}
+
+uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
+{
+       return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->rsp_q_in));
 }
 
 static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
@@ -5050,30 +5153,36 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
        ha->pdev = pdev;
        ha->host = host;
        ha->host_no = host->host_no;
+       ha->func_num = PCI_FUNC(ha->pdev->devfn);
 
        pci_enable_pcie_error_reporting(pdev);
 
        /* Setup Runtime configurable options */
        if (is_qla8022(ha)) {
-               ha->isp_ops = &qla4_8xxx_isp_ops;
-               rwlock_init(&ha->hw_lock);
+               ha->isp_ops = &qla4_82xx_isp_ops;
+               ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl;
                ha->qdr_sn_window = -1;
                ha->ddr_mn_window = -1;
                ha->curr_window = 255;
-               ha->func_num = PCI_FUNC(ha->pdev->devfn);
                nx_legacy_intr = &legacy_intr[ha->func_num];
                ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
                ha->nx_legacy_intr.tgt_status_reg =
                        nx_legacy_intr->tgt_status_reg;
                ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
                ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
+       } else if (is_qla8032(ha)) {
+               ha->isp_ops = &qla4_83xx_isp_ops;
+               ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl;
        } else {
                ha->isp_ops = &qla4xxx_isp_ops;
        }
 
-       /* Set EEH reset type to fundamental if required by hba */
-       if (is_qla8022(ha))
+       if (is_qla80XX(ha)) {
+               rwlock_init(&ha->hw_lock);
+               ha->pf_bit = ha->func_num << 16;
+               /* Set EEH reset type to fundamental if required by hba */
                pdev->needs_freset = 1;
+       }
 
        /* Configure PCI I/O space. */
        ret = ha->isp_ops->iospace_config(ha);
@@ -5094,6 +5203,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
        init_completion(&ha->disable_acb_comp);
 
        spin_lock_init(&ha->hardware_lock);
+       spin_lock_init(&ha->work_lock);
 
        /* Initialize work list */
        INIT_LIST_HEAD(&ha->work_list);
@@ -5128,8 +5238,20 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
        if (ret)
                goto probe_failed;
 
-       if (is_qla8022(ha))
-               (void) qla4_8xxx_get_flash_info(ha);
+       if (is_qla80XX(ha))
+               qla4_8xxx_get_flash_info(ha);
+
+       if (is_qla8032(ha)) {
+               qla4_83xx_read_reset_template(ha);
+               /*
+                * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0.
+                * If DONRESET_BIT0 is set, drivers should not set dev_state
+                * to NEED_RESET. But if NEED_RESET is set, drivers should
+                * should honor the reset.
+                */
+               if (ql4xdontresethba == 1)
+                       qla4_83xx_set_idc_dontreset(ha);
+       }
 
        /*
         * Initialize the Host adapter request/response queues and
@@ -5137,14 +5259,20 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
         * NOTE: interrupts enabled upon successful completion
         */
        status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
+
+       /* Dont retry adapter initialization if IRQ allocation failed */
+       if (!test_bit(AF_IRQ_ATTACHED, &ha->flags))
+               goto skip_retry_init;
+
        while ((!test_bit(AF_ONLINE, &ha->flags)) &&
            init_retry_count++ < MAX_INIT_RETRIES) {
 
-               if (is_qla8022(ha)) {
-                       qla4_8xxx_idc_lock(ha);
-                       dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
-                       qla4_8xxx_idc_unlock(ha);
-                       if (dev_state == QLA82XX_DEV_FAILED) {
+               if (is_qla80XX(ha)) {
+                       ha->isp_ops->idc_lock(ha);
+                       dev_state = qla4_8xxx_rd_direct(ha,
+                                                       QLA82XX_CRB_DEV_STATE);
+                       ha->isp_ops->idc_unlock(ha);
+                       if (dev_state == QLA8XXX_DEV_FAILED) {
                                ql4_printk(KERN_WARNING, ha, "%s: don't retry "
                                    "initialize adapter. H/W is in failed state\n",
                                    __func__);
@@ -5160,16 +5288,18 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
                status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
        }
 
+skip_retry_init:
        if (!test_bit(AF_ONLINE, &ha->flags)) {
                ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
 
-               if (is_qla8022(ha) && ql4xdontresethba) {
+               if ((is_qla8022(ha) && ql4xdontresethba) ||
+                   (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
                        /* Put the device in failed state. */
                        DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
-                       qla4_8xxx_idc_lock(ha);
-                       qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                           QLA82XX_DEV_FAILED);
-                       qla4_8xxx_idc_unlock(ha);
+                       ha->isp_ops->idc_lock(ha);
+                       qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
+                                           QLA8XXX_DEV_FAILED);
+                       ha->isp_ops->idc_unlock(ha);
                }
                ret = -ENODEV;
                goto remove_host;
@@ -5195,12 +5325,13 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
                goto remove_host;
        }
 
-       /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc
+       /*
+        * For ISP-8XXX, request_irqs is called in qla4_8xxx_load_risc
         * (which is called indirectly by qla4xxx_initialize_adapter),
         * so that irqs will be registered after crbinit but before
         * mbx_intr_enable.
         */
-       if (!is_qla8022(ha)) {
+       if (is_qla40XX(ha)) {
                ret = qla4xxx_request_irqs(ha);
                if (ret) {
                        ql4_printk(KERN_WARNING, ha, "Failed to reserve "
@@ -5226,6 +5357,10 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
               ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
               ha->patch_number, ha->build_number);
 
+       /* Set the driver version */
+       if (is_qla80XX(ha))
+               qla4_8xxx_set_param(ha, SET_DRVR_VERSION);
+
        if (qla4xxx_setup_boot_info(ha))
                ql4_printk(KERN_ERR, ha,
                           "%s: No iSCSI boot target configured\n", __func__);
@@ -5333,9 +5468,16 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
 {
        struct scsi_qla_host *ha;
 
+       /*
+        * If the PCI device is disabled then it means probe_adapter had
+        * failed and resources already cleaned up on probe_adapter exit.
+        */
+       if (!pci_is_enabled(pdev))
+               return;
+
        ha = pci_get_drvdata(pdev);
 
-       if (!is_qla8022(ha))
+       if (is_qla40XX(ha))
                qla4xxx_prevent_other_port_reinit(ha);
 
        /* destroy iface from sysfs */
@@ -5755,7 +5897,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
 
        ha = to_qla_host(cmd->device->host);
 
-       if (ql4xdontresethba) {
+       if (is_qla8032(ha) && ql4xdontresethba)
+               qla4_83xx_set_idc_dontreset(ha);
+
+       /*
+        * For ISP8324, if IDC_CTRL DONTRESET_BIT0 is set by other
+        * protocol drivers, we should not set device_state to
+        * NEED_RESET
+        */
+       if (ql4xdontresethba ||
+           (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
                DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
                     ha->host_no, __func__));
 
@@ -5779,7 +5930,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
        }
 
        if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
-               if (is_qla8022(ha))
+               if (is_qla80XX(ha))
                        set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
                else
                        set_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -5874,7 +6025,7 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
                break;
        case SCSI_FIRMWARE_RESET:
                if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
-                       if (is_qla8022(ha))
+                       if (is_qla80XX(ha))
                                /* set firmware context reset */
                                set_bit(DPC_RESET_HA_FW_CONTEXT,
                                        &ha->dpc_flags);
@@ -6013,32 +6164,43 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
                    "0x%x is the owner\n", ha->host_no, __func__,
                    ha->pdev->devfn);
 
-               qla4_8xxx_idc_lock(ha);
-               qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                   QLA82XX_DEV_COLD);
-
-               qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION,
-                   QLA82XX_IDC_VERSION);
+               ha->isp_ops->idc_lock(ha);
+               qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
+                                   QLA8XXX_DEV_COLD);
+               ha->isp_ops->idc_unlock(ha);
+
+               rval = qla4_8xxx_update_idc_reg(ha);
+               if (rval == QLA_ERROR) {
+                       ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: FAILED\n",
+                                  ha->host_no, __func__);
+                       ha->isp_ops->idc_lock(ha);
+                       qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
+                                           QLA8XXX_DEV_FAILED);
+                       ha->isp_ops->idc_unlock(ha);
+                       goto exit_error_recovery;
+               }
 
-               qla4_8xxx_idc_unlock(ha);
                clear_bit(AF_FW_RECOVERY, &ha->flags);
                rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
-               qla4_8xxx_idc_lock(ha);
 
                if (rval != QLA_SUCCESS) {
                        ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
                            "FAILED\n", ha->host_no, __func__);
+                       ha->isp_ops->idc_lock(ha);
                        qla4_8xxx_clear_drv_active(ha);
-                       qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                           QLA82XX_DEV_FAILED);
+                       qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
+                                           QLA8XXX_DEV_FAILED);
+                       ha->isp_ops->idc_unlock(ha);
                } else {
                        ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
                            "READY\n", ha->host_no, __func__);
-                       qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                           QLA82XX_DEV_READY);
+                       ha->isp_ops->idc_lock(ha);
+                       qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
+                                           QLA8XXX_DEV_READY);
                        /* Clear driver state register */
-                       qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0);
+                       qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, 0);
                        qla4_8xxx_set_drv_active(ha);
+                       ha->isp_ops->idc_unlock(ha);
                        ret = qla4xxx_request_irqs(ha);
                        if (ret) {
                                ql4_printk(KERN_WARNING, ha, "Failed to "
@@ -6050,13 +6212,12 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
                                rval = QLA_SUCCESS;
                        }
                }
-               qla4_8xxx_idc_unlock(ha);
        } else {
                ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not "
                    "the reset owner\n", ha->host_no, __func__,
                    ha->pdev->devfn);
-               if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
-                   QLA82XX_DEV_READY)) {
+               if ((qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE) ==
+                    QLA8XXX_DEV_READY)) {
                        clear_bit(AF_FW_RECOVERY, &ha->flags);
                        rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
                        if (rval == QLA_SUCCESS) {
@@ -6071,11 +6232,12 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
                                        rval = QLA_SUCCESS;
                                }
                        }
-                       qla4_8xxx_idc_lock(ha);
+                       ha->isp_ops->idc_lock(ha);
                        qla4_8xxx_set_drv_active(ha);
-                       qla4_8xxx_idc_unlock(ha);
+                       ha->isp_ops->idc_unlock(ha);
                }
        }
+exit_error_recovery:
        clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
        return rval;
 }
@@ -6114,7 +6276,7 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev)
 
        ha->isp_ops->disable_intrs(ha);
 
-       if (is_qla8022(ha)) {
+       if (is_qla80XX(ha)) {
                if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) {
                        ret = PCI_ERS_RESULT_RECOVERED;
                        goto exit_slot_reset;
@@ -6180,6 +6342,12 @@ static struct pci_device_id qla4xxx_pci_tbl[] = {
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
        },
+       {
+               .vendor         = PCI_VENDOR_ID_QLOGIC,
+               .device         = PCI_DEVICE_ID_QLOGIC_ISP8324,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+       },
        {0, 0},
 };
 MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);