]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
[SCSI] qla2xxx: IDC implementation for ISP83xx.
authorSantosh Vernekar <santosh.vernekar@qlogic.com>
Wed, 22 Aug 2012 18:21:03 +0000 (14:21 -0400)
committerJames Bottomley <JBottomley@Parallels.com>
Fri, 14 Sep 2012 17:28:47 +0000 (18:28 +0100)
Signed-off-by: Santosh Vernekar <santosh.vernekar@qlogic.com>
Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com>
Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
13 files changed:
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_nx.c
drivers/scsi/qla2xxx/qla_nx.h
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c

index da804f487f21871a8e68cf784069afc91db56252..f76424ef05b094ac42f012cf6191367caaa41c6a 100644 (file)
@@ -564,6 +564,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
        int type;
+       uint32_t idc_control;
 
        if (off != 0)
                return -EINVAL;
@@ -587,22 +588,36 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
                scsi_unblock_requests(vha->host);
                break;
        case 0x2025d:
-               if (!IS_QLA81XX(ha) || !IS_QLA8031(ha))
+               if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
                        return -EPERM;
 
                ql_log(ql_log_info, vha, 0x706f,
                    "Issuing MPI reset.\n");
 
-               /* Make sure FC side is not in reset */
-               qla2x00_wait_for_hba_online(vha);
-
-               /* Issue MPI reset */
-               scsi_block_requests(vha->host);
-               if (qla81xx_restart_mpi_firmware(vha) != QLA_SUCCESS)
-                       ql_log(ql_log_warn, vha, 0x7070,
-                           "MPI reset failed.\n");
-               scsi_unblock_requests(vha->host);
-               break;
+               if (IS_QLA83XX(ha)) {
+                       uint32_t idc_control;
+
+                       qla83xx_idc_lock(vha, 0);
+                       __qla83xx_get_idc_control(vha, &idc_control);
+                       idc_control |= QLA83XX_IDC_GRACEFUL_RESET;
+                       __qla83xx_set_idc_control(vha, idc_control);
+                       qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE,
+                           QLA8XXX_DEV_NEED_RESET);
+                       qla83xx_idc_audit(vha, IDC_AUDIT_TIMESTAMP);
+                       qla83xx_idc_unlock(vha, 0);
+                       break;
+               } else {
+                       /* Make sure FC side is not in reset */
+                       qla2x00_wait_for_hba_online(vha);
+
+                       /* Issue MPI reset */
+                       scsi_block_requests(vha->host);
+                       if (qla81xx_restart_mpi_firmware(vha) != QLA_SUCCESS)
+                               ql_log(ql_log_warn, vha, 0x7070,
+                                   "MPI reset failed.\n");
+                       scsi_unblock_requests(vha->host);
+                       break;
+               }
        case 0x2025e:
                if (!IS_QLA82XX(ha) || vha != base_vha) {
                        ql_log(ql_log_info, vha, 0x7071,
@@ -616,6 +631,29 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
                qla2xxx_wake_dpc(vha);
                qla2x00_wait_for_fcoe_ctx_reset(vha);
                break;
+       case 0x2025f:
+               if (!IS_QLA8031(ha))
+                       return -EPERM;
+               ql_log(ql_log_info, vha, 0x70bc,
+                   "Disabling Reset by IDC control\n");
+               qla83xx_idc_lock(vha, 0);
+               __qla83xx_get_idc_control(vha, &idc_control);
+               idc_control |= QLA83XX_IDC_RESET_DISABLED;
+               __qla83xx_set_idc_control(vha, idc_control);
+               qla83xx_idc_unlock(vha, 0);
+               break;
+       case 0x20260:
+               if (!IS_QLA8031(ha))
+                       return -EPERM;
+               ql_log(ql_log_info, vha, 0x70bd,
+                   "Enabling Reset by IDC control\n");
+               qla83xx_idc_lock(vha, 0);
+               __qla83xx_get_idc_control(vha, &idc_control);
+               idc_control &= ~QLA83XX_IDC_RESET_DISABLED;
+               __qla83xx_set_idc_control(vha, idc_control);
+               qla83xx_idc_unlock(vha, 0);
+               break;
+
        }
        return count;
 }
index dac3427ebf24854910038e726e24c3a39032ca51..6da13e26ccac3a1332f67b745b6322b5e27a9049 100644 (file)
@@ -1364,7 +1364,7 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
        struct qla_hw_data *ha = vha->hw;
        int rval = 0;
 
-       if (ha->flags.isp82xx_reset_hdlr_active)
+       if (ha->flags.nic_core_reset_hdlr_active)
                return -EBUSY;
 
        rval = qla2x00_optrom_setup(bsg_job, vha, 0);
index 156f5341a7a3f0bc106d6e8c20a9dbdfe2573868..55998f4fb3aebcb0c3cc5324e101ac6bd237e42c 100644 (file)
  * ----------------------------------------------------------------------
  * |             Level            |   Last Value Used  |     Holes     |
  * ----------------------------------------------------------------------
- * | Module Init and Probe        |       0x0123       | 0x4b,0xba,0xfa |
- * | Mailbox commands             |       0x1140       | 0x111a-0x111b  |
+ * | Module Init and Probe        |       0x0124       | 0x4b,0xba,0xfa |
+ * | Mailbox commands             |       0x114c       | 0x111a-0x111b  |
  * |                              |                    | 0x112c-0x112e  |
  * |                              |                    | 0x113a         |
  * | Device Discovery             |       0x2087       | 0x2020-0x2022  |
  * | Queue Command and IO tracing |       0x3030       | 0x3006,0x3008  |
  * |                              |                    | 0x302d-0x302e  |
  * | DPC Thread                   |       0x401c       | 0x4002,0x4013  |
- * | Async Events                 |       0x505f       | 0x502b-0x502f  |
+ * | Async Events                 |       0x506c       | 0x502b-0x502f  |
  * |                              |                    | 0x5047,0x5052  |
  * | Timer Routines               |       0x6011       |                |
- * | User Space Interactions      |       0x70bb       | 0x7018,0x702e, |
+ * | User Space Interactions      |       0x70bd       | 0x7018,0x702e, |
  * |                              |                    | 0x7039,0x7045, |
  * |                              |                    | 0x7073-0x7075, |
  * |                              |                    | 0x708c,        |
@@ -33,7 +33,7 @@
  * |                              |                    | 0x800b,0x8039  |
  * | AER/EEH                      |       0x9011       |               |
  * | Virtual Port                 |       0xa007       |               |
- * | ISP82XX Specific             |       0xb055       | 0xb024         |
+ * | ISP82XX Specific             |       0xb080       | 0xb024         |
  * | MultiQ                       |       0xc00c       |               |
  * | Misc                         |       0xd010       |               |
  * | Target Mode                 |       0xe06f       |                |
index 9926d9b61285b51819cbc8196cd3baaa4340907e..f82e7bbd9354f2ff823319ab05d6bf054707ecdf 100644 (file)
 #define WRT_REG_WORD(addr, data)       writew(data,addr)
 #define WRT_REG_DWORD(addr, data)      writel(data,addr)
 
+/*
+ * ISP83XX specific remote register addresses
+ */
+#define QLA83XX_LED_PORT0                      0x00201320
+#define QLA83XX_LED_PORT1                      0x00201328
+#define QLA83XX_IDC_DEV_STATE          0x22102384
+#define QLA83XX_IDC_MAJOR_VERSION      0x22102380
+#define QLA83XX_IDC_MINOR_VERSION      0x22102398
+#define QLA83XX_IDC_DRV_PRESENCE       0x22102388
+#define QLA83XX_IDC_DRIVER_ACK         0x2210238c
+#define QLA83XX_IDC_CONTROL                    0x22102390
+#define QLA83XX_IDC_AUDIT                      0x22102394
+#define QLA83XX_IDC_LOCK_RECOVERY      0x2210239c
+#define QLA83XX_DRIVER_LOCKID          0x22102104
+#define QLA83XX_DRIVER_LOCK                    0x8111c028
+#define QLA83XX_DRIVER_UNLOCK          0x8111c02c
+#define QLA83XX_FLASH_LOCKID           0x22102100
+#define QLA83XX_FLASH_LOCK                     0x8111c010
+#define QLA83XX_FLASH_UNLOCK           0x8111c014
+#define QLA83XX_DEV_PARTINFO1          0x221023e0
+#define QLA83XX_DEV_PARTINFO2          0x221023e4
+#define QLA83XX_FW_HEARTBEAT           0x221020b0
+#define QLA83XX_PEG_HALT_STATUS1       0x221020a8
+#define QLA83XX_PEG_HALT_STATUS2       0x221020ac
+
+/* 83XX: Macros defining 8200 AEN Reason codes */
+#define IDC_DEVICE_STATE_CHANGE BIT_0
+#define IDC_PEG_HALT_STATUS_CHANGE BIT_1
+#define IDC_NIC_FW_REPORTED_FAILURE BIT_2
+#define IDC_HEARTBEAT_FAILURE BIT_3
+
+/* 83XX: Macros defining 8200 AEN Error-levels */
+#define ERR_LEVEL_NON_FATAL 0x1
+#define ERR_LEVEL_RECOVERABLE_FATAL 0x2
+#define ERR_LEVEL_UNRECOVERABLE_FATAL 0x4
+
+/* 83XX: Macros for IDC Version */
+#define QLA83XX_SUPP_IDC_MAJOR_VERSION 0x01
+#define QLA83XX_SUPP_IDC_MINOR_VERSION 0x0
+
+/* 83XX: Macros for scheduling dpc tasks */
+#define QLA83XX_NIC_CORE_RESET 0x1
+#define QLA83XX_IDC_STATE_HANDLER 0x2
+#define QLA83XX_NIC_CORE_UNRECOVERABLE 0x3
+
+/* 83XX: Macros for defining IDC-Control bits */
+#define QLA83XX_IDC_RESET_DISABLED BIT_0
+#define QLA83XX_IDC_GRACEFUL_RESET BIT_1
+
+/* 83XX: Macros for different timeouts */
+#define QLA83XX_IDC_INITIALIZATION_TIMEOUT 30
+#define QLA83XX_IDC_RESET_ACK_TIMEOUT 10
+#define QLA83XX_MAX_LOCK_RECOVERY_WAIT (2 * HZ)
+
+/* 83XX: Macros for defining class in DEV-Partition Info register */
+#define QLA83XX_CLASS_TYPE_NONE                0x0
+#define QLA83XX_CLASS_TYPE_NIC         0x1
+#define QLA83XX_CLASS_TYPE_FCOE                0x2
+#define QLA83XX_CLASS_TYPE_ISCSI       0x3
+
+/* 83XX: Macros for IDC Lock-Recovery stages */
+#define IDC_LOCK_RECOVERY_STAGE1       0x1 /* Stage1: Intent for
+                                            * lock-recovery
+                                            */
+#define IDC_LOCK_RECOVERY_STAGE2       0x2 /* Stage2: Perform lock-recovery */
+
+/* 83XX: Macros for IDC Audit type */
+#define IDC_AUDIT_TIMESTAMP            0x0 /* IDC-AUDIT: Record timestamp of
+                                            * dev-state change to NEED-RESET
+                                            * or NEED-QUIESCENT
+                                            */
+#define IDC_AUDIT_COMPLETION           0x1 /* IDC-AUDIT: Record duration of
+                                            * reset-recovery completion is
+                                            * second
+                                            */
+
 /*
  * The ISP2312 v2 chip cannot access the FLASH/GPIO registers via MMIO in an
  * 133Mhz slot.
@@ -596,6 +672,9 @@ typedef struct {
 #define MBA_DISCARD_RND_FRAME  0x8048  /* discard RND frame due to error. */
 #define MBA_REJECTED_FCP_CMD   0x8049  /* rejected FCP_CMD. */
 
