+++ /dev/null
-From: Jamie Wellnitz <jamie.wellnitz@emulex.com>
-Subject: Update lpfc to 8.2.8.7
-References: bnc#420767
-
-This patch updates the SLES 11 inbox lpfc driver 8.2.8.7, which fixes several
-issues we've found in testing on SLES 11 Beta.
-
-* Changed version number to 8.2.8.7
-* Fixed system lockup problem when HBA is in MSI-X mode (CR 85802, 85441)
-* Fixed slow vport deletes
-* Fixed locking issue when lpfc_ioctl_send_mgmt_cmd fails to allocate buffer
-* Changed mdelay to msleep in the ioctl path (CR 85606)
-* Fixed a discovery issue (CR 85714)
-* Extended Error Handling (EEH) support on IBM PowerPC P6 platform (CR 85671)
-* Fix allocation of HBQs should not be done in interrupt context (CR 84717)
-* Fixed loopback tests not working if auth enabled but auth service not
- available (CR 85334)
-* Changed version number to 8.2.8.6
-* Fix memory leaks in netlink send code
-* Fixed fail-to-enable INTx when auth is enabled but auth service is not
- running (CR 85162)
-* Fix build warning of uninitialized variable in lpfc_enable_intr
-* Fix crash when running latency test (CR 85257)
-* Fixed missing CNA attribute for sysfs (CR 85265)
-* Fixed false overrun failure for menlo commands that are less than the command
- header size (CR 85168)
-* Fixed mbuf leak when lpfc_pci_probe_one hit an error exit in SLI-2 mode
-* Fix memory leak with dump mailbox completion
-* Fix bpl size to reflect the correct buffer's size
-* Fixed lpfc install problem for SLES 11 Beta2 (CR 84623)
-* Fix driver online notification to come after port is added to auth list
-* Added active interrupt test and automatic fallback for enabling
- MSI/MSI-X/INTx (CR 84266)
-* Fixed NULL pointer dereference in lpfc_prep_els_iocb (CR 84470)
-* Fixed time out handling in the worker thread (CR 84540)
-* Changed version number to 8.2.8.5
-* Small cleanup to match upstream 8.2.8 changes
-* Fix bug with Interrupt Enable Block support (CR 84106)
-* Applied pci_max_read fix from 8.2.0.x driver series (CR 84414)
-* Added support for hps bit (CR 84425 84428)
-
-Signed-off-by: Jamie Wellnitz <jamie.wellnitz@emulex.com>
-Signed-off-by: Hannes Reinecke <hare@suse.de>
-
-diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
-index 7508dea..7bb7971 100644
---- a/drivers/scsi/lpfc/lpfc.h
-+++ b/drivers/scsi/lpfc/lpfc.h
-@@ -73,6 +73,9 @@ struct lpfc_sli2_slim;
- /* Number of MSI-X vectors the driver uses */
- #define LPFC_MSIX_VECTORS 2
-
-+/* Active interrupt test threshold */
-+#define LPFC_INTR_THRESHOLD 1
-+
- /* lpfc wait event data ready flag */
- #define LPFC_DATA_READY (1<<0)
-
-@@ -629,6 +632,7 @@ struct lpfc_hba {
- uint32_t cfg_hba_queue_depth;
- uint32_t cfg_enable_hba_reset;
- uint32_t cfg_enable_hba_heartbeat;
-+ uint32_t cfg_pci_max_read;
-
- lpfc_vpd_t vpd; /* vital product data */
-
-@@ -718,6 +722,8 @@ struct lpfc_hba {
-
- struct fc_host_statistics link_stats;
- enum intr_type_t intr_type;
-+ uint32_t intr_mode;
-+#define LPFC_INTR_ERROR 0xFFFFFFFF
- struct msix_entry msix_entries[LPFC_MSIX_VECTORS];
- struct lpfcdfc_host *dfc_host;
-
-diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
-index 1069491..2140408 100644
---- a/drivers/scsi/lpfc/lpfc_attr.c
-+++ b/drivers/scsi/lpfc/lpfc_attr.c
-@@ -42,6 +42,7 @@
- #include "lpfc_crtn.h"
- #include "lpfc_vport.h"
- #include "lpfc_auth_access.h"
-+#include "lpfc_security.h"
-
- #define LPFC_DEF_DEVLOSS_TMO 30
- #define LPFC_MIN_DEVLOSS_TMO 1
-@@ -3100,6 +3101,27 @@ LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
- */
- LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT,
- LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count");
-+/*
-+ * lpfc_pci_max_read: Maximum DMA read byte count. This parameter can have
-+ * values 512, 1024, 2048, 4096. Default value is 2048.
-+ */
-+static int lpfc_pci_max_read = 2048;
-+module_param(lpfc_pci_max_read, int, 0);
-+MODULE_PARM_DESC(lpfc_pci_max_read,
-+ "Maximum DMA read byte count. Allowed values:"
-+ " 512,1024,2048,4096.");
-+static int
-+lpfc_pci_max_read_init(struct lpfc_hba *phba, int val)
-+{
-+ phba->cfg_pci_max_read = 2048;
-+ if ((val == 512) || (val == 1024) || (val == 2048) || (val == 4096))
-+ phba->cfg_pci_max_read = val;
-+ return 0;
-+}
-+
-+lpfc_param_show(pci_max_read)
-+static DEVICE_ATTR(lpfc_pci_max_read, S_IRUGO,
-+ lpfc_pci_max_read_show, NULL);
-
- struct device_attribute *lpfc_hba_attrs[] = {
- &dev_attr_info,
-@@ -3136,6 +3158,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
- &dev_attr_lpfc_fdmi_on,
- &dev_attr_lpfc_max_luns,
- &dev_attr_lpfc_enable_npiv,
-+ &dev_attr_lpfc_pci_max_read,
- &dev_attr_nport_evt_cnt,
- &dev_attr_board_mode,
- &dev_attr_max_vpi,
-@@ -4176,12 +4199,22 @@ lpfc_alloc_sysfs_attr(struct lpfc_vport *vport)
- if (error)
- goto out_remove_ctlreg_attr;
-
-+ error = sysfs_create_bin_file(&shost->shost_dev.kobj,
-+ &sysfs_menlo_attr);
-+ if (error)
-+ goto out_remove_menlo_attr;
-+
-+
- return 0;
- out_remove_ctlreg_attr:
- sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr);
- out_remove_stat_attr:
- sysfs_remove_bin_file(&shost->shost_dev.kobj,
- &sysfs_drvr_stat_data_attr);
-+out_remove_menlo_attr:
-+ sysfs_remove_bin_file(&shost->shost_dev.kobj,
-+ &sysfs_menlo_attr);
-+
- out:
- return error;
- }
-@@ -4269,6 +4302,13 @@ lpfc_get_host_port_state(struct Scsi_Host *shost)
- if (vport->fc_flag & FC_OFFLINE_MODE)
- fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
- else {
-+ if ((vport->cfg_enable_auth) &&
-+ (lpfc_security_service_state == SECURITY_OFFLINE)) {
-+ fc_host_port_state(shost) = FC_PORTSTATE_ERROR;
-+ spin_unlock_irq(shost->host_lock);
-+ return;
-+ }
-+
- switch (phba->link_state) {
- case LPFC_LINK_UNKNOWN:
- case LPFC_LINK_DOWN:
-@@ -4837,6 +4877,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
- lpfc_link_speed_init(phba, lpfc_link_speed);
- lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
- lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
-+ lpfc_pci_max_read_init(phba, lpfc_pci_max_read);
- lpfc_use_msi_init(phba, lpfc_use_msi);
- lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
- lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
-diff --git a/drivers/scsi/lpfc/lpfc_auth_access.c b/drivers/scsi/lpfc/lpfc_auth_access.c
-index 7481eb0..9f48c59 100644
---- a/drivers/scsi/lpfc/lpfc_auth_access.c
-+++ b/drivers/scsi/lpfc/lpfc_auth_access.c
-@@ -1,7 +1,7 @@
- /*******************************************************************
- * This file is part of the Emulex Linux Device Driver for *
- * Fibre Channel Host Bus Adapters. *
-- * Copyright (C) 2006-2007 Emulex. All rights reserved. *
-+ * Copyright (C) 2006-2008 Emulex. All rights reserved. *
- * EMULEX and SLI are trademarks of Emulex. *
- * www.emulex.com *
- * *
-@@ -213,10 +213,11 @@ lpfc_fc_sc_request(struct lpfc_vport *vport,
- fc_sc_req->tran_id = seq;
-
- len = sizeof(struct fc_nl_sc_message) + auth_req_len;
-- fc_nl_sc_msg = kzalloc(sizeof(struct fc_nl_sc_message) + auth_req_len,
-- GFP_KERNEL);
-- if (!fc_nl_sc_msg)
-+ fc_nl_sc_msg = kzalloc(len, GFP_KERNEL);
-+ if (!fc_nl_sc_msg) {
-+ kfree(fc_sc_req);
- return -ENOMEM;
-+ }
- fc_nl_sc_msg->msgtype = msg_type;
- fc_nl_sc_msg->data_len = auth_req_len;
- memcpy(fc_nl_sc_msg->data, auth_req, auth_req_len);
-@@ -228,6 +229,7 @@ lpfc_fc_sc_request(struct lpfc_vport *vport,
- scsi_nl_send_vendor_msg(fc_service_pid, shost->host_no,
- (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX),
- (char *) fc_nl_sc_msg, len);
-+ kfree(fc_nl_sc_msg);
- lpfc_fc_sc_add_timer(fc_sc_req, FC_SC_REQ_TIMEOUT,
- lpfc_fc_sc_req_times_out);
- return 0;
-diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
-index 380acef..cedbfea 100644
---- a/drivers/scsi/lpfc/lpfc_crtn.h
-+++ b/drivers/scsi/lpfc/lpfc_crtn.h
-@@ -43,6 +43,7 @@ void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
- void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
- int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
- LPFC_MBOXQ_t *, uint32_t);
-+void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
- void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
- void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
- void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
-@@ -166,6 +167,8 @@ void lpfc_offline(struct lpfc_hba *);
-
- int lpfc_sli_setup(struct lpfc_hba *);
- int lpfc_sli_queue_setup(struct lpfc_hba *);
-+int lpfc_sli_set_dma_length(struct lpfc_hba *, uint32_t);
-+
-
- void lpfc_handle_eratt(struct lpfc_hba *);
- void lpfc_handle_latt(struct lpfc_hba *);
-diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
-index 7fecdbb..896c7b0 100644
---- a/drivers/scsi/lpfc/lpfc_ct.c
-+++ b/drivers/scsi/lpfc/lpfc_ct.c
-@@ -560,18 +560,25 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
-
- /* Don't bother processing response if vport is being torn down. */
-- if (vport->load_flag & FC_UNLOADING)
-+ if (vport->load_flag & FC_UNLOADING) {
-+ if (vport->fc_flag & FC_RSCN_MODE)
-+ lpfc_els_flush_rscn(vport);
- goto out;
-+ }
-
- if (lpfc_els_chk_latt(vport)) {
- lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "0216 Link event during NS query\n");
-+ if (vport->fc_flag & FC_RSCN_MODE)
-+ lpfc_els_flush_rscn(vport);
- lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- goto out;
- }
- if (lpfc_error_lost_link(irsp)) {
- lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "0226 NS query failed due to link event\n");
-+ if (vport->fc_flag & FC_RSCN_MODE)
-+ lpfc_els_flush_rscn(vport);
- goto out;
- }
- if (irsp->ulpStatus) {
-@@ -587,6 +594,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- if (rc == 0)
- goto out;
- }
-+ if (vport->fc_flag & FC_RSCN_MODE)
-+ lpfc_els_flush_rscn(vport);
- lpfc_vport_set_state(vport, FC_VPORT_FAILED);
- lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0257 GID_FT Query error: 0x%x 0x%x\n",
-diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
-index 3f58a4b..69f92e8 100644
---- a/drivers/scsi/lpfc/lpfc_els.c
-+++ b/drivers/scsi/lpfc/lpfc_els.c
-@@ -278,7 +278,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
- return elsiocb;
-
- els_iocb_free_pbuf_exit:
-- lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
-+ if (expectRsp)
-+ lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
- kfree(pbuflist);
-
- els_iocb_free_prsp_exit:
-@@ -943,6 +944,10 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
- struct lpfc_hba *phba = vport->phba;
- struct lpfc_nodelist *ndlp;
-
-+ if ((vport->cfg_enable_auth) &&
-+ (lpfc_security_service_state == SECURITY_OFFLINE))
-+ return 1;
-+
- vport->port_state = LPFC_FLOGI;
- lpfc_set_disctmo(vport);
-
-@@ -4985,10 +4990,6 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
- uint32_t timeout;
- uint32_t remote_ID = 0xffffffff;
-
-- /* If the timer is already canceled do nothing */
-- if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
-- return;
-- }
- spin_lock_irq(&phba->hbalock);
- timeout = (uint32_t)(phba->fc_ratov << 1);
-
-diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
-index 358e9de..f02c2bb 100644
---- a/drivers/scsi/lpfc/lpfc_hbadisc.c
-+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
-@@ -39,6 +39,7 @@
- #include "lpfc_crtn.h"
- #include "lpfc_vport.h"
- #include "lpfc_debugfs.h"
-+#include "lpfc_security.h"
-
- /* AlpaArray for assignment of scsid for scan-down and bind_method */
- static uint8_t lpfcAlpaArray[] = {
-@@ -1008,9 +1009,12 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- /* Start discovery by sending a FLOGI. port_state is identically
- * LPFC_FLOGI while waiting for FLOGI cmpl
- */
-- if (vport->port_state != LPFC_FLOGI) {
-+ if ((vport->cfg_enable_auth) &&
-+ (lpfc_security_service_state == SECURITY_OFFLINE))
-+ lpfc_issue_clear_la(phba, vport);
-+ else if (vport->port_state != LPFC_FLOGI)
- lpfc_initial_flogi(vport);
-- }
-+
- return;
-
- out:
-diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
-index c77d49e..f9a42f6 100644
---- a/drivers/scsi/lpfc/lpfc_hw.h
-+++ b/drivers/scsi/lpfc/lpfc_hw.h
-@@ -2370,6 +2370,14 @@ typedef struct {
- uint32_t rsvd1;
- } CLEAR_LA_VAR;
-
-+/* Structure for MB Command SET_SLIM (33) */
-+/* Values needed to set MAX_DMA_LENGTH parameter */
-+#define SLIM_VAR_MAX_DMA_LENGTH 0x100506
-+#define SLIM_VAL_MAX_DMA_512 0x0
-+#define SLIM_VAL_MAX_DMA_1024 0x1
-+#define SLIM_VAL_MAX_DMA_2048 0x2
-+#define SLIM_VAL_MAX_DMA_4096 0x3
-+
- /* Structure for MB Command DUMP */
-
- typedef struct {
-@@ -2621,10 +2629,17 @@ typedef struct {
-
- uint32_t pcbLow; /* bit 31:0 of memory based port config block */
- uint32_t pcbHigh; /* bit 63:32 of memory based port config block */
-- uint32_t hbainit[6];
-+ uint32_t hbainit[5];
-+#ifdef __BIG_ENDIAN_BITFIELD
-+ uint32_t hps : 1; /* bit 31 word9 Host Pointer in slim */
-+ uint32_t rsvd : 31; /* least significant 31 bits of word 9 */
-+#else /* __LITTLE_ENDIAN */
-+ uint32_t rsvd : 31; /* least significant 31 bits of word 9 */
-+ uint32_t hps : 1; /* bit 31 word9 Host Pointer in slim */
-+#endif
-
- #ifdef __BIG_ENDIAN_BITFIELD
-- uint32_t rsvd : 24; /* Reserved */
-+ uint32_t rsvd1 : 24; /* Reserved */
- uint32_t cmv : 1; /* Configure Max VPIs */
- uint32_t ccrp : 1; /* Config Command Ring Polling */
- uint32_t csah : 1; /* Configure Synchronous Abort Handling */
-@@ -2642,7 +2657,7 @@ typedef struct {
- uint32_t csah : 1; /* Configure Synchronous Abort Handling */
- uint32_t ccrp : 1; /* Config Command Ring Polling */
- uint32_t cmv : 1; /* Configure Max VPIs */
-- uint32_t rsvd : 24; /* Reserved */
-+ uint32_t rsvd1 : 24; /* Reserved */
- #endif
- #ifdef __BIG_ENDIAN_BITFIELD
- uint32_t rsvd2 : 24; /* Reserved */
-diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
-index c151651..4032bda 100644
---- a/drivers/scsi/lpfc/lpfc_init.c
-+++ b/drivers/scsi/lpfc/lpfc_init.c
-@@ -290,8 +290,10 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
- /* character array used for decoding dist type. */
- char dist_char[] = "nabx";
-
-- if (pmboxq->mb.mbxStatus != MBX_SUCCESS)
-+ if (pmboxq->mb.mbxStatus != MBX_SUCCESS) {
-+ mempool_free(pmboxq, phba->mbox_mem_pool);
- return;
-+ }
-
- prg = (struct prog_id *) &prog_id_word;
-
-@@ -309,6 +311,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
- sprintf(phba->OptionROMVersion, "%d.%d%d%c%d",
- prg->ver, prg->rev, prg->lev,
- dist, prg->num);
-+ mempool_free(pmboxq, phba->mbox_mem_pool);
- return;
- }
-
-@@ -521,22 +524,46 @@ lpfc_config_port_post(struct lpfc_hba *phba)
- /* Set up error attention (ERATT) polling timer */
- mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL);
-
-+ /* Use the existing MBOX buffer, it will be freed in mbox compl */
-+ lpfc_config_async(phba, pmb, LPFC_ELS_RING);
-+ pmb->mbox_cmpl = lpfc_config_async_cmpl;
-+ pmb->vport = phba->pport;
-+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
-+ if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
-+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+ "0456 Adapter failed to issue "
-+ "ASYNCEVT_ENABLE mbox status x%x \n.", rc);
-+ mempool_free(pmb, phba->mbox_mem_pool);
-+ }
-+
-+ /* Allocate new MBOX buffer, it will be freed in mbox compl */
-+ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-+ lpfc_dump_wakeup_param(phba, pmb);
-+ pmb->mbox_cmpl = lpfc_dump_wakeup_param_cmpl;
-+ pmb->vport = phba->pport;
-+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
-+ if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
-+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+ "0435 Adapter failed to get Option "
-+ "ROM version status x%x\n.", rc);
-+ mempool_free(pmb, phba->mbox_mem_pool);
-+ }
-+
- if (vport->cfg_enable_auth) {
- if (lpfc_security_service_state == SECURITY_OFFLINE) {
- lpfc_printf_log(vport->phba, KERN_ERR, LOG_SECURITY,
- "1000 Authentication is enabled but "
- "authentication service is not running\n");
- vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN;
-- phba->link_state = LPFC_HBA_ERROR;
-- mempool_free(pmb, phba->mbox_mem_pool);
-- return 0;
- }
- }
-
-+ /* Allocate new MBOX buffer, will be freed in mbox compl */
-+ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
- pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
-- if (rc != MBX_SUCCESS) {
-+ if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0454 Adapter failed to init, mbxCmd x%x "
- "INIT_LINK, mbxStatus x%x\n",
-@@ -550,40 +577,9 @@ lpfc_config_port_post(struct lpfc_hba *phba)
- readl(phba->HAregaddr); /* flush */
-
- phba->link_state = LPFC_HBA_ERROR;
-- if (rc != MBX_BUSY)
-- mempool_free(pmb, phba->mbox_mem_pool);
-- return -EIO;
-- }
-- /* MBOX buffer will be freed in mbox compl */
-- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-- lpfc_config_async(phba, pmb, LPFC_ELS_RING);
-- pmb->mbox_cmpl = lpfc_config_async_cmpl;
-- pmb->vport = phba->pport;
-- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
--
-- if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
-- lpfc_printf_log(phba,
-- KERN_ERR,
-- LOG_INIT,
-- "0456 Adapter failed to issue "
-- "ASYNCEVT_ENABLE mbox status x%x \n.",
-- rc);
-- mempool_free(pmb, phba->mbox_mem_pool);
-- }
--
-- /* Get Option rom version */
-- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-- lpfc_dump_wakeup_param(phba, pmb);
-- pmb->mbox_cmpl = lpfc_dump_wakeup_param_cmpl;
-- pmb->vport = phba->pport;
-- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
--
-- if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
-- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed "
-- "to get Option ROM version status x%x\n.", rc);
- mempool_free(pmb, phba->mbox_mem_pool);
-+ return -EIO;
- }
--
- return 0;
- }
-
-@@ -788,11 +784,6 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
- return;
-
- spin_lock_irq(&phba->pport->work_port_lock);
-- /* If the timer is already canceled do nothing */
-- if (!(phba->pport->work_port_events & WORKER_HB_TMO)) {
-- spin_unlock_irq(&phba->pport->work_port_lock);
-- return;
-- }
-
- if (time_after(phba->last_completion_time + LPFC_HB_MBOX_INTERVAL * HZ,
- jiffies)) {
-@@ -2307,6 +2298,51 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
- }
-
- /**
-+ * lpfc_setup_max_dma_length: Check the host's chipset and adjust HBA's
-+ * max DMA length.
-+ * @phba: pointer to lpfc hba data structure.
-+ *
-+ * This routine is invoked to test the machines chipsets. Some of Emulex's
-+ * HBA models expose bugs in these chipsets. To work around these bugs we
-+ * tell the HBA to use a smaller maxium DMA length.
-+ * This routine is only called during module init. The DMA length is passed
-+ * to the driver as a module parameter(lpfc_pci_max_read).
-+ *
-+ * return: NONE.
-+ **/
-+void
-+lpfc_setup_max_dma_length(struct lpfc_hba *phba)
-+{
-+ struct pci_dev *pdev = phba->pcidev;
-+ struct pci_bus *bus = pdev->bus;
-+ uint8_t rev;
-+
-+ while (bus) {
-+ /*
-+ * 0x7450 == PCI_DEVICE_ID_AMD_8131_BRIDGE for 2.6 kernels
-+ * 0x7450 == PCI_DEVICE_ID_AMD_8131_APIC for 2.4 kernels
-+ */
-+ if (bus->self &&
-+ (bus->self->vendor == PCI_VENDOR_ID_AMD) &&
-+ (bus->self->device == 0x7450)) {
-+ pci_read_config_byte(bus->self, 0x08, &rev);
-+ if (rev == 0x13) {
-+ /*
-+ * If set a value in module paramter,
-+ * use that value.
-+ */
-+ if (phba->cfg_pci_max_read == 2048)
-+ phba->cfg_pci_max_read = 1024;
-+ return;
-+ }
-+ }
-+ bus = bus->parent;
-+ }
-+ return;
-+}
-+
-+
-+/**
- * lpfc_enable_msix: Enable MSI-X interrupt mode.
- * @phba: pointer to lpfc hba data structure.
- *
-@@ -2340,8 +2376,7 @@ lpfc_enable_msix(struct lpfc_hba *phba)
- ARRAY_SIZE(phba->msix_entries));
- if (rc) {
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-- "0420 Enable MSI-X failed (%d), continuing "
-- "with MSI\n", rc);
-+ "0420 PCI enable MSI-X failed (%d)\n", rc);
- goto msi_fail_out;
- } else
- for (i = 0; i < LPFC_MSIX_VECTORS; i++)
-@@ -2358,9 +2393,9 @@ lpfc_enable_msix(struct lpfc_hba *phba)
- rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler,
- IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba);
- if (rc) {
-- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- "0421 MSI-X slow-path request_irq failed "
-- "(%d), continuing with MSI\n", rc);
-+ "(%d)\n", rc);
- goto msi_fail_out;
- }
-
-@@ -2369,9 +2404,9 @@ lpfc_enable_msix(struct lpfc_hba *phba)
- IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba);
-
- if (rc) {
-- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
- "0429 MSI-X fast-path request_irq failed "
-- "(%d), continuing with MSI\n", rc);
-+ "(%d)\n", rc);
- goto irq_fail_out;
- }
-
-@@ -2392,7 +2427,7 @@ lpfc_enable_msix(struct lpfc_hba *phba)
- goto mbx_fail_out;
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
- if (rc != MBX_SUCCESS) {
-- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
- "0351 Config MSI mailbox command failed, "
- "mbxCmd x%x, mbxStatus x%x\n",
- pmb->mb.mbxCommand, pmb->mb.mbxStatus);
-@@ -2441,6 +2476,111 @@ lpfc_disable_msix(struct lpfc_hba *phba)
- }
-
- /**
-+ * lpfc_enable_msi: Enable MSI interrupt mode.
-+ * @phba: pointer to lpfc hba data structure.
-+ *
-+ * This routine is invoked to enable the MSI interrupt mode. The kernel
-+ * function pci_enable_msi() is called to enable the MSI vector. The
-+ * device driver is responsible for calling the request_irq() to register
-+ * MSI vector with a interrupt the handler, which is done in this function.
-+ *
-+ * Return codes
-+ * 0 - sucessful
-+ * other values - error
-+ */
-+static int
-+lpfc_enable_msi(struct lpfc_hba *phba)
-+{
-+ int rc;
-+
-+ rc = pci_enable_msi(phba->pcidev);
-+ if (!rc)
-+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-+ "0462 PCI enable MSI mode success.\n");
-+ else {
-+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-+ "0471 PCI enable MSI mode failed (%d)\n", rc);
-+ return rc;
-+ }
-+
-+ rc = request_irq(phba->pcidev->irq, lpfc_intr_handler,
-+ IRQF_SHARED, LPFC_DRIVER_NAME, phba);
-+ if (rc) {
-+ pci_disable_msi(phba->pcidev);
-+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
-+ "0478 MSI request_irq failed (%d)\n", rc);
-+ }
-+ return rc;
-+}
-+
-+/**
-+ * lpfc_disable_msi: Disable MSI interrupt mode.
-+ * @phba: pointer to lpfc hba data structure.
-+ *
-+ * This routine is invoked to disable the MSI interrupt mode. The driver
-+ * calls free_irq() on MSI vector it has done request_irq() on before
-+ * calling pci_disable_msi(). Failure to do so results in a BUG_ON() and
-+ * a device will be left with MSI enabled and leaks its vector.
-+ */
-+
-+static void
-+lpfc_disable_msi(struct lpfc_hba *phba)
-+{
-+ free_irq(phba->pcidev->irq, phba);
-+ pci_disable_msi(phba->pcidev);
-+ return;
-+}
-+
-+/**
-+ * lpfc_log_intr_mode: Log the active interrupt mode
-+ * @phba: pointer to lpfc hba data structure.
-+ * @intr_mode: active interrupt mode adopted.
-+ *
-+ * This routine it invoked to log the currently used active interrupt mode
-+ * to the device.
-+ */
-+static void
-+lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
-+{
-+ switch (intr_mode) {
-+ case 0:
-+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-+ "0470 Enable INTx interrupt mode.\n");
-+ break;
-+ case 1:
-+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-+ "0481 Enabled MSI interrupt mode.\n");
-+ break;
-+ case 2:
-+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-+ "0480 Enabled MSI-X interrupt mode.\n");
-+ break;
-+ default:
-+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+ "0482 Illegal interrupt mode.\n");
-+ break;
-+ }
-+ return;
-+}
-+
-+static void
-+lpfc_stop_port(struct lpfc_hba *phba)
-+{
-+ /* Clear all interrupt enable conditions */
-+ writel(0, phba->HCregaddr);
-+ readl(phba->HCregaddr); /* flush */
-+ /* Clear all pending interrupts */
-+ writel(0xffffffff, phba->HAregaddr);
-+ readl(phba->HAregaddr); /* flush */
-+
-+ /* Reset some HBA SLI setup states */
-+ lpfc_stop_phba_timers(phba);
-+ phba->pport->work_port_events = 0;
-+
-+ return;
-+}
-+
-+/**
- * lpfc_enable_intr: Enable device interrupt.
- * @phba: pointer to lpfc hba data structure.
- *
-@@ -2454,60 +2594,47 @@ lpfc_disable_msix(struct lpfc_hba *phba)
- * 0 - sucessful
- * other values - error
- **/
--static int
--lpfc_enable_intr(struct lpfc_hba *phba)
-+static uint32_t
-+lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
- {
-- int retval = 0;
--
-- /* Starting point of configuring interrupt method */
-- phba->intr_type = NONE;
-+ uint32_t intr_mode = LPFC_INTR_ERROR;
-+ int retval;
-
-- if (phba->cfg_use_msi == 2) {
-+ if (cfg_mode == 2) {
- /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
- retval = lpfc_sli_config_port(phba, 3);
-- if (retval)
-- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-- "0478 Firmware not capable of SLI 3 mode.\n");
-- else {
-- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-- "0479 Firmware capable of SLI 3 mode.\n");
-+ if (!retval) {
- /* Now, try to enable MSI-X interrupt mode */
- retval = lpfc_enable_msix(phba);
- if (!retval) {
-+ /* Indicate initialization to MSI-X mode */
- phba->intr_type = MSIX;
-- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-- "0480 enable MSI-X mode.\n");
-+ intr_mode = 2;
- }
- }
- }
-
- /* Fallback to MSI if MSI-X initialization failed */
-- if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) {
-- retval = pci_enable_msi(phba->pcidev);
-+ if (cfg_mode >= 1 && phba->intr_type == NONE) {
-+ retval = lpfc_enable_msi(phba);
- if (!retval) {
-+ /* Indicate initialization to MSI mode */
- phba->intr_type = MSI;
-- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-- "0481 enable MSI mode.\n");
-- } else
-- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-- "0470 enable IRQ mode.\n");
-+ intr_mode = 1;
-+ }
- }
-
-- /* MSI-X is the only case the doesn't need to call request_irq */
-- if (phba->intr_type != MSIX) {
-+ /* Fallback to INTx if both MSI-X/MSI initalization failed */
-+ if (phba->intr_type == NONE) {
- retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
- IRQF_SHARED, LPFC_DRIVER_NAME, phba);
-- if (retval) {
-- if (phba->intr_type == MSI)
-- pci_disable_msi(phba->pcidev);
-- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-- "0471 Enable interrupt handler "
-- "failed\n");
-- } else if (phba->intr_type != MSI)
-+ if (!retval) {
-+ /* Indicate initialization to INTx mode */
- phba->intr_type = INTx;
-+ intr_mode = 0;
-+ }
- }
--
-- return retval;
-+ return intr_mode;
- }
-
- /**
-@@ -2522,13 +2649,18 @@ lpfc_enable_intr(struct lpfc_hba *phba)
- static void
- lpfc_disable_intr(struct lpfc_hba *phba)
- {
-+ /* Disable the currently initialized interrupt mode */
- if (phba->intr_type == MSIX)
- lpfc_disable_msix(phba);
-- else {
-+ else if (phba->intr_type == MSI)
-+ lpfc_disable_msi(phba);
-+ else if (phba->intr_type == INTx)
- free_irq(phba->pcidev->irq, phba);
-- if (phba->intr_type == MSI)
-- pci_disable_msi(phba->pcidev);
-- }
-+
-+ /* Reset interrupt management states */
-+ phba->intr_type = NONE;
-+ phba->sli.slistat.sli_intr = 0;
-+
- return;
- }
-
-@@ -2562,6 +2694,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- int error = -ENODEV, retval;
- int i, hbq_count;
- uint16_t iotag;
-+ uint32_t cfg_mode, intr_mode;
- int bars = pci_select_bars(pdev, IORESOURCE_MEM);
- struct lpfc_adapter_event_header adapter_event;
-
-@@ -2593,6 +2726,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- * establish the host.
- */
- lpfc_get_cfgparam(phba);
-+ /* Check if we need to change the DMA length */
-+ lpfc_setup_max_dma_length(phba);
-+
- phba->max_vpi = lpfc_hba_max_vpi(phba->pcidev->device);
-
- /* Initialize timers used by driver */
-@@ -2615,6 +2751,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- phba->eratt_poll.data = (unsigned long) phba;
-
- pci_set_master(pdev);
-+ pci_save_state(pdev);
- pci_try_set_mwi(pdev);
-
- if (pci_set_dma_mask(phba->pcidev, DMA_64BIT_MASK) != 0)
-@@ -2769,9 +2906,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
-
- if ((lpfc_get_security_enabled)(shost)) {
- unsigned long flags;
-- /* Triggers fcauthd to register if it is running */
-- fc_host_post_event(shost, fc_get_event_number(),
-- FCH_EVT_PORT_ONLINE, shost->host_no);
- spin_lock_irqsave(&fc_security_user_lock, flags);
- list_add_tail(&vport->sc_users, &fc_security_user_list);
- spin_unlock_irqrestore(&fc_security_user_lock, flags);
-@@ -2779,6 +2913,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- lpfc_fc_queue_security_work(vport,
- &vport->sc_online_work);
- }
-+ /* Triggers fcauthd to register if it is running */
-+ fc_host_post_event(shost, fc_get_event_number(),
-+ FCH_EVT_PORT_ONLINE, shost->host_no);
- }
- phba->pport = vport;
- lpfc_debugfs_initialize(vport);
-@@ -2791,34 +2928,66 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
- phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
-
-- /* Configure and enable interrupt */
-- error = lpfc_enable_intr(phba);
-- if (error) {
-- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-- "0426 Failed to enable interrupt.\n");
-- goto out_destroy_port;
-- }
--
-+ /* Confiugre sysfs attributes */
- phba->dfc_host = lpfcdfc_host_add(pdev, shost, phba);
- if (!phba->dfc_host) {
- lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
- "1201 Failed to allocate dfc_host \n");
- error = -ENOMEM;
-- goto out_free_irq;
-+ goto out_destroy_port;
- }
-
- if (lpfc_alloc_sysfs_attr(vport)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "1476 Failed to allocate sysfs attr\n");
- error = -ENOMEM;
-- goto out_free_irq;
-+ goto out_del_dfc_host;
- }
-
-- if (lpfc_sli_hba_setup(phba)) {
-- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-- "1477 Failed to set up hba\n");
-- error = -ENODEV;
-- goto out_remove_device;
-+ cfg_mode = phba->cfg_use_msi;
-+ while (true) {
-+ /* Configure and enable interrupt */
-+ intr_mode = lpfc_enable_intr(phba, cfg_mode);
-+ if (intr_mode == LPFC_INTR_ERROR) {
-+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+ "0426 Failed to enable interrupt.\n");
-+ goto out_free_sysfs_attr;
-+ }
-+ /* HBA SLI setup */
-+ if (lpfc_sli_hba_setup(phba)) {
-+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+ "1477 Failed to set up hba\n");
-+ error = -ENODEV;
-+ goto out_remove_device;
-+ }
-+
-+ /* Wait 50ms for the interrupts of previous mailbox commands */
-+ msleep(50);
-+ /* Check active interrupts received */
-+ if (phba->sli.slistat.sli_intr > LPFC_INTR_THRESHOLD) {
-+ /* Log the current active interrupt mode */
-+ phba->intr_mode = intr_mode;
-+ lpfc_log_intr_mode(phba, intr_mode);
-+ break;
-+ } else {
-+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-+ "0451 Configure interrupt mode (%d) "
-+ "failed active interrupt test.\n",
-+ intr_mode);
-+ if (intr_mode == 0) {
-+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+ "0479 Failed to enable "
-+ "interrupt.\n");
-+ error = -ENODEV;
-+ goto out_remove_device;
-+ }
-+ /* Stop HBA SLI setups */
-+ lpfc_stop_port(phba);
-+ /* Disable the current interrupt mode */
-+ lpfc_disable_intr(phba);
-+ /* Try next level of interrupt mode */
-+ cfg_mode = --intr_mode;
-+ }
- }
-
- /*
-@@ -2850,16 +3019,19 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
- return 0;
-
- out_remove_device:
-- lpfc_free_sysfs_attr(vport);
- spin_lock_irq(shost->host_lock);
- vport->load_flag |= FC_UNLOADING;
- spin_unlock_irq(shost->host_lock);
--out_free_irq:
-- if (phba->dfc_host)
-- lpfcdfc_host_del(phba->dfc_host);
- lpfc_stop_phba_timers(phba);
- phba->pport->work_port_events = 0;
- lpfc_disable_intr(phba);
-+ lpfc_sli_hba_down(phba);
-+ lpfc_sli_brdrestart(phba);
-+out_free_sysfs_attr:
-+ lpfc_free_sysfs_attr(vport);
-+out_del_dfc_host:
-+ if (phba->dfc_host)
-+ lpfcdfc_host_del(phba->dfc_host);
- out_destroy_port:
- destroy_port(vport);
- out_kthread_stop:
-@@ -3051,6 +3223,7 @@ lpfc_pci_resume_one(struct pci_dev *pdev)
- {
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
-+ uint32_t intr_mode;
- int error;
-
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-@@ -3073,19 +3246,22 @@ lpfc_pci_resume_one(struct pci_dev *pdev)
- return error;
- }
-
-- /* Enable interrupt from device */
-- error = lpfc_enable_intr(phba);
-- if (error) {
-+ /* Configure and enable interrupt */
-+ intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
-+ if (intr_mode == LPFC_INTR_ERROR) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-- "0430 PM resume Failed to enable interrupt: "
-- "error=x%x.\n", error);
-- return error;
-- }
-+ "0430 PM resume Failed to enable interrupt\n");
-+ return -EIO;
-+ } else
-+ phba->intr_mode = intr_mode;
-
- /* Restart HBA and bring it online */
- lpfc_sli_brdrestart(phba);
- lpfc_online(phba);
-
-+ /* Log the current active interrupt mode */
-+ lpfc_log_intr_mode(phba, phba->intr_mode);
-+
- return 0;
- }
-
-@@ -3161,7 +3337,7 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
- struct lpfc_sli *psli = &phba->sli;
-- int error;
-+ uint32_t intr_mode;
-
- dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
- if (pci_enable_device_mem(pdev)) {
-@@ -3170,25 +3346,31 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
- return PCI_ERS_RESULT_DISCONNECT;
- }
-
-- pci_set_master(pdev);
-+ pci_restore_state(pdev);
-+ if (pdev->is_busmaster)
-+ pci_set_master(pdev);
-
- spin_lock_irq(&phba->hbalock);
- psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
- spin_unlock_irq(&phba->hbalock);
-
-- /* Enable configured interrupt method */
-- error = lpfc_enable_intr(phba);
-- if (error) {
-+ /* Configure and enable interrupt */
-+ intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
-+ if (intr_mode == LPFC_INTR_ERROR) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0427 Cannot re-enable interrupt after "
- "slot reset.\n");
- return PCI_ERS_RESULT_DISCONNECT;
-- }
-+ } else
-+ phba->intr_mode = intr_mode;
-
- /* Take device offline; this will perform cleanup */
- lpfc_offline(phba);
- lpfc_sli_brdrestart(phba);
-
-+ /* Log the current active interrupt mode */
-+ lpfc_log_intr_mode(phba, phba->intr_mode);
-+
- return PCI_ERS_RESULT_RECOVERED;
- }
-
-diff --git a/drivers/scsi/lpfc/lpfc_ioctl.c b/drivers/scsi/lpfc/lpfc_ioctl.c
-index e80d157..127b47b 100644
---- a/drivers/scsi/lpfc/lpfc_ioctl.c
-+++ b/drivers/scsi/lpfc/lpfc_ioctl.c
-@@ -162,7 +162,7 @@ lpfc_ioctl_hba_rnid(struct lpfc_hba * phba,
- for (i0 = 0;
- i0 < 10 && (pndl->nlp_flag & NLP_ELS_SND_MASK) == NLP_RNID_SND;
- i0++) {
-- mdelay(1000);
-+ msleep(1000);
- }
-
- if (i0 == 10) {
-@@ -731,7 +731,6 @@ lpfc_ioctl_send_mgmt_cmd(struct lpfc_hba * phba,
- outdmp = dfc_cmd_data_alloc(phba, NULL, bpl, snsbfrcnt);
- if (!outdmp) {
- rc = ENOMEM;
-- spin_lock_irq(shost->host_lock);
- goto send_mgmt_cmd_free_indmp;
- }
-
-@@ -1104,7 +1103,7 @@ lpfc_ioctl_loopback_mode(struct lpfc_hba *phba,
- if (i++ > 500) /* wait up to 5 seconds */
- break;
-
-- mdelay(10);
-+ msleep(10);
- }
-
- memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
-diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
-index f0ab456..84619ed 100644
---- a/drivers/scsi/lpfc/lpfc_mbox.c
-+++ b/drivers/scsi/lpfc/lpfc_mbox.c
-@@ -835,6 +835,40 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
- }
-
- /**
-+ * lpfc_set_var: Prepare a mailbox command to write slim.
-+ * @phba: pointer to lpfc hba data structure.
-+ * @pmb: pointer to the driver internal queue element for mailbox command.
-+ * @addr: This the set variable number that identifies the variable.
-+ * @value:The value that we are setting the parameter to.
-+ *
-+ * The routine just sets the addr and value in the set variable mailbox
-+ * command structure.
-+ * returns: NONE.
-+ **/
-+void
-+lpfc_set_var(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, uint32_t addr,
-+ uint32_t value)
-+{
-+ MAILBOX_t *mb;
-+
-+ mb = &pmb->mb;
-+ memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
-+
-+ /*
-+ * Always turn on DELAYED ABTS for ELS timeouts
-+ */
-+ if ((addr == 0x052198) && (value == 0))
-+ value = 1;
-+
-+ mb->un.varWords[0] = addr;
-+ mb->un.varWords[1] = value;
-+
-+ mb->mbxCommand = MBX_SET_VARIABLE;
-+ mb->mbxOwner = OWN_HOST;
-+ return;
-+}
-+
-+/**
- * lpfc_read_rev: Prepare a mailbox command for reading HBA revision.
- * @phba: pointer to lpfc hba data structure.
- * @pmb: pointer to the driver internal queue element for mailbox command.
-@@ -1093,6 +1127,9 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr);
- mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr);
-
-+ /* Always Host Group Pointer is in SLIM */
-+ mb->un.varCfgPort.hps = 1;
-+
- /* If HBA supports SLI=3 ask for it */
-
- if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
-@@ -1195,16 +1232,11 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
- sizeof(*phba->host_gp));
- }
-
-- /* Setup Port Group ring pointer */
-- if (phba->sli3_options & LPFC_SLI3_INB_ENABLED) {
-- pgp_offset = offsetof(struct lpfc_sli2_slim,
-- mbx.us.s3_inb_pgp.port);
-- phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get;
-- } else if (phba->sli_rev == 3) {
-+ /* Setup Port Group offset */
-+ if (phba->sli_rev == 3)
- pgp_offset = offsetof(struct lpfc_sli2_slim,
- mbx.us.s3_pgp.port);
-- phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
-- } else
-+ else
- pgp_offset = offsetof(struct lpfc_sli2_slim, mbx.us.s2.port);
- pdma_addr = phba->slim2p.phys + pgp_offset;
- phba->pcb->pgpAddrHigh = putPaddrHigh(pdma_addr);
-diff --git a/drivers/scsi/lpfc/lpfc_menlo.c b/drivers/scsi/lpfc/lpfc_menlo.c
-index aa36c16..4f3b332 100644
---- a/drivers/scsi/lpfc/lpfc_menlo.c
-+++ b/drivers/scsi/lpfc/lpfc_menlo.c
-@@ -289,19 +289,16 @@ static void
- sysfs_menlo_idle(struct lpfc_hba *phba,
- struct lpfc_sysfs_menlo *sysfs_menlo)
- {
-- struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport);
-
- spin_lock_irq(&phba->hbalock);
- list_del_init(&sysfs_menlo->list);
- spin_unlock_irq(&phba->hbalock);
-- spin_lock_irq(shost->host_lock);
-
- if (sysfs_menlo->cr.cmdiocbq)
- sysfs_menlo_genreq_free(phba, &sysfs_menlo->cr);
- if (sysfs_menlo->cx.cmdiocbq)
- sysfs_menlo_genreq_free(phba, &sysfs_menlo->cx);
-
-- spin_unlock_irq(shost->host_lock);
- kfree(sysfs_menlo);
- }
-
-@@ -543,14 +540,15 @@ lpfc_menlo_write(struct lpfc_hba *phba,
- }
-
- if ((count + sysfs_menlo->cr.offset) > sysfs_menlo->cmdhdr.cmdsize) {
-- if ( sysfs_menlo->cmdhdr.cmdsize != 4) {
-- lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
-+ if (sysfs_menlo->cmdhdr.cmdsize >=
-+ sizeof(struct lpfc_sysfs_menlo_hdr)) {
-+ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
- "1213 FCoE cmd overflow: off %d + cnt %d > cmdsz %d\n",
-- (int)sysfs_menlo->cr.offset,
-- (int)count,
-- (int)sysfs_menlo->cmdhdr.cmdsize);
-- sysfs_menlo_idle(phba, sysfs_menlo);
-- return -ERANGE;
-+ (int)sysfs_menlo->cr.offset,
-+ (int)count,
-+ (int)sysfs_menlo->cmdhdr.cmdsize);
-+ sysfs_menlo_idle(phba, sysfs_menlo);
-+ return -ERANGE;
- }
- }
-
-diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
-index 0c25d97..8f548ad 100644
---- a/drivers/scsi/lpfc/lpfc_nportdisc.c
-+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
-@@ -1929,10 +1929,10 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
- if (vport->fc_flag & FC_RSCN_DEFERRED)
- return ndlp->nlp_state;
-
-+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
- spin_lock_irq(shost->host_lock);
- ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(shost->host_lock);
-- lpfc_cancel_retry_delay_tmo(vport, ndlp);
- return ndlp->nlp_state;
- }
-
-diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
-index daf400e..38a7faf 100644
---- a/drivers/scsi/lpfc/lpfc_scsi.c
-+++ b/drivers/scsi/lpfc/lpfc_scsi.c
-@@ -65,6 +65,8 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
- if (cmd->result)
- return;
-
-+ latency = jiffies_to_msecs((long)jiffies - (long)lpfc_cmd->start_time);
-+
- spin_lock_irqsave(shost->host_lock, flags);
- if (!vport->stat_data_enabled ||
- vport->stat_data_blocked ||
-@@ -73,13 +75,15 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
- spin_unlock_irqrestore(shost->host_lock, flags);
- return;
- }
-- latency = jiffies_to_msecs(jiffies - lpfc_cmd->start_time);
-
- if (phba->bucket_type == LPFC_LINEAR_BUCKET) {
- i = (latency + phba->bucket_step - 1 - phba->bucket_base)/
- phba->bucket_step;
-- if (i >= LPFC_MAX_BUCKET_COUNT)
-- i = LPFC_MAX_BUCKET_COUNT;
-+ /* check array subscript bounds */
-+ if (i < 0)
-+ i = 0;
-+ else if (i >= LPFC_MAX_BUCKET_COUNT)
-+ i = LPFC_MAX_BUCKET_COUNT - 1;
- } else {
- for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++)
- if (latency <= (phba->bucket_base +
-@@ -413,14 +417,14 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
- bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd));
- bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd);
- bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-- bpl[0].tus.w = le32_to_cpu(bpl->tus.w);
-+ bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w);
-
- /* Setup the physical region for the FCP RSP */
- bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp));
- bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp));
- bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp);
- bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-- bpl[1].tus.w = le32_to_cpu(bpl->tus.w);
-+ bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w);
-
- /*
- * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf,
-@@ -920,7 +924,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
- if (!pnode || !NLP_CHK_NODE_ACT(pnode)
- || (pnode->nlp_state != NLP_STE_MAPPED_NODE))
- cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED,
-- SAM_STAT_BUSY);
-+ SAM_STAT_BUSY);
- } else {
- cmd->result = ScsiResult(DID_OK, 0);
- }
-diff --git a/drivers/scsi/lpfc/lpfc_security.c b/drivers/scsi/lpfc/lpfc_security.c
-index c0fbe56..3d2a8c8 100644
---- a/drivers/scsi/lpfc/lpfc_security.c
-+++ b/drivers/scsi/lpfc/lpfc_security.c
-@@ -45,8 +45,7 @@ lpfc_security_service_online(struct Scsi_Host *shost)
-
- lpfc_security_service_state = SECURITY_ONLINE;
- if (vport->cfg_enable_auth &&
-- vport->auth.auth_mode == FC_AUTHMODE_UNKNOWN &&
-- vport->phba->link_state == LPFC_HBA_ERROR)
-+ vport->auth.auth_mode == FC_AUTHMODE_UNKNOWN)
- lpfc_selective_reset(vport->phba);
- }
-
-diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
-index ac78493..5838e41 100644
---- a/drivers/scsi/lpfc/lpfc_sli.c
-+++ b/drivers/scsi/lpfc/lpfc_sli.c
-@@ -1262,68 +1262,6 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
- }
-
- /**
-- * lpfc_sli_replace_hbqbuff: Replace the HBQ buffer with a new buffer.
-- * @phba: Pointer to HBA context object.
-- * @tag: Tag for the HBQ buffer.
-- *
-- * This function is called from unsolicited event handler code path to get the
-- * HBQ buffer associated with an unsolicited iocb. This function is called with
-- * no lock held. It returns the buffer associated with the given tag and posts
-- * another buffer to the firmware. Note that the new buffer must be allocated
-- * before taking the hbalock and that the hba lock must be held until it is
-- * finished with the hbq entry swap.
-- **/
--static struct lpfc_dmabuf *
--lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
--{
-- struct hbq_dmabuf *hbq_entry, *new_hbq_entry;
-- uint32_t hbqno;
-- void *virt; /* virtual address ptr */
-- dma_addr_t phys; /* mapped address */
-- unsigned long flags;
--
-- hbqno = tag >> 16;
-- new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
-- /* Check whether HBQ is still in use */
-- spin_lock_irqsave(&phba->hbalock, flags);
-- if (!phba->hbq_in_use) {
-- if (new_hbq_entry)
-- (phba->hbqs[hbqno].hbq_free_buffer)(phba,
-- new_hbq_entry);
-- spin_unlock_irqrestore(&phba->hbalock, flags);
-- return NULL;
-- }
--
-- hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
-- if (hbq_entry == NULL) {
-- if (new_hbq_entry)
-- (phba->hbqs[hbqno].hbq_free_buffer)(phba,
-- new_hbq_entry);
-- spin_unlock_irqrestore(&phba->hbalock, flags);
-- return NULL;
-- }
-- list_del(&hbq_entry->dbuf.list);
--
-- if (new_hbq_entry == NULL) {
-- list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list);
-- spin_unlock_irqrestore(&phba->hbalock, flags);
-- return &hbq_entry->dbuf;
-- }
-- new_hbq_entry->tag = -1;
-- phys = new_hbq_entry->dbuf.phys;
-- virt = new_hbq_entry->dbuf.virt;
-- new_hbq_entry->dbuf.phys = hbq_entry->dbuf.phys;
-- new_hbq_entry->dbuf.virt = hbq_entry->dbuf.virt;
-- hbq_entry->dbuf.phys = phys;
-- hbq_entry->dbuf.virt = virt;
-- lpfc_sli_free_hbq(phba, hbq_entry);
-- list_add_tail(&new_hbq_entry->dbuf.list, &phba->hbqbuf_in_list);
-- spin_unlock_irqrestore(&phba->hbalock, flags);
--
-- return &new_hbq_entry->dbuf;
--}
--
--/**
- * lpfc_sli_get_buff: Get the buffer associated with the buffer tag.
- * @phba: Pointer to HBA context object.
- * @pring: Pointer to driver SLI ring object.
-@@ -1337,13 +1275,17 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
- **/
- static struct lpfc_dmabuf *
- lpfc_sli_get_buff(struct lpfc_hba *phba,
-- struct lpfc_sli_ring *pring,
-- uint32_t tag)
-+ struct lpfc_sli_ring *pring,
-+ uint32_t tag)
- {
-+ struct hbq_dmabuf *hbq_entry;
-+
- if (tag & QUE_BUFTAG_BIT)
- return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
-- else
-- return lpfc_sli_replace_hbqbuff(phba, tag);
-+ hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
-+ if (!hbq_entry)
-+ return NULL;
-+ return &hbq_entry->dbuf;
- }
-
-
-@@ -1375,8 +1317,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- match = 0;
- irsp = &(saveq->iocb);
-
-- if (irsp->ulpStatus == IOSTAT_NEED_BUFFER)
-- return 1;
- if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
- if (pring->lpfc_sli_rcv_async_status)
- pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
-@@ -2776,6 +2716,86 @@ lpfc_sli_brdreset(struct lpfc_hba *phba)
- }
-
- /**
-+ * lpfc_sli_set_dma_length: Set the HBA's max DMA length.
-+ * @phba: Pointer to HBA context object.
-+ * @polling: flag that indicates if interrupts are enabled.
-+ *
-+ * This function sets the HBA's max dma length by issuing a set variable
-+ * mailbox command. The dma length is taking from the cfg_pci_max_read
-+ * configuration parameter. This parameter is passed as a module parameter
-+ * during the driver load. If the HBA does not support this set variable
-+ * mbox command the failure status will reset the cfg_pci_max_read to the
-+ * default(2048).
-+ * If interrupts are not enabled yet then the polling flag = 1 should be
-+ * be used so that the right mailbox routine is called.
-+ * This function returns 0 for success, non 0 returned for failure.
-+ **/
-+int
-+lpfc_sli_set_dma_length(struct lpfc_hba *phba, uint32_t polling)
-+{
-+ uint32_t dma_length;
-+ LPFC_MBOXQ_t *mbox;
-+ int ret = 0;
-+
-+ switch (phba->cfg_pci_max_read) {
-+ case 512:
-+ dma_length = SLIM_VAL_MAX_DMA_512;
-+ break;
-+ case 1024:
-+ dma_length = SLIM_VAL_MAX_DMA_1024;
-+ break;
-+ case 2048:
-+ dma_length = SLIM_VAL_MAX_DMA_2048;
-+ break;
-+ case 4096:
-+ dma_length = SLIM_VAL_MAX_DMA_4096;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-+ if (!mbox)
-+ goto failed;
-+
-+ lpfc_set_var(phba, mbox, SLIM_VAR_MAX_DMA_LENGTH, dma_length);
-+
-+ if (polling)
-+ ret = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
-+ else
-+ ret = lpfc_sli_issue_mbox_wait(phba, mbox,
-+ LPFC_MBOX_TMO * 2);
-+
-+ if (ret != MBX_SUCCESS) {
-+ if (mbox->mb.mbxStatus != MBXERR_UNKNOWN_CMD)
-+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-+ "%d:0443 Adapter failed to set maximum"
-+ " DMA length mbxStatus x%x \n",
-+ phba->brd_no, mbox->mb.mbxStatus);
-+ else
-+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-+ "%d:0447 Adapter failed to set maximum"
-+ " DMA length mbxStatus x%x \n",
-+ phba->brd_no, mbox->mb.mbxStatus);
-+ goto failed;
-+ }
-+
-+ mempool_free(mbox, phba->mbox_mem_pool);
-+ return 0;
-+
-+failed:
-+ /* If mailbox command failed, reset the value to default value */
-+ phba->cfg_pci_max_read = 2048;
-+ if (ret == MBX_TIMEOUT) {
-+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-+ return -EPERM;
-+ } else if (mbox) {
-+ mempool_free(mbox, phba->mbox_mem_pool);
-+ return -EPERM;
-+ } else
-+ return -ENOMEM;
-+}
-+/**
- * lpfc_sli_brdrestart: Restart the HBA.
- * @phba: Pointer to HBA context object.
- *
-@@ -3140,17 +3160,20 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
- phba->sli3_options |= LPFC_SLI3_CRP_ENABLED;
- if (pmb->mb.un.varCfgPort.ginb) {
- phba->sli3_options |= LPFC_SLI3_INB_ENABLED;
-+ phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get;
- phba->port_gp = phba->mbox->us.s3_inb_pgp.port;
- phba->inb_ha_copy = &phba->mbox->us.s3_inb_pgp.ha_copy;
- phba->inb_counter = &phba->mbox->us.s3_inb_pgp.counter;
- phba->inb_last_counter =
- phba->mbox->us.s3_inb_pgp.counter;
- } else {
-+ phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
- phba->port_gp = phba->mbox->us.s3_pgp.port;
- phba->inb_ha_copy = NULL;
- phba->inb_counter = NULL;
- }
- } else {
-+ phba->hbq_get = NULL;
- phba->port_gp = phba->mbox->us.s2.port;
- phba->inb_ha_copy = NULL;
- phba->inb_counter = NULL;
-@@ -3226,6 +3249,9 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "0444 Firmware in SLI %x mode. Max_vpi %d\n",
- phba->sli_rev, phba->max_vpi);
-+
-+ lpfc_sli_set_dma_length(phba, 1);
-+
- rc = lpfc_sli_ring_map(phba);
-
- if (rc)
-@@ -3301,10 +3327,6 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
- struct lpfc_sli *psli = &phba->sli;
- struct lpfc_sli_ring *pring;
-
-- if (!(phba->pport->work_port_events & WORKER_MBOX_TMO)) {
-- return;
-- }
--
- /* Mbox cmd <mbxCommand> timeout */
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
- "0310 Mailbox command x%x timeout Data: x%x x%x x%p\n",
-@@ -5275,6 +5297,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
- uint32_t ha_copy;
- uint32_t work_ha_copy;
- unsigned long status;
-+ unsigned long iflag;
- uint32_t control;
-
- MAILBOX_t *mbox, *pmbox;
-@@ -5307,7 +5330,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
- if (unlikely(phba->link_state < LPFC_LINK_DOWN))
- return IRQ_NONE;
- /* Need to read HA REG for slow-path events */
-- spin_lock(&phba->hbalock);
-+ spin_lock_irqsave(&phba->hbalock, iflag);
- ha_copy = readl(phba->HAregaddr);
- /* If somebody is waiting to handle an eratt don't process it
- * here. The brdkill function will do this.
-@@ -5327,7 +5350,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
- writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)),
- phba->HAregaddr);
- readl(phba->HAregaddr); /* flush */
-- spin_unlock(&phba->hbalock);
-+ spin_unlock_irqrestore(&phba->hbalock, iflag);
- } else
- ha_copy = phba->ha_copy;
-
-@@ -5340,13 +5363,13 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
- * Turn off Link Attention interrupts
- * until CLEAR_LA done
- */
-- spin_lock(&phba->hbalock);
-+ spin_lock_irqsave(&phba->hbalock, iflag);
- phba->sli.sli_flag &= ~LPFC_PROCESS_LA;
- control = readl(phba->HCregaddr);
- control &= ~HC_LAINT_ENA;
- writel(control, phba->HCregaddr);
- readl(phba->HCregaddr); /* flush */
-- spin_unlock(&phba->hbalock);
-+ spin_unlock_irqrestore(&phba->hbalock, iflag);
- }
- else
- work_ha_copy &= ~HA_LATT;
-@@ -5361,7 +5384,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
- (HA_RXMASK << (4*LPFC_ELS_RING)));
- status >>= (4*LPFC_ELS_RING);
- if (status & HA_RXMASK) {
-- spin_lock(&phba->hbalock);
-+ spin_lock_irqsave(&phba->hbalock, iflag);
- control = readl(phba->HCregaddr);
-
- lpfc_debugfs_slow_ring_trc(phba,
-@@ -5390,10 +5413,10 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
- (uint32_t)((unsigned long)
- &phba->work_waitq));
- }
-- spin_unlock(&phba->hbalock);
-+ spin_unlock_irqrestore(&phba->hbalock, iflag);
- }
- }
-- spin_lock(&phba->hbalock);
-+ spin_lock_irqsave(&phba->hbalock, iflag);
- if (work_ha_copy & HA_ERATT)
- lpfc_sli_read_hs(phba);
- if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) {
-@@ -5405,7 +5428,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
- /* First check out the status word */
- lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t));
- if (pmbox->mbxOwner != OWN_HOST) {
-- spin_unlock(&phba->hbalock);
-+ spin_unlock_irqrestore(&phba->hbalock, iflag);
- /*
- * Stray Mailbox Interrupt, mbxCommand <cmd>
- * mbxStatus <status>
-@@ -5422,7 +5445,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
- work_ha_copy &= ~HA_MBATT;
- } else {
- phba->sli.mbox_active = NULL;
-- spin_unlock(&phba->hbalock);
-+ spin_unlock_irqrestore(&phba->hbalock, iflag);
- phba->last_completion_time = jiffies;
- del_timer(&phba->sli.mbox_tmo);
- if (pmb->mbox_cmpl) {
-@@ -5480,14 +5503,18 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
- goto send_current_mbox;
- }
- }
-- spin_lock(&phba->pport->work_port_lock);
-+ spin_lock_irqsave(
-+ &phba->pport->work_port_lock,
-+ iflag);
- phba->pport->work_port_events &=
- ~WORKER_MBOX_TMO;
-- spin_unlock(&phba->pport->work_port_lock);
-+ spin_unlock_irqrestore(
-+ &phba->pport->work_port_lock,
-+ iflag);
- lpfc_mbox_cmpl_put(phba, pmb);
- }
- } else
-- spin_unlock(&phba->hbalock);
-+ spin_unlock_irqrestore(&phba->hbalock, iflag);
-
- if ((work_ha_copy & HA_MBATT) &&
- (phba->sli.mbox_active == NULL)) {
-@@ -5503,9 +5530,9 @@ send_current_mbox:
- "MBX_SUCCESS");
- }
-
-- spin_lock(&phba->hbalock);
-+ spin_lock_irqsave(&phba->hbalock, iflag);
- phba->work_ha |= work_ha_copy;
-- spin_unlock(&phba->hbalock);
-+ spin_unlock_irqrestore(&phba->hbalock, iflag);
- lpfc_worker_wake_up(phba);
- }
- return IRQ_HANDLED;
-@@ -5537,6 +5564,7 @@ lpfc_fp_intr_handler(int irq, void *dev_id)
- struct lpfc_hba *phba;
- uint32_t ha_copy;
- unsigned long status;
-+ unsigned long iflag;
-
- /* Get the driver's phba structure from the dev_id and
- * assume the HBA is not interrupting.
-@@ -5562,11 +5590,11 @@ lpfc_fp_intr_handler(int irq, void *dev_id)
- /* Need to read HA REG for FCP ring and other ring events */
- ha_copy = readl(phba->HAregaddr);
- /* Clear up only attention source related to fast-path */
-- spin_lock(&phba->hbalock);
-+ spin_lock_irqsave(&phba->hbalock, iflag);
- writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)),
- phba->HAregaddr);
- readl(phba->HAregaddr); /* flush */
-- spin_unlock(&phba->hbalock);
-+ spin_unlock_irqrestore(&phba->hbalock, iflag);
- } else
- ha_copy = phba->ha_copy;
-
-diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
-index 57b559a..16626a5 100644
---- a/drivers/scsi/lpfc/lpfc_version.h
-+++ b/drivers/scsi/lpfc/lpfc_version.h
-@@ -18,7 +18,7 @@
- * included with this package. *
- *******************************************************************/
-
--#define LPFC_DRIVER_VERSION "8.2.8.4"
-+#define LPFC_DRIVER_VERSION "8.2.8.7"
-
- #define LPFC_DRIVER_NAME "lpfc"
- #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"