uint32_t word0;
};
+#define LPFC_PORT_SEM_UE_RECOVERABLE 0xE000
+#define LPFC_PORT_SEM_MASK 0xF000
/* The following BAR0 Registers apply to SLI4 if_type 0 UCNAs. */
#define LPFC_UERR_STATUS_HI 0x00A4
#define LPFC_UERR_STATUS_LO 0x00A0
#define LPFC_MBOX_OPCODE_READ_OBJECT_LIST 0xAD
#define LPFC_MBOX_OPCODE_DELETE_OBJECT 0xAE
#define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS 0xB5
+#define LPFC_MBOX_OPCODE_SET_FEATURES 0xBF
/* FCoE Opcodes */
#define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE 0x01
#define cfg_ext_embed_cb_WORD word19
};
+#define LPFC_SET_UE_RECOVERY 0x10
+struct lpfc_mbx_set_feature {
+ struct mbox_header header;
+ uint32_t feature;
+ uint32_t param_len;
+ uint32_t word6;
+#define lpfc_mbx_set_feature_UER_SHIFT 0
+#define lpfc_mbx_set_feature_UER_MASK 0x00000001
+#define lpfc_mbx_set_feature_UER_WORD word6
+ uint32_t word7;
+#define lpfc_mbx_set_feature_UERP_SHIFT 0
+#define lpfc_mbx_set_feature_UERP_MASK 0x0000ffff
+#define lpfc_mbx_set_feature_UERP_WORD word7
+#define lpfc_mbx_set_feature_UESR_SHIFT 16
+#define lpfc_mbx_set_feature_UESR_MASK 0x0000ffff
+#define lpfc_mbx_set_feature_UESR_WORD word7
+};
+
+
struct lpfc_mbx_get_sli4_parameters {
struct mbox_header header;
struct lpfc_sli4_parameters sli4_parameters;
struct lpfc_mbx_get_prof_cfg get_prof_cfg;
struct lpfc_mbx_wr_object wr_object;
struct lpfc_mbx_get_port_name get_port_name;
+ struct lpfc_mbx_set_feature set_feature;
struct lpfc_mbx_memory_dump_type3 mem_dump_type3;
struct lpfc_mbx_nop nop;
} un;
phba->last_completion_time = jiffies;
/* Set up error attention (ERATT) polling timer */
mod_timer(&phba->eratt_poll,
- jiffies + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL));
+ jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval));
if (phba->hba_flag & LINK_DISABLED) {
lpfc_printf_log(phba,
int rc;
uint32_t intr_mode;
- /*
- * On error status condition, driver need to wait for port
- * ready before performing reset.
- */
- rc = lpfc_sli4_pdev_status_reg_wait(phba);
- if (!rc) {
- /* need reset: attempt for port recovery */
- if (en_rn_msg)
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "2887 Reset Needed: Attempting Port "
- "Recovery...\n");
- lpfc_offline_prep(phba, mbx_action);
- lpfc_offline(phba);
- /* release interrupt for possible resource change */
- lpfc_sli4_disable_intr(phba);
- lpfc_sli_brdrestart(phba);
- /* request and enable interrupt */
- intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
- if (intr_mode == LPFC_INTR_ERROR) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "3175 Failed to enable interrupt\n");
- return -EIO;
- } else {
- phba->intr_mode = intr_mode;
- }
- rc = lpfc_online(phba);
- if (rc == 0)
- lpfc_unblock_mgmt_io(phba);
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_2) {
+ /*
+ * On error status condition, driver need to wait for port
+ * ready before performing reset.
+ */
+ rc = lpfc_sli4_pdev_status_reg_wait(phba);
+ if (!rc)
+ return rc;
+ }
+ /* need reset: attempt for port recovery */
+ if (en_rn_msg)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2887 Reset Needed: Attempting Port "
+ "Recovery...\n");
+ lpfc_offline_prep(phba, mbx_action);
+ lpfc_offline(phba);
+ /* release interrupt for possible resource change */
+ lpfc_sli4_disable_intr(phba);
+ lpfc_sli_brdrestart(phba);
+ /* request and enable interrupt */
+ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
+ if (intr_mode == LPFC_INTR_ERROR) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3175 Failed to enable interrupt\n");
+ return -EIO;
}
+ phba->intr_mode = intr_mode;
+ rc = lpfc_online(phba);
+ if (rc == 0)
+ lpfc_unblock_mgmt_io(phba);
+
return rc;
}
struct lpfc_register portstat_reg = {0};
uint32_t reg_err1, reg_err2;
uint32_t uerrlo_reg, uemasklo_reg;
- uint32_t pci_rd_rc1, pci_rd_rc2;
+ uint32_t smphr_port_status = 0, pci_rd_rc1, pci_rd_rc2;
bool en_rn_msg = true;
struct temp_event temp_event_data;
- int rc;
+ struct lpfc_register portsmphr_reg;
+ int rc, i;
/* If the pci channel is offline, ignore possible errors, since
* we cannot communicate with the pci card anyway.
if (pci_channel_offline(phba->pcidev))
return;
+ memset(&portsmphr_reg, 0, sizeof(portsmphr_reg));
if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
switch (if_type) {
case LPFC_SLI_INTF_IF_TYPE_0:
/* consider PCI bus read error as pci_channel_offline */
if (pci_rd_rc1 == -EIO && pci_rd_rc2 == -EIO)
return;
+ if (!(phba->hba_flag & HBA_RECOVERABLE_UE)) {
+ lpfc_sli4_offline_eratt(phba);
+ return;
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "7623 Checking UE recoverable");
+
+ for (i = 0; i < phba->sli4_hba.ue_to_sr / 1000; i++) {
+ if (lpfc_readl(phba->sli4_hba.PSMPHRregaddr,
+ &portsmphr_reg.word0))
+ continue;
+
+ smphr_port_status = bf_get(lpfc_port_smphr_port_status,
+ &portsmphr_reg);
+ if ((smphr_port_status & LPFC_PORT_SEM_MASK) ==
+ LPFC_PORT_SEM_UE_RECOVERABLE)
+ break;
+ /*Sleep for 1Sec, before checking SEMAPHORE */
+ msleep(1000);
+ }
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "4827 smphr_port_status x%x : Waited %dSec",
+ smphr_port_status, i);
+
+ /* Recoverable UE, reset the HBA device */
+ if ((smphr_port_status & LPFC_PORT_SEM_MASK) ==
+ LPFC_PORT_SEM_UE_RECOVERABLE) {
+ for (i = 0; i < 20; i++) {
+ msleep(1000);
+ if (!lpfc_readl(phba->sli4_hba.PSMPHRregaddr,
+ &portsmphr_reg.word0) &&
+ (LPFC_POST_STAGE_PORT_READY ==
+ bf_get(lpfc_port_smphr_port_status,
+ &portsmphr_reg))) {
+ rc = lpfc_sli4_port_sta_fn_reset(phba,
+ LPFC_MBX_NO_WAIT, en_rn_msg);
+ if (rc == 0)
+ return;
+ lpfc_printf_log(phba,
+ KERN_ERR, LOG_INIT,
+ "4215 Failed to recover UE");
+ break;
+ }
+ }
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "7624 Firmware not ready: Failing UE recovery,"
+ " waited %dSec", i);
lpfc_sli4_offline_eratt(phba);
break;
goto out_free_bsmbx;
}
}
+
/*
* Get sli4 parameters that override parameters from Port capabilities.
* If this call fails, it isn't critical unless the SLI4 parameters come
kfree(phba);
return NULL;
}
+ phba->eratt_poll_interval = LPFC_ERATT_POLL_INTERVAL;
spin_lock_init(&phba->ct_ev_lock);
INIT_LIST_HEAD(&phba->ct_ev_waiters);
else
cnt = (sli_intr - phba->sli.slistat.sli_prev_intr);
- /* 64-bit integer division not supporte on 32-bit x86 - use do_div */
- do_div(cnt, LPFC_ERATT_POLL_INTERVAL);
+ /* 64-bit integer division not supported on 32-bit x86 - use do_div */
+ do_div(cnt, phba->eratt_poll_interval);
phba->sli.slistat.sli_ips = cnt;
phba->sli.slistat.sli_prev_intr = sli_intr;
/* Restart the timer for next eratt poll */
mod_timer(&phba->eratt_poll,
jiffies +
- msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL));
+ msecs_to_jiffies(1000 * phba->eratt_poll_interval));
return;
}
return rc;
}
+void
+lpfc_set_features(struct lpfc_hba *phba)
+{
+ LPFC_MBOXQ_t *mbox = NULL;
+ uint32_t len;
+ int rc;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ return;
+ len = sizeof(struct lpfc_mbx_set_feature) -
+ sizeof(struct lpfc_sli4_cfg_mhdr);
+ lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+ LPFC_MBOX_OPCODE_SET_FEATURES, len,
+ LPFC_SLI4_MBX_EMBED);
+ bf_set(lpfc_mbx_set_feature_UER,
+ &mbox->u.mqe.un.set_feature, 1);
+ mbox->u.mqe.un.set_feature.feature = LPFC_SET_UE_RECOVERY;
+ mbox->u.mqe.un.set_feature.param_len = 8;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+
+ if (rc != MBX_SUCCESS) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return;
+ }
+ phba->hba_flag |= HBA_RECOVERABLE_UE;
+ phba->eratt_poll_interval = 1; /* Set 1Sec interval to detect UE */
+ phba->sli4_hba.ue_to_sr = bf_get(lpfc_mbx_set_feature_UESR,
+ &mbox->u.mqe.un.set_feature);
+ phba->sli4_hba.ue_to_rp = bf_get(lpfc_mbx_set_feature_UERP,
+ &mbox->u.mqe.un.set_feature);
+ mempool_free(mbox, phba->mbox_mem_pool);
+}
+
/**
* lpfc_sli4_alloc_resource_identifiers - Allocate all SLI4 resource extents.
* @phba: Pointer to HBA context object.
phba->pport->cfg_lun_queue_depth = rc;
}
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_0)
+ lpfc_set_features(phba);
/*
* Discover the port's supported feature set and match it against the
/* Start error attention (ERATT) polling timer */
mod_timer(&phba->eratt_poll,
- jiffies + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL));
+ jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval));
/* Enable PCIe device Advanced Error Reporting (AER) if configured */
if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) {