+/* 83XX FCoE specific */
+#define MBA_IDC_AEN            0x8200  /* FCoE: NIC Core state change AEN */
+
 /* ISP mailbox loopback echo diagnostic error code */
 #define MBS_LB_RESET   0x17
 /*
@@ -2523,11 +2602,12 @@ struct qla_hw_data {
                uint32_t        disable_msix_handshake  :1;
                uint32_t        fcp_prio_enabled        :1;
                uint32_t        isp82xx_fw_hung:1;
+               uint32_t        nic_core_hung:1;
 
                uint32_t        quiesce_owner:1;
                uint32_t        thermal_supported:1;
-               uint32_t        isp82xx_reset_hdlr_active:1;
-               uint32_t        isp82xx_reset_owner:1;
+               uint32_t        nic_core_reset_hdlr_active:1;
+               uint32_t        nic_core_reset_owner:1;
                uint32_t        isp82xx_no_md_cap:1;
                uint32_t        host_shutting_down:1;
                /* 30 bits */
@@ -2912,8 +2992,8 @@ struct qla_hw_data {
        unsigned long   mn_win_crb;
        unsigned long   ms_win_crb;
        int             qdr_sn_window;
-       uint32_t        nx_dev_init_timeout;
-       uint32_t        nx_reset_timeout;
+       uint32_t        fcoe_dev_init_timeout;
+       uint32_t        fcoe_reset_timeout;
        rwlock_t        hw_lock;
        uint16_t        portnum;                /* port number */
        int             link_width;
@@ -2935,6 +3015,19 @@ struct qla_hw_data {
        uint32_t        md_dump_size;
 
        void            *loop_id_map;
+
+       /* QLA83XX IDC specific fields */
+       uint32_t        idc_audit_ts;
+
+       /* DPC low-priority workqueue */
+       struct workqueue_struct *dpc_lp_wq;
+       struct work_struct idc_aen;
+       /* DPC high-priority workqueue */
+       struct workqueue_struct *dpc_hp_wq;
+       struct work_struct nic_core_reset;
+       struct work_struct idc_state_handler;
+       struct work_struct nic_core_unrecoverable;
+
        struct qlt_hw_data tgt;
 };
 
index a678ed5d6884fb730c1c2ed0f568c8d3d906558d..84543fe487cd21388005c9513dcea431af349069 100644 (file)
@@ -1540,7 +1540,10 @@ struct access_chip_rsp_84xx {
 /*
  * ISP83xx mailbox commands
  */
-#define MBC_WRITE_REMOTE_REG 0x0001 /* Write remote register */
+#define MBC_WRITE_REMOTE_REG           0x0001 /* Write remote register */
+#define MBC_READ_REMOTE_REG            0x0009 /* Read remote register */
+#define MBC_RESTART_NIC_FIRMWARE       0x003d /* Restart NIC firmware */
+#define MBC_SET_ACCESS_CONTROL         0x003e /* Access control command */
 
 /* Flash access control option field bit definitions */
 #define FAC_OPT_FORCE_SEMAPHORE                BIT_15
index d7588adc768b45b932333a6ae81a35a6e4b93b91..98c187da2c91fc114f4b17d8488ec84642874e8f 100644 (file)
@@ -76,6 +76,13 @@ extern int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *, fc_port_t *);
 
 extern fc_port_t *
 qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
+
+extern int __qla83xx_set_idc_control(scsi_qla_host_t *, uint32_t);
+extern int __qla83xx_get_idc_control(scsi_qla_host_t *, uint32_t *);
+extern void qla83xx_idc_audit(scsi_qla_host_t *, int);
+extern int qla83xx_nic_core_reset(scsi_qla_host_t *);
+extern void qla83xx_reset_ownership(scsi_qla_host_t *);
+
 /*
  * Global Data in qla_os.c source file.
  */
@@ -133,6 +140,20 @@ extern void qla2x00_relogin(struct scsi_qla_host *);
 extern void qla2x00_do_work(struct scsi_qla_host *);
 extern void qla2x00_free_fcports(struct scsi_qla_host *);
 
+extern void qla83xx_schedule_work(scsi_qla_host_t *, int);
+extern void qla83xx_service_idc_aen(struct work_struct *);
+extern void qla83xx_nic_core_unrecoverable_work(struct work_struct *);
+extern void qla83xx_idc_state_handler_work(struct work_struct *);
+extern void qla83xx_nic_core_reset_work(struct work_struct *);
+
+extern void qla83xx_idc_lock(scsi_qla_host_t *, uint16_t);
+extern void qla83xx_idc_unlock(scsi_qla_host_t *, uint16_t);
+extern int qla83xx_idc_state_handler(scsi_qla_host_t *);
+extern int qla83xx_set_drv_presence(scsi_qla_host_t *vha);
+extern int __qla83xx_set_drv_presence(scsi_qla_host_t *vha);
+extern int qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
+extern int __qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
+
 /*
  * Global Functions in qla_mid.c source file.
  */
@@ -421,7 +442,11 @@ extern void qla24xx_beacon_blink(struct scsi_qla_host *);
 extern void qla83xx_beacon_blink(struct scsi_qla_host *);
 extern int qla82xx_beacon_on(struct scsi_qla_host *);
 extern int qla82xx_beacon_off(struct scsi_qla_host *);
-extern int qla83xx_write_remote_reg(struct scsi_qla_host *, uint32_t, uint32_t);
+extern int qla83xx_wr_reg(scsi_qla_host_t *, uint32_t, uint32_t);
+extern int qla83xx_rd_reg(scsi_qla_host_t *, uint32_t, uint32_t *);
+extern int qla83xx_restart_nic_firmware(scsi_qla_host_t *);
+extern int qla83xx_access_control(scsi_qla_host_t *, uint16_t, uint32_t,
+    uint32_t, uint16_t *);
 
 extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *,
     uint32_t, uint32_t);
@@ -582,6 +607,7 @@ extern uint32_t  qla82xx_wait_for_state_change(scsi_qla_host_t *, uint32_t);
 extern int qla82xx_idc_lock(struct qla_hw_data *);
 extern void qla82xx_idc_unlock(struct qla_hw_data *);
 extern int qla82xx_device_state_handler(scsi_qla_host_t *);
+extern void qla8xxx_dev_failed_handler(scsi_qla_host_t *);
 extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *);
 
 extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
index 4aef7f0f5a911980bced31845f5405de64e83f02..71310d3c6fd46126af015b4678d06cb1f10fc3c5 100644 (file)
@@ -429,6 +429,71 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
 /*                QLogic ISP2x00 Hardware Support Functions.                */
 /****************************************************************************/
 
+int
+qla83xx_nic_core_fw_load(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t idc_major_ver, idc_minor_ver;
+
+       qla83xx_idc_lock(vha, 0);
+
+       /* SV: TODO: Assign initialization timeout from
+        * flash-info / other param
+        */
+       ha->fcoe_dev_init_timeout = QLA83XX_IDC_INITIALIZATION_TIMEOUT;
+       ha->fcoe_reset_timeout = QLA83XX_IDC_RESET_ACK_TIMEOUT;
+
+       /* Set our fcoe function presence */
+       if (__qla83xx_set_drv_presence(vha) != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_p3p, vha, 0xb077,
+                   "Error while setting DRV-Presence.\n");
+               rval = QLA_FUNCTION_FAILED;
+               goto exit;
+       }
+
+       /* Decide the reset ownership */
+       qla83xx_reset_ownership(vha);
+
+       /*
+        * On first protocol driver load:
+        * Init-Owner: Set IDC-Major-Version and Clear IDC-Lock-Recovery
+        * register.
+        * Others: Check compatibility with current IDC Major version.
+        */
+       qla83xx_rd_reg(vha, QLA83XX_IDC_MAJOR_VERSION, &idc_major_ver);
+       if (ha->flags.nic_core_reset_owner) {
+               /* Set IDC Major version */
+               idc_major_ver = QLA83XX_SUPP_IDC_MAJOR_VERSION;
+               qla83xx_wr_reg(vha, QLA83XX_IDC_MAJOR_VERSION, idc_major_ver);
+
+               /* Clearing IDC-Lock-Recovery register */
+               qla83xx_wr_reg(vha, QLA83XX_IDC_LOCK_RECOVERY, 0);
+       } else if (idc_major_ver != QLA83XX_SUPP_IDC_MAJOR_VERSION) {
+               /*
+                * Clear further IDC participation if we are not compatible with
+                * the current IDC Major Version.
+                */
+               ql_log(ql_log_warn, vha, 0xb07d,
+                   "Failing load, idc_major_ver=%d, expected_major_ver=%d.\n",
+                   idc_major_ver, QLA83XX_SUPP_IDC_MAJOR_VERSION);
+               __qla83xx_clear_drv_presence(vha);
+               rval = QLA_FUNCTION_FAILED;
+               goto exit;
+       }
+       /* Each function sets its supported Minor version. */
+       qla83xx_rd_reg(vha, QLA83XX_IDC_MINOR_VERSION, &idc_minor_ver);
+       idc_minor_ver |= (QLA83XX_SUPP_IDC_MINOR_VERSION << (ha->portnum * 2));
+       qla83xx_wr_reg(vha, QLA83XX_IDC_MINOR_VERSION, idc_minor_ver);
+
+       rval = qla83xx_idc_state_handler(vha);
+
+exit:
+       qla83xx_idc_unlock(vha, 0);
+
+       return rval;
+}
+
 /*
 * qla2x00_initialize_adapter
 *      Initialize board.
@@ -537,6 +602,14 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
                }
        }
 
+       /* Load the NIC Core f/w if we are the first protocol driver. */
+       if (IS_QLA8031(ha)) {
+               rval = qla83xx_nic_core_fw_load(vha);
+               if (rval)
+                       ql_log(ql_log_warn, vha, 0x0124,
+                           "Error in initializing NIC Core f/w.\n");
+       }
+
        if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
                qla24xx_read_fcp_prio_cfg(vha);
 
@@ -3736,6 +3809,307 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
        spin_unlock_irqrestore(&ha->vport_slock, flags);
 }
 
+/* Assumes idc_lock always held on entry */
+void
+qla83xx_reset_ownership(scsi_qla_host_t *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t drv_presence, drv_presence_mask;
+       uint32_t dev_part_info1, dev_part_info2, class_type;
+       uint32_t class_type_mask = 0x3;
+       uint16_t fcoe_other_function = 0xffff, i;
+
+       qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
+
+       qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO1, &dev_part_info1);
+       qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO2, &dev_part_info2);
+       for (i = 0; i < 8; i++) {
+               class_type = ((dev_part_info1 >> (i * 4)) & class_type_mask);
+               if ((class_type == QLA83XX_CLASS_TYPE_FCOE) &&
+                   (i != ha->portnum)) {
+                       fcoe_other_function = i;
+                       break;
+               }
+       }
+       if (fcoe_other_function == 0xffff) {
+               for (i = 0; i < 8; i++) {
+                       class_type = ((dev_part_info2 >> (i * 4)) &
+                           class_type_mask);
+                       if ((class_type == QLA83XX_CLASS_TYPE_FCOE) &&
+                           ((i + 8) != ha->portnum)) {
+                               fcoe_other_function = i + 8;
+                               break;
+                       }
+               }
+       }
+       /*
+        * Prepare drv-presence mask based on fcoe functions present.
+        * However consider only valid physical fcoe function numbers (0-15).
+        */
+       drv_presence_mask = ~((1 << (ha->portnum)) |
+                       ((fcoe_other_function == 0xffff) ?
+                        0 : (1 << (fcoe_other_function))));
+
+       /* We are the reset owner iff:
+        *    - No other protocol drivers present.
+        *    - This is the lowest among fcoe functions. */
+       if (!(drv_presence & drv_presence_mask) &&
+                       (ha->portnum < fcoe_other_function)) {
+               ql_dbg(ql_dbg_p3p, vha, 0xb07f,
+                   "This host is Reset owner.\n");
+               ha->flags.nic_core_reset_owner = 1;
+       }
+}
+
+int
+__qla83xx_set_drv_ack(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t drv_ack;
+
+       rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRIVER_ACK, &drv_ack);
+       if (rval == QLA_SUCCESS) {
+               drv_ack |= (1 << ha->portnum);
+               rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRIVER_ACK, drv_ack);
+       }
+
+       return rval;
+}
+
+int
+qla83xx_set_drv_ack(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+
+       qla83xx_idc_lock(vha, 0);
+       rval = __qla83xx_set_drv_ack(vha);
+       qla83xx_idc_unlock(vha, 0);
+
+       return rval;
+}
+
+int
+__qla83xx_clear_drv_ack(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t drv_ack;
+
+       rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRIVER_ACK, &drv_ack);
+       if (rval == QLA_SUCCESS) {
+               drv_ack &= ~(1 << ha->portnum);
+               rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRIVER_ACK, drv_ack);
+       }
+
+       return rval;
+}
+
+int
+qla83xx_clear_drv_ack(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+
+       qla83xx_idc_lock(vha, 0);
+       rval = __qla83xx_clear_drv_ack(vha);
+       qla83xx_idc_unlock(vha, 0);
+
+       return rval;
+}
+
+const char *
+qla83xx_dev_state_to_string(uint32_t dev_state)
+{
+       switch (dev_state) {
+       case QLA8XXX_DEV_COLD:
+               return "COLD/RE-INIT";
+       case QLA8XXX_DEV_INITIALIZING:
+               return "INITIALIZING";
+       case QLA8XXX_DEV_READY:
+               return "READY";
+       case QLA8XXX_DEV_NEED_RESET:
+               return "NEED RESET";
+       case QLA8XXX_DEV_NEED_QUIESCENT:
+               return "NEED QUIESCENT";
+       case QLA8XXX_DEV_FAILED:
+               return "FAILED";
+       case QLA8XXX_DEV_QUIESCENT:
+               return "QUIESCENT";
+       default:
+               return "Unknown";
+       }
+}
+
+/* Assumes idc-lock always held on entry */
+void
+qla83xx_idc_audit(scsi_qla_host_t *vha, int audit_type)
+{
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t idc_audit_reg = 0, duration_secs = 0;
+
+       switch (audit_type) {
+       case IDC_AUDIT_TIMESTAMP:
+               ha->idc_audit_ts = (jiffies_to_msecs(jiffies) / 1000);
+               idc_audit_reg = (ha->portnum) |
+                   (IDC_AUDIT_TIMESTAMP << 7) | (ha->idc_audit_ts << 8);
+               qla83xx_wr_reg(vha, QLA83XX_IDC_AUDIT, idc_audit_reg);
+               break;
+
+       case IDC_AUDIT_COMPLETION:
+               duration_secs = ((jiffies_to_msecs(jiffies) -
+                   jiffies_to_msecs(ha->idc_audit_ts)) / 1000);
+               idc_audit_reg = (ha->portnum) |
+                   (IDC_AUDIT_COMPLETION << 7) | (duration_secs << 8);
+               qla83xx_wr_reg(vha, QLA83XX_IDC_AUDIT, idc_audit_reg);
+               break;
+
+       default:
+               ql_log(ql_log_warn, vha, 0xb078,
+                   "Invalid audit type specified.\n");
+               break;
+       }
+}
+
+/* Assumes idc_lock always held on entry */
+int
+qla83xx_initiating_reset(scsi_qla_host_t *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t  idc_control, dev_state;
+
+       __qla83xx_get_idc_control(vha, &idc_control);
+       if ((idc_control & QLA83XX_IDC_RESET_DISABLED)) {
+               ql_log(ql_log_info, vha, 0xb080,
+                   "NIC Core reset has been disabled. idc-control=0x%x\n",
+                   idc_control);
+               return QLA_FUNCTION_FAILED;
+       }
+
+       /* Set NEED-RESET iff in READY state and we are the reset-owner */
+       qla83xx_rd_reg(vha, QLA83XX_IDC_DEV_STATE, &dev_state);
+       if (ha->flags.nic_core_reset_owner && dev_state == QLA8XXX_DEV_READY) {
+               qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE,
+                   QLA8XXX_DEV_NEED_RESET);
+               ql_log(ql_log_info, vha, 0xb056, "HW State: NEED RESET.\n");
+               qla83xx_idc_audit(vha, IDC_AUDIT_TIMESTAMP);
+       } else {
+               const char *state = qla83xx_dev_state_to_string(dev_state);
+               ql_log(ql_log_info, vha, 0xb057, "HW State: %s.\n", state);
+
+               /* SV: XXX: Is timeout required here? */
+               /* Wait for IDC state change READY -> NEED_RESET */
+               while (dev_state == QLA8XXX_DEV_READY) {
+                       qla83xx_idc_unlock(vha, 0);
+                       msleep(200);
+                       qla83xx_idc_lock(vha, 0);
+                       qla83xx_rd_reg(vha, QLA83XX_IDC_DEV_STATE, &dev_state);
+               }
+       }
+
+       /* Send IDC ack by writing to drv-ack register */
+       __qla83xx_set_drv_ack(vha);
+
+       return QLA_SUCCESS;
+}
+
+int
+__qla83xx_set_idc_control(scsi_qla_host_t *vha, uint32_t idc_control)
+{
+       return qla83xx_wr_reg(vha, QLA83XX_IDC_CONTROL, idc_control);
+}
+
+int
+qla83xx_set_idc_control(scsi_qla_host_t *vha, uint32_t idc_control)
+{
+       int rval = QLA_SUCCESS;
+
+       qla83xx_idc_lock(vha, 0);
+       rval = __qla83xx_set_idc_control(vha, idc_control);
+       qla83xx_idc_unlock(vha, 0);
+
+       return rval;
+}
+
+int
+__qla83xx_get_idc_control(scsi_qla_host_t *vha, uint32_t *idc_control)
+{
+       return qla83xx_rd_reg(vha, QLA83XX_IDC_CONTROL, idc_control);
+}
+
+int
+qla83xx_get_idc_control(scsi_qla_host_t *vha, uint32_t *idc_control)
+{
+       int rval = QLA_SUCCESS;
+
+       qla83xx_idc_lock(vha, 0);
+       rval = __qla83xx_get_idc_control(vha, idc_control);
+       qla83xx_idc_unlock(vha, 0);
+
+       return rval;
+}
+
+int
+qla83xx_check_driver_presence(scsi_qla_host_t *vha)
+{
+       uint32_t drv_presence = 0;
+       struct qla_hw_data *ha = vha->hw;
+
+       qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
+       if (drv_presence & (1 << ha->portnum))
+               return QLA_SUCCESS;
+       else
+               return QLA_TEST_FAILED;
+}
+
+int
+qla83xx_nic_core_reset(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+       struct qla_hw_data *ha = vha->hw;
+
+       ql_dbg(ql_dbg_p3p, vha, 0xb058,
+           "Entered  %s().\n", __func__);
+
+       if (vha->device_flags & DFLG_DEV_FAILED) {
+               ql_log(ql_log_warn, vha, 0xb059,
+                   "Device in unrecoverable FAILED state.\n");
+               return QLA_FUNCTION_FAILED;
+       }
+
+       qla83xx_idc_lock(vha, 0);
+
+       if (qla83xx_check_driver_presence(vha) != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0xb05a,
+                   "Function=0x%x has been removed from IDC participation.\n",
+                   ha->portnum);
+               rval = QLA_FUNCTION_FAILED;
+               goto exit;
+       }
+
+       qla83xx_reset_ownership(vha);
+
+       rval = qla83xx_initiating_reset(vha);
+
+       /*
+        * Perform reset if we are the reset-owner,
+        * else wait till IDC state changes to READY/FAILED.
+        */
+       if (rval == QLA_SUCCESS) {
+               rval = qla83xx_idc_state_handler(vha);
+
+               if (rval == QLA_SUCCESS)
+                       ha->flags.nic_core_hung = 0;
+               __qla83xx_clear_drv_ack(vha);
+       }
+
+exit:
+       qla83xx_idc_unlock(vha, 0);
+
+       ql_dbg(ql_dbg_p3p, vha, 0xb05b, "Exiting %s.\n", __func__);
+
+       return rval;
+}
+
 /*
 * qla82xx_quiescent_state_cleanup
 * Description: This function will block the new I/Os
@@ -3871,6 +4245,14 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
        struct req_que *req = ha->req_q_map[0];
        unsigned long flags;
 
+       if (IS_QLA8031(ha)) {
+               ql_dbg(ql_dbg_p3p, vha, 0xb05c,
+                   "Clearing fcoe driver presence.\n");
+               if (qla83xx_clear_drv_presence(vha) != QLA_SUCCESS)
+                       ql_dbg(ql_dbg_p3p, vha, 0xb073,
+                           "Erro while clearing DRV-Presence.\n");
+       }
+
        if (vha->flags.online) {
                qla2x00_abort_isp_cleanup(vha);
 
@@ -3982,6 +4364,13 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                }
                spin_unlock_irqrestore(&ha->vport_slock, flags);
 
+               if (IS_QLA8031(ha)) {
+                       ql_dbg(ql_dbg_p3p, vha, 0xb05d,
+                           "Setting back fcoe driver presence.\n");
+                       if (qla83xx_set_drv_presence(vha) != QLA_SUCCESS)
+                               ql_dbg(ql_dbg_p3p, vha, 0xb074,
+                                   "Error while setting DRV-Presence.\n");
+               }
        } else {
                ql_log(ql_log_warn, vha, 0x8023, "%s **** FAILED ****.\n",
                       __func__);
index 2ea848c01199aa4b16e558c1336cb9a8401cfd97..681a9f897fa35a871503b259eca820bcc7b6c3f6 100644 (file)
@@ -332,6 +332,166 @@ qla2x00_get_link_speed_str(struct qla_hw_data *ha)
        return link_speed;
 }
 
+void
+qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
+{
+       struct qla_hw_data *ha = vha->hw;
+
+       /*
+        * 8200 AEN Interpretation:
+        * mb[0] = AEN code
+        * mb[1] = AEN Reason code
+        * mb[2] = LSW of Peg-Halt Status-1 Register
+        * mb[6] = MSW of Peg-Halt Status-1 Register
+        * mb[3] = LSW of Peg-Halt Status-2 register
+        * mb[7] = MSW of Peg-Halt Status-2 register
+        * mb[4] = IDC Device-State Register value
+        * mb[5] = IDC Driver-Presence Register value
+        */
+       ql_dbg(ql_dbg_async, vha, 0x506b, "AEN Code: mb[0] = 0x%x AEN reason: "
+           "mb[1] = 0x%x PH-status1: mb[2] = 0x%x PH-status1: mb[6] = 0x%x.\n",
+           mb[0], mb[1], mb[2], mb[6]);
+       ql_dbg(ql_dbg_async, vha, 0x506c, "PH-status2: mb[3] = 0x%x "
+           "PH-status2: mb[7] = 0x%x Device-State: mb[4] = 0x%x "
+           "Drv-Presence: mb[5] = 0x%x.\n", mb[3], mb[7], mb[4], mb[5]);
+
+       if (mb[1] & (IDC_PEG_HALT_STATUS_CHANGE | IDC_NIC_FW_REPORTED_FAILURE |
+                               IDC_HEARTBEAT_FAILURE)) {
+               ha->flags.nic_core_hung = 1;
+               ql_log(ql_log_warn, vha, 0x5060,
+                   "83XX: F/W Error Reported: Check if reset required.\n");
+
+               if (mb[1] & IDC_PEG_HALT_STATUS_CHANGE) {
+                       uint32_t protocol_engine_id, fw_err_code, err_level;
+
+                       /*
+                        * IDC_PEG_HALT_STATUS_CHANGE interpretation:
+                        *  - PEG-Halt Status-1 Register:
+                        *      (LSW = mb[2], MSW = mb[6])
+                        *      Bits 0-7   = protocol-engine ID
+                        *      Bits 8-28  = f/w error code
+                        *      Bits 29-31 = Error-level
+                        *          Error-level 0x1 = Non-Fatal error
+                        *          Error-level 0x2 = Recoverable Fatal error
+                        *          Error-level 0x4 = UnRecoverable Fatal error
+                        *  - PEG-Halt Status-2 Register:
+                        *      (LSW = mb[3], MSW = mb[7])
+                        */
+                       protocol_engine_id = (mb[2] & 0xff);
+                       fw_err_code = (((mb[2] & 0xff00) >> 8) |
+                           ((mb[6] & 0x1fff) << 8));
+                       err_level = ((mb[6] & 0xe000) >> 13);
+                       ql_log(ql_log_warn, vha, 0x5061, "PegHalt Status-1 "
+                           "Register: protocol_engine_id=0x%x "
+                           "fw_err_code=0x%x err_level=0x%x.\n",
+                           protocol_engine_id, fw_err_code, err_level);
+                       ql_log(ql_log_warn, vha, 0x5062, "PegHalt Status-2 "
+                           "Register: 0x%x%x.\n", mb[7], mb[3]);
+                       if (err_level == ERR_LEVEL_NON_FATAL) {
+                               ql_log(ql_log_warn, vha, 0x5063,
+                                   "Not a fatal error, f/w has recovered "
+                                   "iteself.\n");
+                       } else if (err_level == ERR_LEVEL_RECOVERABLE_FATAL) {
+                               ql_log(ql_log_fatal, vha, 0x5064,
+                                   "Recoverable Fatal error: Chip reset "
+                                   "required.\n");
+                               qla83xx_schedule_work(vha,
+                                   QLA83XX_NIC_CORE_RESET);
+                       } else if (err_level == ERR_LEVEL_UNRECOVERABLE_FATAL) {
+                               ql_log(ql_log_fatal, vha, 0x5065,
+                                   "Unrecoverable Fatal error: Set FAILED "
+                                   "state, reboot required.\n");
+                               qla83xx_schedule_work(vha,
+                                   QLA83XX_NIC_CORE_UNRECOVERABLE);
+                       }
+               }
+
+               if (mb[1] & IDC_NIC_FW_REPORTED_FAILURE) {
+                       uint16_t peg_fw_state, nw_interface_link_up;
+                       uint16_t nw_interface_signal_detect, sfp_status;
+                       uint16_t htbt_counter, htbt_monitor_enable;
+                       uint16_t sfp_additonal_info, sfp_multirate;
+                       uint16_t sfp_tx_fault, link_speed, dcbx_status;
+
+                       /*
+                        * IDC_NIC_FW_REPORTED_FAILURE interpretation:
+                        *  - PEG-to-FC Status Register:
+                        *      (LSW = mb[2], MSW = mb[6])
+                        *      Bits 0-7   = Peg-Firmware state
+                        *      Bit 8      = N/W Interface Link-up
+                        *      Bit 9      = N/W Interface signal detected
+                        *      Bits 10-11 = SFP Status
+                        *        SFP Status 0x0 = SFP+ transceiver not expected
+                        *        SFP Status 0x1 = SFP+ transceiver not present
+                        *        SFP Status 0x2 = SFP+ transceiver invalid
+                        *        SFP Status 0x3 = SFP+ transceiver present and
+                        *        valid
+                        *      Bits 12-14 = Heartbeat Counter
+                        *      Bit 15     = Heartbeat Monitor Enable
+                        *      Bits 16-17 = SFP Additional Info
+                        *        SFP info 0x0 = Unregocnized transceiver for
+                        *        Ethernet
+                        *        SFP info 0x1 = SFP+ brand validation failed
+                        *        SFP info 0x2 = SFP+ speed validation failed
+                        *        SFP info 0x3 = SFP+ access error
+                        *      Bit 18     = SFP Multirate
+                        *      Bit 19     = SFP Tx Fault
+                        *      Bits 20-22 = Link Speed
+                        *      Bits 23-27 = Reserved
+                        *      Bits 28-30 = DCBX Status
+                        *        DCBX Status 0x0 = DCBX Disabled
+                        *        DCBX Status 0x1 = DCBX Enabled
+                        *        DCBX Status 0x2 = DCBX Exchange error
+                        *      Bit 31     = Reserved
+                        */
+                       peg_fw_state = (mb[2] & 0x00ff);
+                       nw_interface_link_up = ((mb[2] & 0x0100) >> 8);
+                       nw_interface_signal_detect = ((mb[2] & 0x0200) >> 9);
+                       sfp_status = ((mb[2] & 0x0c00) >> 10);
+                       htbt_counter = ((mb[2] & 0x7000) >> 12);
+                       htbt_monitor_enable = ((mb[2] & 0x8000) >> 15);
+                       sfp_additonal_info = (mb[6] & 0x0003);
+                       sfp_multirate = ((mb[6] & 0x0004) >> 2);
+                       sfp_tx_fault = ((mb[6] & 0x0008) >> 3);
+                       link_speed = ((mb[6] & 0x0070) >> 4);
+                       dcbx_status = ((mb[6] & 0x7000) >> 12);
+
+                       ql_log(ql_log_warn, vha, 0x5066,
+                           "Peg-to-Fc Status Register:\n"
+                           "peg_fw_state=0x%x, nw_interface_link_up=0x%x, "
+                           "nw_interface_signal_detect=0x%x"
+                           "\nsfp_statis=0x%x.\n ", peg_fw_state,
+                           nw_interface_link_up, nw_interface_signal_detect,
+                           sfp_status);
+                       ql_log(ql_log_warn, vha, 0x5067,
+                           "htbt_counter=0x%x, htbt_monitor_enable=0x%x, "
+                           "sfp_additonal_info=0x%x, sfp_multirate=0x%x.\n ",
+                           htbt_counter, htbt_monitor_enable,
+                           sfp_additonal_info, sfp_multirate);
+                       ql_log(ql_log_warn, vha, 0x5068,
+                           "sfp_tx_fault=0x%x, link_state=0x%x, "
+                           "dcbx_status=0x%x.\n", sfp_tx_fault, link_speed,
+                           dcbx_status);
+
+                       qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
+               }
+
+               if (mb[1] & IDC_HEARTBEAT_FAILURE) {
+                       ql_log(ql_log_warn, vha, 0x5069,
+                           "Heartbeat Failure encountered, chip reset "
+                           "required.\n");
+
+                       qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
+               }
+       }
+
+       if (mb[1] & IDC_DEVICE_STATE_CHANGE) {
+               ql_log(ql_log_info, vha, 0x506a,
+                   "IDC Device-State changed = 0x%x.\n", mb[4]);
+               qla83xx_schedule_work(vha, MBA_IDC_AEN);
+       }
+}
+
 /**
  * qla2x00_async_event() - Process aynchronous events.
  * @ha: SCSI driver HA context
@@ -825,8 +985,18 @@ skip_rio:
        case MBA_IDC_COMPLETE:
        case MBA_IDC_NOTIFY:
        case MBA_IDC_TIME_EXT:
-               qla81xx_idc_event(vha, mb[0], mb[1]);
+               if (IS_QLA81XX(vha->hw))
+                       qla81xx_idc_event(vha, mb[0], mb[1]);
+               break;
+
+       case MBA_IDC_AEN:
+               mb[4] = RD_REG_WORD(&reg24->mailbox4);
+               mb[5] = RD_REG_WORD(&reg24->mailbox5);
+               mb[6] = RD_REG_WORD(&reg24->mailbox6);
+               mb[7] = RD_REG_WORD(&reg24->mailbox7);
+               qla83xx_handle_8200_aen(vha, mb);
                break;
+
        default:
                ql_dbg(ql_dbg_async, vha, 0x5057,
                    "Unknown AEN:%04x %04x %04x %04x\n",
@@ -2301,7 +2471,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
        unsigned long   iter;
        uint32_t        stat;
        uint32_t        hccr;
-       uint16_t        mb[4];
+       uint16_t        mb[8];
        struct rsp_que *rsp;
        unsigned long   flags;
 
@@ -2457,7 +2627,7 @@ qla24xx_msix_default(int irq, void *dev_id)
        int             status;
        uint32_t        stat;
        uint32_t        hccr;
-       uint16_t        mb[4];
+       uint16_t        mb[8];
        unsigned long flags;
 
        rsp = (struct rsp_que *) dev_id;
index f8a1a64c0ca7f2172364961860cb085b27a8e585..1587b64b4bc399427e20af8d496d555ec05cecf1 100644 (file)
@@ -75,7 +75,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                return QLA_FUNCTION_TIMEOUT;
        }
 
-       if (ha->flags.isp82xx_fw_hung) {
+       if (IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung) {
                /* Setting Link-Down error */
                mcp->mb[0] = MBS_LINK_DOWN_ERROR;
                ql_log(ql_log_warn, vha, 0x1004,
@@ -232,7 +232,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                ha->flags.mbox_int = 0;
                clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
-               if (ha->flags.isp82xx_fw_hung) {
+               if ((IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung)) {
                        ha->flags.mbox_busy = 0;
                        /* Setting Link-Down error */
                        mcp->mb[0] = MBS_LINK_DOWN_ERROR;
@@ -4741,7 +4741,7 @@ qla82xx_mbx_beacon_ctl(scsi_qla_host_t *vha, int enable)
 }
 
 int
-qla83xx_write_remote_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data)
+qla83xx_wr_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data)
 {
        int rval;
        struct qla_hw_data *ha = vha->hw;
@@ -4814,3 +4814,139 @@ qla2x00_port_logout(scsi_qla_host_t *vha, struct fc_port *fcport)
        return rval;
 }
 
+int
+qla83xx_rd_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t *data)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+       struct qla_hw_data *ha = vha->hw;
+       unsigned long retry_max_time = jiffies + (2 * HZ);
+
+       if (!IS_QLA83XX(ha))
+               return QLA_FUNCTION_FAILED;
+
+       ql_dbg(ql_dbg_mbx, vha, 0x114b, "Entered %s.\n", __func__);
+
+retry_rd_reg:
+       mcp->mb[0] = MBC_READ_REMOTE_REG;
+       mcp->mb[1] = LSW(reg);
+       mcp->mb[2] = MSW(reg);
+       mcp->out_mb = MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_4|MBX_3|MBX_1|MBX_0;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_mbx, vha, 0x114c,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
+       } else {
+               *data = (mcp->mb[3] | (mcp->mb[4] << 16));
+               if (*data == QLA8XXX_BAD_VALUE) {
+                       /*
+                        * During soft-reset CAMRAM register reads might
+                        * return 0xbad0bad0. So retry for MAX of 2 sec
+                        * while reading camram registers.
+                        */
+                       if (time_after(jiffies, retry_max_time)) {
+                               ql_dbg(ql_dbg_mbx, vha, 0x1141,
+                                   "Failure to read CAMRAM register. "
+                                   "data=0x%x.\n", *data);
+                               return QLA_FUNCTION_FAILED;
+                       }
+                       msleep(100);
+                       goto retry_rd_reg;
+               }
+               ql_dbg(ql_dbg_mbx, vha, 0x1142, "Done %s.\n", __func__);
+       }
+
+       return rval;
+}
+
+int
+qla83xx_restart_nic_firmware(scsi_qla_host_t *vha)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (!IS_QLA83XX(ha))
+               return QLA_FUNCTION_FAILED;
+
+       ql_dbg(ql_dbg_mbx, vha, 0x1143, "Entered %s.\n", __func__);
+
+       mcp->mb[0] = MBC_RESTART_NIC_FIRMWARE;
+       mcp->out_mb = MBX_0;
+       mcp->in_mb = MBX_1|MBX_0;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_mbx, vha, 0x1144,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
+               ha->isp_ops->fw_dump(vha, 0);
+       } else {
+               ql_dbg(ql_dbg_mbx, vha, 0x1145, "Done %s.\n", __func__);
+       }
+
+       return rval;
+}
+
+int
+qla83xx_access_control(scsi_qla_host_t *vha, uint16_t options,
+       uint32_t start_addr, uint32_t end_addr, uint16_t *sector_size)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+       uint8_t subcode = (uint8_t)options;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (!IS_QLA8031(ha))
+               return QLA_FUNCTION_FAILED;
+
+       ql_dbg(ql_dbg_mbx, vha, 0x1146, "Entered %s.\n", __func__);
+
+       mcp->mb[0] = MBC_SET_ACCESS_CONTROL;
+       mcp->mb[1] = options;
+       mcp->out_mb = MBX_1|MBX_0;
+       if (subcode & BIT_2) {
+               mcp->mb[2] = LSW(start_addr);
+               mcp->mb[3] = MSW(start_addr);
+               mcp->mb[4] = LSW(end_addr);
+               mcp->mb[5] = MSW(end_addr);
+               mcp->out_mb |= MBX_5|MBX_4|MBX_3|MBX_2;
+       }
+       mcp->in_mb = MBX_2|MBX_1|MBX_0;
+       if (!(subcode & (BIT_2 | BIT_5)))
+               mcp->in_mb |= MBX_4|MBX_3;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_mbx, vha, 0x1147,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[3]=%x mb[4]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3],
+                   mcp->mb[4]);
+               ha->isp_ops->fw_dump(vha, 0);
+       } else {
+               if (subcode & BIT_5)
+                       *sector_size = mcp->mb[1];
+               else if (subcode & (BIT_6 | BIT_7)) {
+                       ql_dbg(ql_dbg_mbx, vha, 0x1148,
+                           "Driver-lock id=%x%x", mcp->mb[4], mcp->mb[3]);
+               } else if (subcode & (BIT_3 | BIT_4)) {
+                       ql_dbg(ql_dbg_mbx, vha, 0x1149,
+                           "Flash-lock id=%x%x", mcp->mb[4], mcp->mb[3]);
+               }
+               ql_dbg(ql_dbg_mbx, vha, 0x114a, "Done %s.\n", __func__);
+       }
+
+       return rval;
+}
index 642aea04faa7439e3b6aefab58ae145bc1f89d10..75cdf200f45329f6caf62b40e6c30dda35cd66b5 100644 (file)
@@ -2355,7 +2355,7 @@ qla82xx_need_reset(struct qla_hw_data *ha)
        uint32_t drv_state;
        int rval;
 
-       if (ha->flags.isp82xx_reset_owner)
+       if (ha->flags.nic_core_reset_owner)
                return 1;
        else {
                drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
@@ -2864,7 +2864,7 @@ qla82xx_device_bootstrap(scsi_qla_host_t *vha)
                timeout = msleep_interruptible(200);
                if (timeout) {
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                               QLA82XX_DEV_FAILED);
+                               QLA8XXX_DEV_FAILED);
                        return QLA_FUNCTION_FAILED;
                }
 
@@ -2895,7 +2895,7 @@ dev_initialize:
        /* set to DEV_INITIALIZING */
        ql_log(ql_log_info, vha, 0x009e,
            "HW State: INITIALIZING.\n");
-       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING);
+       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_INITIALIZING);
 
        /* Driver that sets device state to initializating sets IDC version */
        qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION);
@@ -2908,14 +2908,14 @@ dev_initialize:
                ql_log(ql_log_fatal, vha, 0x00ad,
                    "HW State: FAILED.\n");
                qla82xx_clear_drv_active(ha);
-               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED);
+               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_FAILED);
                return rval;
        }
 
 dev_ready:
        ql_log(ql_log_info, vha, 0x00ae,
            "HW State: READY.\n");
-       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY);
+       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_READY);
 
        return QLA_SUCCESS;
 }
@@ -2964,7 +2964,7 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
                            "DRV_STATE:%d.\n", QLA2XXX_DRIVER_NAME,
                            drv_active, drv_state);
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                           QLA82XX_DEV_READY);
+                           QLA8XXX_DEV_READY);
                        ql_log(ql_log_info, vha, 0xb025,
                            "HW State: DEV_READY.\n");
                        qla82xx_idc_unlock(ha);
@@ -2985,10 +2985,10 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
        }
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
        /* everyone acked so set the state to DEV_QUIESCENCE */
-       if (dev_state == QLA82XX_DEV_NEED_QUIESCENT) {
+       if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT) {
                ql_log(ql_log_info, vha, 0xb026,
                    "HW State: DEV_QUIESCENT.\n");
-               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_QUIESCENT);
+               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_QUIESCENT);
        }
 }
 
@@ -3018,8 +3018,8 @@ qla82xx_wait_for_state_change(scsi_qla_host_t *vha, uint32_t curr_state)
        return dev_state;
 }
 
-static void
-qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
+void
+qla8xxx_dev_failed_handler(scsi_qla_host_t *vha)
 {
        struct qla_hw_data *ha = vha->hw;
 
@@ -3067,7 +3067,7 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
        }
 
        drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
-       if (!ha->flags.isp82xx_reset_owner) {
+       if (!ha->flags.nic_core_reset_owner) {
                ql_dbg(ql_dbg_p3p, vha, 0xb028,
                    "reset_acknowledged by 0x%x\n", ha->portnum);
                qla82xx_set_rst_ready(ha);
@@ -3079,7 +3079,7 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
        }
 
        /* wait for 10 seconds for reset ack from all functions */
-       reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
+       reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
 
        drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
        drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
@@ -3091,7 +3091,7 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
            drv_state, drv_active, dev_state, active_mask);
 
        while (drv_state != drv_active &&
-           dev_state != QLA82XX_DEV_INITIALIZING) {
+           dev_state != QLA8XXX_DEV_INITIALIZING) {
                if (time_after_eq(jiffies, reset_timeout)) {
                        ql_log(ql_log_warn, vha, 0x00b5,
                            "Reset timeout.\n");
@@ -3102,7 +3102,7 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
                qla82xx_idc_lock(ha);
                drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
                drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
-               if (ha->flags.isp82xx_reset_owner)
+               if (ha->flags.nic_core_reset_owner)
                        drv_active &= active_mask;
                dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
        }
@@ -3118,11 +3118,11 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
            dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown");
 
        /* Force to DEV_COLD unless someone else is starting a reset */
-       if (dev_state != QLA82XX_DEV_INITIALIZING &&
-           dev_state != QLA82XX_DEV_COLD) {
+       if (dev_state != QLA8XXX_DEV_INITIALIZING &&
+           dev_state != QLA8XXX_DEV_COLD) {
                ql_log(ql_log_info, vha, 0x00b7,
                    "HW State: COLD/RE-INIT.\n");
-               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD);
+               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_COLD);
                qla82xx_set_rst_ready(ha);
                if (ql2xmdenable) {
                        if (qla82xx_md_collect(vha))
@@ -3240,7 +3240,7 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
            dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown");
 
        /* wait for 30 seconds for device to go ready */
-       dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
+       dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ);
 
        while (1) {
 
@@ -3264,18 +3264,18 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
                }
 
                switch (dev_state) {
-               case QLA82XX_DEV_READY:
-                       ha->flags.isp82xx_reset_owner = 0;
+               case QLA8XXX_DEV_READY:
+                       ha->flags.nic_core_reset_owner = 0;
                        goto rel_lock;
-               case QLA82XX_DEV_COLD:
+               case QLA8XXX_DEV_COLD:
                        rval = qla82xx_device_bootstrap(vha);
                        break;
-               case QLA82XX_DEV_INITIALIZING:
+               case QLA8XXX_DEV_INITIALIZING:
                        qla82xx_idc_unlock(ha);
                        msleep(1000);
                        qla82xx_idc_lock(ha);
                        break;
-               case QLA82XX_DEV_NEED_RESET:
+               case QLA8XXX_DEV_NEED_RESET:
                        if (!ql2xdontresethba)
                                qla82xx_need_reset_handler(vha);
                        else {
@@ -3284,15 +3284,15 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
                                qla82xx_idc_lock(ha);
                        }
                        dev_init_timeout = jiffies +
-                           (ha->nx_dev_init_timeout * HZ);
+                           (ha->fcoe_dev_init_timeout * HZ);
                        break;
-               case QLA82XX_DEV_NEED_QUIESCENT:
+               case QLA8XXX_DEV_NEED_QUIESCENT:
                        qla82xx_need_qsnt_handler(vha);
                        /* Reset timeout value after quiescence handler */
-                       dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
+                       dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout\
                                                         * HZ);
                        break;
-               case QLA82XX_DEV_QUIESCENT:
+               case QLA8XXX_DEV_QUIESCENT:
                        /* Owner will exit and other will wait for the state
                         * to get changed
                         */
@@ -3304,11 +3304,11 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
                        qla82xx_idc_lock(ha);
 
                        /* Reset timeout value after quiescence handler */
-                       dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
+                       dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout\
                                                         * HZ);
                        break;
-               case QLA82XX_DEV_FAILED:
-                       qla82xx_dev_failed_handler(vha);
+               case QLA8XXX_DEV_FAILED:
+                       qla8xxx_dev_failed_handler(vha);
                        rval = QLA_FUNCTION_FAILED;
                        goto exit;
                default:
@@ -3368,23 +3368,23 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
 
        /* don't poll if reset is going on */
-       if (!ha->flags.isp82xx_reset_hdlr_active) {
+       if (!ha->flags.nic_core_reset_hdlr_active) {
                dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
                if (qla82xx_check_temp(vha)) {
                        set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
                        ha->flags.isp82xx_fw_hung = 1;
                        qla82xx_clear_pending_mbx(vha);
-               } else if (dev_state == QLA82XX_DEV_NEED_RESET &&
+               } else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
                    !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
                        ql_log(ql_log_warn, vha, 0x6001,
                            "Adapter reset needed.\n");
                        set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
-               } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
+               } else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
                        !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
                        ql_log(ql_log_warn, vha, 0x6002,
                            "Quiescent needed.\n");
                        set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
-               } else if (dev_state == QLA82XX_DEV_FAILED &&
+               } else if (dev_state == QLA8XXX_DEV_FAILED &&
                        !test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) &&
                        vha->flags.online == 1) {
                        ql_log(ql_log_warn, vha, 0xb055,
@@ -3453,12 +3453,12 @@ qla82xx_set_reset_owner(scsi_qla_host_t *vha)
        uint32_t dev_state;
 
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
-       if (dev_state == QLA82XX_DEV_READY) {
+       if (dev_state == QLA8XXX_DEV_READY) {
                ql_log(ql_log_info, vha, 0xb02f,
                    "HW State: NEED RESET\n");
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                       QLA82XX_DEV_NEED_RESET);
-               ha->flags.isp82xx_reset_owner = 1;
+                       QLA8XXX_DEV_NEED_RESET);
+               ha->flags.nic_core_reset_owner = 1;
                ql_dbg(ql_dbg_p3p, vha, 0xb030,
                    "reset_owner is 0x%x\n", ha->portnum);
        } else
@@ -3489,7 +3489,7 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
                    "Device in failed state, exiting.\n");
                return QLA_SUCCESS;
        }
-       ha->flags.isp82xx_reset_hdlr_active = 1;
+       ha->flags.nic_core_reset_hdlr_active = 1;
 
        qla82xx_idc_lock(ha);
        qla82xx_set_reset_owner(vha);
@@ -3503,7 +3503,7 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
 
        if (rval == QLA_SUCCESS) {
                ha->flags.isp82xx_fw_hung = 0;
-               ha->flags.isp82xx_reset_hdlr_active = 0;
+               ha->flags.nic_core_reset_hdlr_active = 0;
                qla82xx_restart_isp(vha);
        }
 
index 6eb210e3cc637242aed65efde17902a0f94c2d60..d0aa16ccf49a3609ebd20fc76186595571cf6a49 100644 (file)
 #define QLA82XX_CRB_DRV_IDC_VERSION  (QLA82XX_CAM_RAM(0x174))
 
 /* Every driver should use these Device State */
-#define QLA82XX_DEV_COLD               1
-#define QLA82XX_DEV_INITIALIZING       2
-#define QLA82XX_DEV_READY              3
-#define QLA82XX_DEV_NEED_RESET         4
-#define QLA82XX_DEV_NEED_QUIESCENT     5
-#define QLA82XX_DEV_FAILED             6
-#define QLA82XX_DEV_QUIESCENT          7
+#define QLA8XXX_DEV_COLD               1
+#define QLA8XXX_DEV_INITIALIZING       2
+#define QLA8XXX_DEV_READY              3
+#define QLA8XXX_DEV_NEED_RESET         4
+#define QLA8XXX_DEV_NEED_QUIESCENT     5
+#define QLA8XXX_DEV_FAILED             6
+#define QLA8XXX_DEV_QUIESCENT          7
 #define        MAX_STATES                      8 /* Increment if new state added */
+#define QLA8XXX_BAD_VALUE              0xbad0bad0
 
 #define QLA82XX_IDC_VERSION                    1
 #define QLA82XX_ROM_DEV_INIT_TIMEOUT           30
index d96adb73a1fe1045d083e4db1fa3422ced18dab3..8862d5b65a770338f266657c8b7535f63ac1225c 100644 (file)
@@ -2149,7 +2149,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        scsi_qla_host_t *base_vha = NULL;
        struct qla_hw_data *ha;
        char pci_info[30];
-       char fw_str[30];
+       char fw_str[30], wq_name[30];
        struct scsi_host_template *sht;
        int bars, mem_only = 0;
        uint16_t req_length = 0, rsp_length = 0;
@@ -2319,6 +2319,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
                ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
        } else if (IS_QLA83XX(ha)) {
+               ha->portnum = PCI_FUNC(ha->pdev->devfn);
                ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
                ha->mbx_count = MAILBOX_REGISTER_COUNT;
                req_length = REQUEST_ENTRY_CNT_24XX;
@@ -2403,6 +2404,20 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER +
                                                base_vha->vp_idx;
 
+       if (IS_QLA8031(ha)) {
+               sprintf(wq_name, "qla2xxx_%lu_dpc_lp_wq", base_vha->host_no);
+               ha->dpc_lp_wq = create_singlethread_workqueue(wq_name);
+               INIT_WORK(&ha->idc_aen, qla83xx_service_idc_aen);
+
+               sprintf(wq_name, "qla2xxx_%lu_dpc_hp_wq", base_vha->host_no);
+               ha->dpc_hp_wq = create_singlethread_workqueue(wq_name);
+               INIT_WORK(&ha->nic_core_reset, qla83xx_nic_core_reset_work);
+               INIT_WORK(&ha->idc_state_handler,
+                   qla83xx_idc_state_handler_work);
+               INIT_WORK(&ha->nic_core_unrecoverable,
+                   qla83xx_nic_core_unrecoverable_work);
+       }
+
        /* Set the SG table size based on ISP type */
        if (!IS_FWI2_CAPABLE(ha)) {
                if (IS_QLA2100(ha))
@@ -2500,7 +2515,7 @@ que_init:
                if (IS_QLA82XX(ha)) {
                        qla82xx_idc_lock(ha);
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                               QLA82XX_DEV_FAILED);
+                               QLA8XXX_DEV_FAILED);
                        qla82xx_idc_unlock(ha);
                        ql_log(ql_log_fatal, base_vha, 0x00d7,
                            "HW State: FAILED.\n");
@@ -2751,6 +2766,14 @@ qla2x00_remove_one(struct pci_dev *pdev)
        }
        mutex_unlock(&ha->vport_lock);
 
+       if (IS_QLA8031(ha)) {
+               ql_dbg(ql_dbg_p3p, base_vha, 0xb07e,
+                   "Clearing fcoe driver presence.\n");
+               if (qla83xx_clear_drv_presence(base_vha) != QLA_SUCCESS)
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb079,
+                           "Error while clearing DRV-Presence.\n");
+       }
+
        set_bit(UNLOADING, &base_vha->dpc_flags);
 
        qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
@@ -2772,6 +2795,21 @@ qla2x00_remove_one(struct pci_dev *pdev)
                ha->wq = NULL;
        }
 
+       /* Cancel all work and destroy DPC workqueues */
+       if (ha->dpc_lp_wq) {
+               cancel_work_sync(&ha->idc_aen);
+               destroy_workqueue(ha->dpc_lp_wq);
+               ha->dpc_lp_wq = NULL;
+       }
+
+       if (ha->dpc_hp_wq) {
+               cancel_work_sync(&ha->nic_core_reset);
+               cancel_work_sync(&ha->idc_state_handler);
+               cancel_work_sync(&ha->nic_core_unrecoverable);
+               destroy_workqueue(ha->dpc_hp_wq);
+               ha->dpc_hp_wq = NULL;
+       }
+
        /* Kill the kernel thread for this host */
        if (ha->dpc_thread) {
                struct task_struct *t = ha->dpc_thread;
@@ -2838,7 +2876,6 @@ qla2x00_free_device(scsi_qla_host_t *vha)
        qla2x00_stop_dpc_thread(vha);
 
        qla25xx_delete_queues(vha);
-
        if (ha->flags.fce_enabled)
                qla2x00_disable_fce_trace(vha, NULL, NULL);
 
@@ -3708,6 +3745,637 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
        }
 }
 
+/* Schedule work on any of the dpc-workqueues */
+void
+qla83xx_schedule_work(scsi_qla_host_t *base_vha, int work_code)
+{
+       struct qla_hw_data *ha = base_vha->hw;
+
+       switch (work_code) {
+       case MBA_IDC_AEN: /* 0x8200 */
+               if (ha->dpc_lp_wq)
+                       queue_work(ha->dpc_lp_wq, &ha->idc_aen);
+               break;
+
+       case QLA83XX_NIC_CORE_RESET: /* 0x1 */
+               if (!ha->flags.nic_core_reset_hdlr_active) {
+                       if (ha->dpc_hp_wq)
+                               queue_work(ha->dpc_hp_wq, &ha->nic_core_reset);
+               } else
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb05e,
+                           "NIC Core reset is already active. Skip "
+                           "scheduling it again.\n");
+               break;
+       case QLA83XX_IDC_STATE_HANDLER: /* 0x2 */
+               if (ha->dpc_hp_wq)
+                       queue_work(ha->dpc_hp_wq, &ha->idc_state_handler);
+               break;
+       case QLA83XX_NIC_CORE_UNRECOVERABLE: /* 0x3 */
+               if (ha->dpc_hp_wq)
+                       queue_work(ha->dpc_hp_wq, &ha->nic_core_unrecoverable);
+               break;
+       default:
+               ql_log(ql_log_warn, base_vha, 0xb05f,
+                   "Unknow work-code=0x%x.\n", work_code);
+       }
+
+       return;
+}
+
+/* Work: Perform NIC Core Unrecoverable state handling */
+void
+qla83xx_nic_core_unrecoverable_work(struct work_struct *work)
+{
+       struct qla_hw_data *ha =
+               container_of(work, struct qla_hw_data, nic_core_reset);
+       scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+       uint32_t dev_state = 0;
+
+       qla83xx_idc_lock(base_vha, 0);
+       qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state);
+       qla83xx_reset_ownership(base_vha);
+       if (ha->flags.nic_core_reset_owner) {
+               ha->flags.nic_core_reset_owner = 0;
+               qla83xx_wr_reg(base_vha, QLA83XX_IDC_DEV_STATE,
+                   QLA8XXX_DEV_FAILED);
+               ql_log(ql_log_info, base_vha, 0xb060, "HW State: FAILED.\n");
+               qla83xx_schedule_work(base_vha, QLA83XX_IDC_STATE_HANDLER);
+       }
+       qla83xx_idc_unlock(base_vha, 0);
+}
+
+/* Work: Execute IDC state handler */
+void
+qla83xx_idc_state_handler_work(struct work_struct *work)
+{
+       struct qla_hw_data *ha =
+               container_of(work, struct qla_hw_data, nic_core_reset);
+       scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+       uint32_t dev_state = 0;
+
+       qla83xx_idc_lock(base_vha, 0);
+       qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state);
+       if (dev_state == QLA8XXX_DEV_FAILED ||
+                       dev_state == QLA8XXX_DEV_NEED_QUIESCENT)
+               qla83xx_idc_state_handler(base_vha);
+       qla83xx_idc_unlock(base_vha, 0);
+}
+
+int
+qla83xx_check_nic_core_fw_alive(scsi_qla_host_t *base_vha)
+{
+       int rval = QLA_SUCCESS;
+       unsigned long heart_beat_wait = jiffies + (1 * HZ);
+       uint32_t heart_beat_counter1, heart_beat_counter2;
+
+       do {
+               if (time_after(jiffies, heart_beat_wait)) {
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb07c,
+                           "Nic Core f/w is not alive.\n");
+                       rval = QLA_FUNCTION_FAILED;
+                       break;
+               }
+
+               qla83xx_idc_lock(base_vha, 0);
+               qla83xx_rd_reg(base_vha, QLA83XX_FW_HEARTBEAT,
+                   &heart_beat_counter1);
+               qla83xx_idc_unlock(base_vha, 0);
+               msleep(100);
+               qla83xx_idc_lock(base_vha, 0);
+               qla83xx_rd_reg(base_vha, QLA83XX_FW_HEARTBEAT,
+                   &heart_beat_counter2);
+               qla83xx_idc_unlock(base_vha, 0);
+       } while (heart_beat_counter1 == heart_beat_counter2);
+
+       return rval;
+}
+
+/* Work: Perform NIC Core Reset handling */
+void
+qla83xx_nic_core_reset_work(struct work_struct *work)
+{
+       struct qla_hw_data *ha =
+               container_of(work, struct qla_hw_data, nic_core_reset);
+       scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+       uint32_t dev_state = 0;
+
+       if (!ha->flags.nic_core_reset_hdlr_active) {
+               if (qla83xx_check_nic_core_fw_alive(base_vha) == QLA_SUCCESS) {
+                       qla83xx_idc_lock(base_vha, 0);
+                       qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE,
+                           &dev_state);
+                       qla83xx_idc_unlock(base_vha, 0);
+                       if (dev_state != QLA8XXX_DEV_NEED_RESET) {
+                               ql_dbg(ql_dbg_p3p, base_vha, 0xb07a,
+                                   "Nic Core f/w is alive.\n");
+                               return;
+                       }
+               }
+
+               ha->flags.nic_core_reset_hdlr_active = 1;
+               if (qla83xx_nic_core_reset(base_vha)) {
+                       /* NIC Core reset failed. */
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb061,
+                           "NIC Core reset failed.\n");
+               }
+               ha->flags.nic_core_reset_hdlr_active = 0;
+       }
+}
+
+/* Work: Handle 8200 IDC aens */
+void
+qla83xx_service_idc_aen(struct work_struct *work)
+{
+       struct qla_hw_data *ha =
+               container_of(work, struct qla_hw_data, idc_aen);
+       scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+       uint32_t dev_state, idc_control;
+
+       qla83xx_idc_lock(base_vha, 0);
+       qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state);
+       qla83xx_rd_reg(base_vha, QLA83XX_IDC_CONTROL, &idc_control);
+       qla83xx_idc_unlock(base_vha, 0);
+       if (dev_state == QLA8XXX_DEV_NEED_RESET) {
+               if (idc_control & QLA83XX_IDC_GRACEFUL_RESET) {
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb062,
+                           "Application requested NIC Core Reset.\n");
+                       qla83xx_schedule_work(base_vha, QLA83XX_NIC_CORE_RESET);
+               } else if (qla83xx_check_nic_core_fw_alive(base_vha) ==
+                   QLA_SUCCESS) {
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb07b,
+                           "Other protocol driver requested NIC Core Reset.\n");
+                       qla83xx_schedule_work(base_vha, QLA83XX_NIC_CORE_RESET);
+               }
+       } else if (dev_state == QLA8XXX_DEV_FAILED ||
+                       dev_state == QLA8XXX_DEV_NEED_QUIESCENT) {
+               qla83xx_schedule_work(base_vha, QLA83XX_IDC_STATE_HANDLER);
+       }
+}
+
+static void
+qla83xx_wait_logic(void)
+{
+       int i;
+
+       /* Yield CPU */
+       if (!in_interrupt()) {
+               /*
+                * Wait about 200ms before retrying again.
+                * This controls the number of retries for single
+                * lock operation.
+                */
+               msleep(100);
+               schedule();
+       } else {
+               for (i = 0; i < 20; i++)
+                       cpu_relax(); /* This a nop instr on i386 */
+       }
+}
+
+int
+qla83xx_force_lock_recovery(scsi_qla_host_t *base_vha)
+{
+       int rval;
+       uint32_t data;
+       uint32_t idc_lck_rcvry_stage_mask = 0x3;
+       uint32_t idc_lck_rcvry_owner_mask = 0x3c;
+       struct qla_hw_data *ha = base_vha->hw;
+
+       rval = qla83xx_rd_reg(base_vha, QLA83XX_IDC_LOCK_RECOVERY, &data);
+       if (rval)
+               return rval;
+
+       if ((data & idc_lck_rcvry_stage_mask) > 0) {
+               return QLA_SUCCESS;
+       } else {
+               data = (IDC_LOCK_RECOVERY_STAGE1) | (ha->portnum << 2);
+               rval = qla83xx_wr_reg(base_vha, QLA83XX_IDC_LOCK_RECOVERY,
+                   data);
+               if (rval)
+                       return rval;
+
+               msleep(200);
+
+               rval = qla83xx_rd_reg(base_vha, QLA83XX_IDC_LOCK_RECOVERY,
+                   &data);
+               if (rval)
+                       return rval;
+
+               if (((data & idc_lck_rcvry_owner_mask) >> 2) == ha->portnum) {
+                       data &= (IDC_LOCK_RECOVERY_STAGE2 |
+                                       ~(idc_lck_rcvry_stage_mask));
+                       rval = qla83xx_wr_reg(base_vha,
+                           QLA83XX_IDC_LOCK_RECOVERY, data);
+                       if (rval)
+                               return rval;
+
+                       /* Forcefully perform IDC UnLock */
+                       rval = qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_UNLOCK,
+                           &data);
+                       if (rval)
+                               return rval;
+                       /* Clear lock-id by setting 0xff */
+                       rval = qla83xx_wr_reg(base_vha, QLA83XX_DRIVER_LOCKID,
+                           0xff);
+                       if (rval)
+                               return rval;
+                       /* Clear lock-recovery by setting 0x0 */
+                       rval = qla83xx_wr_reg(base_vha,
+                           QLA83XX_IDC_LOCK_RECOVERY, 0x0);
+                       if (rval)
+                               return rval;
+               } else
+                       return QLA_SUCCESS;
+       }
+
+       return rval;
+}
+
+int
+qla83xx_idc_lock_recovery(scsi_qla_host_t *base_vha)
+{
+       int rval = QLA_SUCCESS;
+       uint32_t o_drv_lockid, n_drv_lockid;
+       unsigned long lock_recovery_timeout;
+
+       lock_recovery_timeout = jiffies + QLA83XX_MAX_LOCK_RECOVERY_WAIT;
+retry_lockid:
+       rval = qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, &o_drv_lockid);
+       if (rval)
+               goto exit;
+
+       /* MAX wait time before forcing IDC Lock recovery = 2 secs */
+       if (time_after_eq(jiffies, lock_recovery_timeout)) {
+               if (qla83xx_force_lock_recovery(base_vha) == QLA_SUCCESS)
+                       return QLA_SUCCESS;
+               else
+                       return QLA_FUNCTION_FAILED;
+       }
+
+       rval = qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, &n_drv_lockid);
+       if (rval)
+               goto exit;
+
+       if (o_drv_lockid == n_drv_lockid) {
+               qla83xx_wait_logic();
+               goto retry_lockid;
+       } else
+               return QLA_SUCCESS;
+
+exit:
+       return rval;
+}
+
+void
+qla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id)
+{
+       uint16_t options = (requester_id << 15) | BIT_6;
+       uint32_t data;
+       struct qla_hw_data *ha = base_vha->hw;
+
+       /* IDC-lock implementation using driver-lock/lock-id remote registers */
+retry_lock:
+       if (qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCK, &data)
+           == QLA_SUCCESS) {
+               if (data) {
+                       /* Setting lock-id to our function-number */
+                       qla83xx_wr_reg(base_vha, QLA83XX_DRIVER_LOCKID,
+                           ha->portnum);
+               } else {
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb063,
+                           "Failed to acquire IDC lock. retrying...\n");
+
+                       /* Retry/Perform IDC-Lock recovery */
+                       if (qla83xx_idc_lock_recovery(base_vha)
+                           == QLA_SUCCESS) {
+                               qla83xx_wait_logic();
+                               goto retry_lock;
+                       } else
+                               ql_log(ql_log_warn, base_vha, 0xb075,
+                                   "IDC Lock recovery FAILED.\n");
+               }
+
+       }
+
+       return;
+
+       /* XXX: IDC-lock implementation using access-control mbx */
+retry_lock2:
+       if (qla83xx_access_control(base_vha, options, 0, 0, NULL)) {
+               ql_dbg(ql_dbg_p3p, base_vha, 0xb072,
+                   "Failed to acquire IDC lock. retrying...\n");
+               /* Retry/Perform IDC-Lock recovery */
+               if (qla83xx_idc_lock_recovery(base_vha) == QLA_SUCCESS) {
+                       qla83xx_wait_logic();
+                       goto retry_lock2;
+               } else
+                       ql_log(ql_log_warn, base_vha, 0xb076,
+                           "IDC Lock recovery FAILED.\n");
+       }
+
+       return;
+}
+
+void
+qla83xx_idc_unlock(scsi_qla_host_t *base_vha, uint16_t requester_id)
+{
+       uint16_t options = (requester_id << 15) | BIT_7, retry;
+       uint32_t data;
+       struct qla_hw_data *ha = base_vha->hw;
+
+       /* IDC-unlock implementation using driver-unlock/lock-id
+        * remote registers
+        */
+       retry = 0;
+retry_unlock:
+       if (qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, &data)
+           == QLA_SUCCESS) {
+               if (data == ha->portnum) {
+                       qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_UNLOCK, &data);
+                       /* Clearing lock-id by setting 0xff */
+                       qla83xx_wr_reg(base_vha, QLA83XX_DRIVER_LOCKID, 0xff);
+               } else if (retry < 10) {
+                       /* SV: XXX: IDC unlock retrying needed here? */
+
+                       /* Retry for IDC-unlock */
+                       qla83xx_wait_logic();
+                       retry++;
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb064,
+                           "Failed to release IDC lock, retyring=%d\n", retry);
+                       goto retry_unlock;
+               }
+       } else if (retry < 10) {
+               /* Retry for IDC-unlock */
+               qla83xx_wait_logic();
+               retry++;
+               ql_dbg(ql_dbg_p3p, base_vha, 0xb065,
+                   "Failed to read drv-lockid, retyring=%d\n", retry);
+               goto retry_unlock;
+       }
+
+       return;
+
+       /* XXX: IDC-unlock implementation using access-control mbx */
+       retry = 0;
+retry_unlock2:
+       if (qla83xx_access_control(base_vha, options, 0, 0, NULL)) {
+               if (retry < 10) {
+                       /* Retry for IDC-unlock */
+                       qla83xx_wait_logic();
+                       retry++;
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb066,
+                           "Failed to release IDC lock, retyring=%d\n", retry);
+                       goto retry_unlock2;
+               }
+       }
+
+       return;
+}
+
+int
+__qla83xx_set_drv_presence(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t drv_presence;
+
+       rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
+       if (rval == QLA_SUCCESS) {
+               drv_presence |= (1 << ha->portnum);
+               rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRV_PRESENCE,
+                   drv_presence);
+       }
+
+       return rval;
+}
+
+int
+qla83xx_set_drv_presence(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+
+       qla83xx_idc_lock(vha, 0);
+       rval = __qla83xx_set_drv_presence(vha);
+       qla83xx_idc_unlock(vha, 0);
+
+       return rval;
+}
+
+int
+__qla83xx_clear_drv_presence(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t drv_presence;
+
+       rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
+       if (rval == QLA_SUCCESS) {
+               drv_presence &= ~(1 << ha->portnum);
+               rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRV_PRESENCE,
+                   drv_presence);
+       }
+
+       return rval;
+}
+
+int
+qla83xx_clear_drv_presence(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+
+       qla83xx_idc_lock(vha, 0);
+       rval = __qla83xx_clear_drv_presence(vha);
+       qla83xx_idc_unlock(vha, 0);
+
+       return rval;
+}
+
+void
+qla83xx_need_reset_handler(scsi_qla_host_t *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t drv_ack, drv_presence;
+       unsigned long ack_timeout;
+
+       /* Wait for IDC ACK from all functions (DRV-ACK == DRV-PRESENCE) */
+       ack_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
+       while (1) {
+               qla83xx_rd_reg(vha, QLA83XX_IDC_DRIVER_ACK, &drv_ack);
+               qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
+               if (drv_ack == drv_presence)
+                       break;
+
+               if (time_after_eq(jiffies, ack_timeout)) {
+                       ql_log(ql_log_warn, vha, 0xb067,
+                           "RESET ACK TIMEOUT! drv_presence=0x%x "
+                           "drv_ack=0x%x\n", drv_presence, drv_ack);
+                       /*
+                        * The function(s) which did not ack in time are forced
+                        * to withdraw any further participation in the IDC
+                        * reset.
+                        */
+                       if (drv_ack != drv_presence)
+                               qla83xx_wr_reg(vha, QLA83XX_IDC_DRV_PRESENCE,
+                                   drv_ack);
+                       break;
+               }
+
+               qla83xx_idc_unlock(vha, 0);
+               msleep(1000);
+               qla83xx_idc_lock(vha, 0);
+       }
+
+       qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_COLD);
+       ql_log(ql_log_info, vha, 0xb068, "HW State: COLD/RE-INIT.\n");
+}
+
+int
+qla83xx_device_bootstrap(scsi_qla_host_t *vha)
+{
+       int rval = QLA_SUCCESS;
+       uint32_t idc_control;
+
+       qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_INITIALIZING);
+       ql_log(ql_log_info, vha, 0xb069, "HW State: INITIALIZING.\n");
+
+       /* Clearing IDC-Control Graceful-Reset Bit before resetting f/w */
+       __qla83xx_get_idc_control(vha, &idc_control);
+       idc_control &= ~QLA83XX_IDC_GRACEFUL_RESET;
+       __qla83xx_set_idc_control(vha, 0);
+
+       qla83xx_idc_unlock(vha, 0);
+       rval = qla83xx_restart_nic_firmware(vha);
+       qla83xx_idc_lock(vha, 0);
+
+       if (rval != QLA_SUCCESS) {
+               ql_log(ql_log_fatal, vha, 0xb06a,
+                   "Failed to restart NIC f/w.\n");
+               qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_FAILED);
+               ql_log(ql_log_info, vha, 0xb06b, "HW State: FAILED.\n");
+       } else {
+               ql_dbg(ql_dbg_p3p, vha, 0xb06c,
+                   "Success in restarting nic f/w.\n");
+               qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_READY);
+               ql_log(ql_log_info, vha, 0xb06d, "HW State: READY.\n");
+       }
+
+       return rval;
+}
+
+/* Assumes idc_lock always held on entry */
+int
+qla83xx_idc_state_handler(scsi_qla_host_t *base_vha)
+{
+       struct qla_hw_data *ha = base_vha->hw;
+       int rval = QLA_SUCCESS;
+       unsigned long dev_init_timeout;
+       uint32_t dev_state;
+
+       /* Wait for MAX-INIT-TIMEOUT for the device to go ready */
+       dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ);
+
+       while (1) {
+
+               if (time_after_eq(jiffies, dev_init_timeout)) {
+                       ql_log(ql_log_warn, base_vha, 0xb06e,
+                           "Initialization TIMEOUT!\n");
+                       /* Init timeout. Disable further NIC Core
+                        * communication.
+                        */
+                       qla83xx_wr_reg(base_vha, QLA83XX_IDC_DEV_STATE,
+                               QLA8XXX_DEV_FAILED);
+                       ql_log(ql_log_info, base_vha, 0xb06f,
+                           "HW State: FAILED.\n");
+               }
+
+               qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state);
+               switch (dev_state) {
+               case QLA8XXX_DEV_READY:
+                       if (ha->flags.nic_core_reset_owner)
+                               qla83xx_idc_audit(base_vha,
+                                   IDC_AUDIT_COMPLETION);
+                       ha->flags.nic_core_reset_owner = 0;
+                       ql_dbg(ql_dbg_p3p, base_vha, 0xb070,
+                           "Reset_owner reset by 0x%x.\n",
+                           ha->portnum);
+                       goto exit;
+               case QLA8XXX_DEV_COLD:
+                       if (ha->flags.nic_core_reset_owner)
+                               rval = qla83xx_device_bootstrap(base_vha);
+                       else {
+                       /* Wait for AEN to change device-state */
+                               qla83xx_idc_unlock(base_vha, 0);
+                               msleep(1000);
+                               qla83xx_idc_lock(base_vha, 0);
+                       }
+                       break;
+               case QLA8XXX_DEV_INITIALIZING:
+                       /* Wait for AEN to change device-state */
+                       qla83xx_idc_unlock(base_vha, 0);
+                       msleep(1000);
+                       qla83xx_idc_lock(base_vha, 0);
+                       break;
+               case QLA8XXX_DEV_NEED_RESET:
+                       if (!ql2xdontresethba && ha->flags.nic_core_reset_owner)
+                               qla83xx_need_reset_handler(base_vha);
+                       else {
+                               /* Wait for AEN to change device-state */
+                               qla83xx_idc_unlock(base_vha, 0);
+                               msleep(1000);
+                               qla83xx_idc_lock(base_vha, 0);
+                       }
+                       /* reset timeout value after need reset handler */
+                       dev_init_timeout = jiffies +
+                           (ha->fcoe_dev_init_timeout * HZ);
+                       break;
+               case QLA8XXX_DEV_NEED_QUIESCENT:
+                       /* XXX: DEBUG for now */
+                       qla83xx_idc_unlock(base_vha, 0);
+                       msleep(1000);
+                       qla83xx_idc_lock(base_vha, 0);
+                       break;
+               case QLA8XXX_DEV_QUIESCENT:
+                       /* XXX: DEBUG for now */
+                       if (ha->flags.quiesce_owner)
+                               goto exit;
+
+                       qla83xx_idc_unlock(base_vha, 0);
+                       msleep(1000);
+                       qla83xx_idc_lock(base_vha, 0);
+                       dev_init_timeout = jiffies +
+                           (ha->fcoe_dev_init_timeout * HZ);
+                       break;
+               case QLA8XXX_DEV_FAILED:
+                       if (ha->flags.nic_core_reset_owner)
+                               qla83xx_idc_audit(base_vha,
+                                   IDC_AUDIT_COMPLETION);
+                       ha->flags.nic_core_reset_owner = 0;
+                       __qla83xx_clear_drv_presence(base_vha);
+                       qla83xx_idc_unlock(base_vha, 0);
+                       qla8xxx_dev_failed_handler(base_vha);
+                       rval = QLA_FUNCTION_FAILED;
+                       qla83xx_idc_lock(base_vha, 0);
+                       goto exit;
+               case QLA8XXX_BAD_VALUE:
+                       qla83xx_idc_unlock(base_vha, 0);
+                       msleep(1000);
+                       qla83xx_idc_lock(base_vha, 0);
+                       break;
+               default:
+                       ql_log(ql_log_warn, base_vha, 0xb071,
+                           "Unknow Device State: %x.\n", dev_state);
+                       qla83xx_idc_unlock(base_vha, 0);
+                       qla8xxx_dev_failed_handler(base_vha);
+                       rval = QLA_FUNCTION_FAILED;
+                       qla83xx_idc_lock(base_vha, 0);
+                       goto exit;
+               }
+       }
+
+exit:
+       return rval;
+}
+
 /**************************************************************************
 * qla2x00_do_dpc
 *   This kernel thread is a task that is schedule by the interrupt handler
@@ -3763,7 +4431,7 @@ qla2x00_do_dpc(void *data)
                                &base_vha->dpc_flags)) {
                                qla82xx_idc_lock(ha);
                                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                                       QLA82XX_DEV_FAILED);
+                                       QLA8XXX_DEV_FAILED);
                                qla82xx_idc_unlock(ha);
                                ql_log(ql_log_info, base_vha, 0x4004,
                                    "HW State: FAILED.\n");
@@ -4340,7 +5008,7 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                qla82xx_idc_lock(ha);
 
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                   QLA82XX_DEV_INITIALIZING);
+                   QLA8XXX_DEV_INITIALIZING);
 
                qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION,
                    QLA82XX_IDC_VERSION);
@@ -4364,12 +5032,12 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                            "HW State: FAILED.\n");
                        qla82xx_clear_drv_active(ha);
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                           QLA82XX_DEV_FAILED);
+                           QLA8XXX_DEV_FAILED);
                } else {
                        ql_log(ql_log_info, base_vha, 0x900c,
                            "HW State: READY.\n");
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                           QLA82XX_DEV_READY);
+                           QLA8XXX_DEV_READY);
                        qla82xx_idc_unlock(ha);
                        ha->flags.isp82xx_fw_hung = 0;
                        rval = qla82xx_restart_isp(base_vha);
@@ -4384,7 +5052,7 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                    "This devfn is not reset owner = 0x%x.\n",
                    ha->pdev->devfn);
                if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
-                   QLA82XX_DEV_READY)) {
+                   QLA8XXX_DEV_READY)) {
                        ha->flags.isp82xx_fw_hung = 0;
                        rval = qla82xx_restart_isp(base_vha);
                        qla82xx_idc_lock(ha);
index a683e766d1aea088115eb3bde698ebf8390c5a1d..e66fa7fbd933dd6f2f3fd8421d51123a74a83185 100644 (file)
@@ -966,16 +966,16 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha)
                QLA82XX_IDC_PARAM_ADDR , 8);
 
        if (*wptr == __constant_cpu_to_le32(0xffffffff)) {
-               ha->nx_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT;
-               ha->nx_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT;
+               ha->fcoe_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT;
+               ha->fcoe_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT;
        } else {
-               ha->nx_dev_init_timeout = le32_to_cpu(*wptr++);
-               ha->nx_reset_timeout = le32_to_cpu(*wptr);
+               ha->fcoe_dev_init_timeout = le32_to_cpu(*wptr++);
+               ha->fcoe_reset_timeout = le32_to_cpu(*wptr);
        }
        ql_dbg(ql_dbg_init, vha, 0x004e,
-           "nx_dev_init_timeout=%d "
-           "nx_reset_timeout=%d.\n", ha->nx_dev_init_timeout,
-           ha->nx_reset_timeout);
+           "fcoe_dev_init_timeout=%d "
+           "fcoe_reset_timeout=%d.\n", ha->fcoe_dev_init_timeout,
+           ha->fcoe_reset_timeout);
        return;
 }
 
@@ -1017,7 +1017,7 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
            !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
                return;
 
-       if (ha->flags.isp82xx_reset_hdlr_active)
+       if (ha->flags.nic_core_reset_hdlr_active)
                return;
 
        ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr,
@@ -1675,15 +1675,15 @@ qla83xx_beacon_blink(struct scsi_qla_host *vha)
 
        if (IS_QLA2031(ha) && ha->beacon_blink_led) {
                if (ha->flags.port0)
-                       led_select_value = 0x00201320;
+                       led_select_value = QLA83XX_LED_PORT0;
                else
-                       led_select_value = 0x00201328;
+                       led_select_value = QLA83XX_LED_PORT1;
 
-               qla83xx_write_remote_reg(vha, led_select_value, 0x40002000);
-               qla83xx_write_remote_reg(vha, led_select_value + 4, 0x40002000);
+               qla83xx_wr_reg(vha, led_select_value, 0x40002000);
+               qla83xx_wr_reg(vha, led_select_value + 4, 0x40002000);
                msleep(1000);
-               qla83xx_write_remote_reg(vha, led_select_value, 0x40004000);
-               qla83xx_write_remote_reg(vha, led_select_value + 4, 0x40004000);
+               qla83xx_wr_reg(vha, led_select_value, 0x40004000);
+               qla83xx_wr_reg(vha, led_select_value + 4, 0x40004000);
        } else if ((IS_QLA8031(ha) || IS_QLA81XX(ha)) && ha->beacon_blink_led) {
                int rval;