diff options
author | James Smart <james.smart@emulex.com> | 2010-12-15 17:57:46 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-12-21 12:37:23 -0600 |
commit | 2fcee4bf874a8ae72ada68b62728d1fdeb30e3d4 (patch) | |
tree | 8664c529ffcc3e6967e55116b375ff078a455b8b /drivers/scsi/lpfc | |
parent | 70f3c073362ef7b5e55c92b83eb2dd9a7fb4e9bf (diff) |
[SCSI] lpfc 8.3.20: Implement new SLI4 init procedures based on if_type
Implement new SLI4 init procedures based on if_type:
- Add structure changes for new SLIPORT registers and BAR changes.
- Update register names to be consistent with inteface spec terms.
- Added union to encapsulate Hardward error registers.
- Rework lpfc_sli4_post_status_check() around SLI-4's SLI_INTF type
- Removed the lpfc_sli4_fw_cfg_check routine
- Segmented driver logic to include evaluation of the if_type to
engage different behaviors.
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 108 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 660 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 77 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 50 |
4 files changed, 569 insertions, 326 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 3821ecbf5a8f..94c1aa1136de 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -460,42 +460,41 @@ struct lpfc_register { uint32_t word0; }; -/* The SLI4 INTF register offset is common to all if_type values. */ -#define LPFC_SLI_INTF 0x0058 - /* 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_UE_MASK_HI 0x00AC #define LPFC_UE_MASK_LO 0x00A8 -#define LPFC_HST_STATE 0x00AC -#define lpfc_hst_state_perr_SHIFT 31 -#define lpfc_hst_state_perr_MASK 0x1 -#define lpfc_hst_state_perr_WORD word0 -#define lpfc_hst_state_sfi_SHIFT 30 -#define lpfc_hst_state_sfi_MASK 0x1 -#define lpfc_hst_state_sfi_WORD word0 -#define lpfc_hst_state_nip_SHIFT 29 -#define lpfc_hst_state_nip_MASK 0x1 -#define lpfc_hst_state_nip_WORD word0 -#define lpfc_hst_state_ipc_SHIFT 28 -#define lpfc_hst_state_ipc_MASK 0x1 -#define lpfc_hst_state_ipc_WORD word0 -#define lpfc_hst_state_xrom_SHIFT 27 -#define lpfc_hst_state_xrom_MASK 0x1 -#define lpfc_hst_state_xrom_WORD word0 -#define lpfc_hst_state_dl_SHIFT 26 -#define lpfc_hst_state_dl_MASK 0x1 -#define lpfc_hst_state_dl_WORD word0 -#define lpfc_hst_state_port_status_SHIFT 0 -#define lpfc_hst_state_port_status_MASK 0xFFFF -#define lpfc_hst_state_port_status_WORD word0 +/* The following BAR0 register sets are defined for if_type 0 and 2 UCNAs. */ +#define LPFC_SLI_INTF 0x0058 + +#define LPFC_SLIPORT_IF2_SMPHR 0x0400 +#define lpfc_port_smphr_perr_SHIFT 31 +#define lpfc_port_smphr_perr_MASK 0x1 +#define lpfc_port_smphr_perr_WORD word0 +#define lpfc_port_smphr_sfi_SHIFT 30 +#define lpfc_port_smphr_sfi_MASK 0x1 +#define lpfc_port_smphr_sfi_WORD word0 +#define lpfc_port_smphr_nip_SHIFT 29 +#define lpfc_port_smphr_nip_MASK 0x1 +#define lpfc_port_smphr_nip_WORD word0 +#define lpfc_port_smphr_ipc_SHIFT 28 +#define lpfc_port_smphr_ipc_MASK 0x1 +#define lpfc_port_smphr_ipc_WORD word0 +#define lpfc_port_smphr_scr1_SHIFT 27 +#define lpfc_port_smphr_scr1_MASK 0x1 +#define lpfc_port_smphr_scr1_WORD word0 +#define lpfc_port_smphr_scr2_SHIFT 26 +#define lpfc_port_smphr_scr2_MASK 0x1 +#define lpfc_port_smphr_scr2_WORD word0 +#define lpfc_port_smphr_host_scratch_SHIFT 16 +#define lpfc_port_smphr_host_scratch_MASK 0xFF +#define lpfc_port_smphr_host_scratch_WORD word0 +#define lpfc_port_smphr_port_status_SHIFT 0 +#define lpfc_port_smphr_port_status_MASK 0xFFFF +#define lpfc_port_smphr_port_status_WORD word0 -/* - * The following Port Status Values apply to SLI4, if_type 0 and 2 - * UCNAs. - */ #define LPFC_POST_STAGE_POWER_ON_RESET 0x0000 #define LPFC_POST_STAGE_AWAITING_HOST_RDY 0x0001 #define LPFC_POST_STAGE_HOST_RDY 0x0002 @@ -527,36 +526,8 @@ struct lpfc_register { #define LPFC_POST_STAGE_RC_DONE 0x0B07 #define LPFC_POST_STAGE_REBOOT_SYSTEM 0x0B08 #define LPFC_POST_STAGE_MAC_ADDRESS 0x0C00 -#define LPFC_POST_STAGE_ARMFW_READY 0xC000 -#define LPFC_POST_STAGE_ARMFW_UE 0xF000 - - -/* The following BAR0 register sets are defined for if_type 2 UCNAs. */ -#define LPFC_SLIPORT_SEMAPHORE 0x0400 -#define lpfc_sliport_smphr_perr_SHIFT 31 -#define lpfc_sliport_smphr_perr_MASK 0x1 -#define lpfc_sliport_smphr_perr_WORD word0 -#define lpfc_sliport_smphr_sfi_SHIFT 30 -#define lpfc_sliport_smphr_sfi_MASK 0x1 -#define lpfc_sliport_smphr_sfi_WORD word0 -#define lpfc_sliport_smphr_nip_SHIFT 29 -#define lpfc_sliport_smphr_nip_MASK 0x1 -#define lpfc_sliport_smphr_nip_WORD word0 -#define lpfc_sliport_smphr_ipc_SHIFT 28 -#define lpfc_sliport_smphr_ipc_MASK 0x1 -#define lpfc_sliport_smphr_ipc_WORD word0 -#define lpfc_sliport_smphr_scr1_SHIFT 27 -#define lpfc_sliport_smphr_scr1_MASK 0x1 -#define lpfc_sliport_smphr_scr1_WORD word0 -#define lpfc_sliport_smphr_scr2_SHIFT 26 -#define lpfc_sliport_smphr_scr2_MASK 0x1 -#define lpfc_sliport_smphr_scr2_WORD word0 -#define lpfc_sliport_smphr_host_scratch_SHIFT 16 -#define lpfc_sliport_smphr_host_scratch_MASK 0xFF -#define lpfc_sliport_smphr_host_scratch_WORD word0 -#define lpfc_sliport_smphr_port_status_SHIFT 0 -#define lpfc_sliport_smphr_port_status_MASK 0xFFFF -#define lpfc_sliport_smphr_port_status_WORD word0 +#define LPFC_POST_STAGE_PORT_READY 0xC000 +#define LPFC_POST_STAGE_PORT_UE 0xF000 #define LPFC_SLIPORT_STATUS 0x0404 #define lpfc_sliport_status_err_SHIFT 31 @@ -574,8 +545,9 @@ struct lpfc_register { #define lpfc_sliport_status_rdy_SHIFT 23 #define lpfc_sliport_status_rdy_MASK 0x1 #define lpfc_sliport_status_rdy_WORD word0 +#define MAX_IF_TYPE_2_RESETS 1000 -#define LPFC_SLIPORT_CONTROL 0x0408 +#define LPFC_SLIPORT_CNTRL 0x0408 #define lpfc_sliport_ctrl_end_SHIFT 30 #define lpfc_sliport_ctrl_end_MASK 0x1 #define lpfc_sliport_ctrl_end_WORD word0 @@ -584,11 +556,16 @@ struct lpfc_register { #define lpfc_sliport_ctrl_ip_SHIFT 27 #define lpfc_sliport_ctrl_ip_MASK 0x1 #define lpfc_sliport_ctrl_ip_WORD word0 +#define LPFC_SLIPORT_INIT_PORT 1 -#define LPFC_SLIPORT_ERROR_1 0x040C -#define LPFC_SLIPORT_ERROR_2 0x0410 +#define LPFC_SLIPORT_ERR_1 0x040C +#define LPFC_SLIPORT_ERR_2 0x0410 + +/* The following Registers apply to SLI4 if_type 0 UCNAs. They typically + * reside in BAR 2. + */ +#define LPFC_SLIPORT_IF0_SMPHR 0x00AC -/* BAR1 Registers */ #define LPFC_IMR_MASK_ALL 0xFFFFFFFF #define LPFC_ISCR_CLEAR_ALL 0xFFFFFFFF @@ -647,7 +624,7 @@ struct lpfc_register { * The Doorbell registers defined here exist in different BAR * register sets depending on the UCNA Port's reported if_type * value. For UCNA ports running SLI4 and if_type 0, they reside in - * BAR2. For UCNA ports running SLI4 and if_type 2, they reside in + * BAR4. For UCNA ports running SLI4 and if_type 2, they reside in * BAR0. The offsets are the same so the driver must account for * any base address difference. */ @@ -2378,7 +2355,7 @@ struct wqe_common { #define wqe_rcvoxid_WORD word9 uint32_t word10; #define wqe_ebde_cnt_SHIFT 0 -#define wqe_ebde_cnt_MASK 0x00000007 +#define wqe_ebde_cnt_MASK 0x0000000f #define wqe_ebde_cnt_WORD word10 #define wqe_lenloc_SHIFT 7 #define wqe_lenloc_MASK 0x00000003 @@ -2570,7 +2547,6 @@ struct xmit_seq64_wqe { uint32_t relative_offset; struct wqe_rctl_dfctl wge_ctl; struct wqe_common wqe_com; /* words 6-11 */ - /* Note: word10 different REVISIT */ uint32_t xmit_len; uint32_t rsvd_12_15[3]; }; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 311671d3216f..462242dcdd0a 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1406,6 +1406,8 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) struct lpfc_vport *vport = phba->pport; uint32_t event_data; struct Scsi_Host *shost; + uint32_t if_type; + struct lpfc_register portstat_reg; /* If the pci channel is offline, ignore possible errors, since * we cannot communicate with the pci card anyway. @@ -1422,17 +1424,49 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) /* For now, the actual action for SLI4 device handling is not * specified yet, just treated it as adaptor hardware failure */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0143 SLI4 Adapter Hardware Error Data: x%x x%x\n", - phba->work_status[0], phba->work_status[1]); - event_data = FC_REG_DUMP_EVENT; shost = lpfc_shost_from_vport(vport); fc_host_post_vendor_event(shost, fc_get_event_number(), sizeof(event_data), (char *) &event_data, SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); - lpfc_sli4_offline_eratt(phba); + if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); + switch (if_type) { + case LPFC_SLI_INTF_IF_TYPE_0: + lpfc_sli4_offline_eratt(phba); + break; + case LPFC_SLI_INTF_IF_TYPE_2: + portstat_reg.word0 = + readl(phba->sli4_hba.u.if_type2.STATUSregaddr); + + if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) { + /* TODO: Register for Overtemp async events. */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2889 Port Overtemperature event, " + "taking port\n"); + spin_lock_irq(&phba->hbalock); + phba->over_temp_state = HBA_OVER_TEMP; + spin_unlock_irq(&phba->hbalock); + lpfc_sli4_offline_eratt(phba); + return; + } + if (bf_get(lpfc_sliport_status_rn, &portstat_reg)) { + /* + * TODO: Attempt port recovery via a port reset. + * When fully implemented, the driver should + * attempt to recover the port here and return. + * For now, log an error and take the port offline. + */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2887 Port Error: Attempting " + "Port Recovery\n"); + } + lpfc_sli4_offline_eratt(phba); + break; + case LPFC_SLI_INTF_IF_TYPE_1: + default: + break; + } } /** @@ -2983,63 +3017,6 @@ lpfc_sli4_fcf_redisc_wait_tmo(unsigned long ptr) } /** - * lpfc_sli4_fw_cfg_check - Read the firmware config and verify FCoE support - * @phba: pointer to lpfc hba data structure. - * - * This function uses the QUERY_FW_CFG mailbox command to determine if the - * firmware loaded supports FCoE. A return of zero indicates that the mailbox - * was successful and the firmware supports FCoE. Any other return indicates - * a error. It is assumed that this function will be called before interrupts - * are enabled. - **/ -static int -lpfc_sli4_fw_cfg_check(struct lpfc_hba *phba) -{ - int rc = 0; - LPFC_MBOXQ_t *mboxq; - struct lpfc_mbx_query_fw_cfg *query_fw_cfg; - uint32_t length; - uint32_t shdr_status, shdr_add_status; - - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2621 Failed to allocate mbox for " - "query firmware config cmd\n"); - return -ENOMEM; - } - query_fw_cfg = &mboxq->u.mqe.un.query_fw_cfg; - length = (sizeof(struct lpfc_mbx_query_fw_cfg) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_QUERY_FW_CFG, - length, LPFC_SLI4_MBX_EMBED); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr_status = bf_get(lpfc_mbox_hdr_status, - &query_fw_cfg->header.cfg_shdr.response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &query_fw_cfg->header.cfg_shdr.response); - if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2622 Query Firmware Config failed " - "mbx status x%x, status x%x add_status x%x\n", - rc, shdr_status, shdr_add_status); - return -EINVAL; - } - if (!bf_get(lpfc_function_mode_fcoe_i, query_fw_cfg)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2623 FCoE Function not supported by firmware. " - "Function mode = %08x\n", - query_fw_cfg->function_mode); - return -EINVAL; - } - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); - return 0; -} - -/** * lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code * @phba: pointer to lpfc hba data structure. * @acqe_link: pointer to the async link completion queue entry. @@ -4268,6 +4245,14 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) if (rc) return -ENOMEM; + /* IF Type 2 ports get initialized now. */ + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_2) { + rc = lpfc_pci_function_reset(phba); + if (unlikely(rc)) + return -ENODEV; + } + /* Create the bootstrap mailbox command */ rc = lpfc_create_bootstrap_mbox(phba); if (unlikely(rc)) @@ -4278,19 +4263,18 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) if (unlikely(rc)) goto out_free_bsmbx; - rc = lpfc_sli4_fw_cfg_check(phba); - if (unlikely(rc)) - goto out_free_bsmbx; - /* Set up the hba's configuration parameters. */ rc = lpfc_sli4_read_config(phba); if (unlikely(rc)) goto out_free_bsmbx; - /* Perform a function reset */ - rc = lpfc_pci_function_reset(phba); - if (unlikely(rc)) - goto out_free_bsmbx; + /* IF Type 0 ports get initialized now. */ + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_0) { + rc = lpfc_pci_function_reset(phba); + if (unlikely(rc)) + goto out_free_bsmbx; + } mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -5388,49 +5372,51 @@ lpfc_sli_pci_mem_unset(struct lpfc_hba *phba) int lpfc_sli4_post_status_check(struct lpfc_hba *phba) { - struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg; - int i, port_error = -ENODEV; + struct lpfc_register portsmphr_reg, uerrlo_reg, uerrhi_reg; + struct lpfc_register reg_data; + int i, port_error = 0; + uint32_t if_type; - if (!phba->sli4_hba.STAregaddr) + if (!phba->sli4_hba.PSMPHRregaddr) return -ENODEV; /* Wait up to 30 seconds for the SLI Port POST done and ready */ for (i = 0; i < 3000; i++) { - sta_reg.word0 = readl(phba->sli4_hba.STAregaddr); - /* Encounter fatal POST error, break out */ - if (bf_get(lpfc_hst_state_perr, &sta_reg)) { + portsmphr_reg.word0 = readl(phba->sli4_hba.PSMPHRregaddr); + if (bf_get(lpfc_port_smphr_perr, &portsmphr_reg)) { + /* Port has a fatal POST error, break out */ port_error = -ENODEV; break; } - if (LPFC_POST_STAGE_ARMFW_READY == - bf_get(lpfc_hst_state_port_status, &sta_reg)) { - port_error = 0; + if (LPFC_POST_STAGE_PORT_READY == + bf_get(lpfc_port_smphr_port_status, &portsmphr_reg)) break; - } msleep(10); } - if (port_error) + /* + * If there was a port error during POST, then don't proceed with + * other register reads as the data may not be valid. Just exit. + */ + if (port_error) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1408 Failure HBA POST Status: sta_reg=0x%x, " - "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, xrom=x%x, " - "dl=x%x, pstatus=x%x\n", sta_reg.word0, - bf_get(lpfc_hst_state_perr, &sta_reg), - bf_get(lpfc_hst_state_sfi, &sta_reg), - bf_get(lpfc_hst_state_nip, &sta_reg), - bf_get(lpfc_hst_state_ipc, &sta_reg), - bf_get(lpfc_hst_state_xrom, &sta_reg), - bf_get(lpfc_hst_state_dl, &sta_reg), - bf_get(lpfc_hst_state_port_status, &sta_reg)); - - /* Log device information */ - phba->sli4_hba.sli_intf.word0 = readl(phba->sli4_hba.SLIINTFregaddr); - if (bf_get(lpfc_sli_intf_valid, - &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_VALID) { + "1408 Port Failed POST - portsmphr=0x%x, " + "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, scr1=x%x, " + "scr2=x%x, hscratch=x%x, pstatus=x%x\n", + portsmphr_reg.word0, + bf_get(lpfc_port_smphr_perr, &portsmphr_reg), + bf_get(lpfc_port_smphr_sfi, &portsmphr_reg), + bf_get(lpfc_port_smphr_nip, &portsmphr_reg), + bf_get(lpfc_port_smphr_ipc, &portsmphr_reg), + bf_get(lpfc_port_smphr_scr1, &portsmphr_reg), + bf_get(lpfc_port_smphr_scr2, &portsmphr_reg), + bf_get(lpfc_port_smphr_host_scratch, &portsmphr_reg), + bf_get(lpfc_port_smphr_port_status, &portsmphr_reg)); + } else { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2534 Device Info: ChipType=0x%x, SliRev=0x%x, " - "IFType=0x%x, SLIHint_1=0x%x, SLIHint_2=0x%x, " - "FT=0x%x\n", + "2534 Device Info: SLIFamily=0x%x, " + "SLIRev=0x%x, IFType=0x%x, SLIHint_1=0x%x, " + "SLIHint_2=0x%x, FT=0x%x\n", bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf), bf_get(lpfc_sli_intf_slirev, @@ -5443,48 +5429,126 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) &phba->sli4_hba.sli_intf), bf_get(lpfc_sli_intf_func_type, &phba->sli4_hba.sli_intf)); + /* + * Check for other Port errors during the initialization + * process. Fail the load if the port did not come up + * correctly. + */ + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + switch (if_type) { + case LPFC_SLI_INTF_IF_TYPE_0: + phba->sli4_hba.ue_mask_lo = + readl(phba->sli4_hba.u.if_type0.UEMASKLOregaddr); + phba->sli4_hba.ue_mask_hi = + readl(phba->sli4_hba.u.if_type0.UEMASKHIregaddr); + uerrlo_reg.word0 = + readl(phba->sli4_hba.u.if_type0.UERRLOregaddr); + uerrhi_reg.word0 = + readl(phba->sli4_hba.u.if_type0.UERRHIregaddr); + if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) || + (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1422 Unrecoverable Error " + "Detected during POST " + "uerr_lo_reg=0x%x, " + "uerr_hi_reg=0x%x, " + "ue_mask_lo_reg=0x%x, " + "ue_mask_hi_reg=0x%x\n", + uerrlo_reg.word0, + uerrhi_reg.word0, + phba->sli4_hba.ue_mask_lo, + phba->sli4_hba.ue_mask_hi); + port_error = -ENODEV; + } + break; + case LPFC_SLI_INTF_IF_TYPE_2: + /* Final checks. The port status should be clean. */ + reg_data.word0 = + readl(phba->sli4_hba.u.if_type2.STATUSregaddr); + if (bf_get(lpfc_sliport_status_err, ®_data)) { + phba->work_status[0] = + readl(phba->sli4_hba.u.if_type2. + ERR1regaddr); + phba->work_status[1] = + readl(phba->sli4_hba.u.if_type2. + ERR2regaddr); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2888 Port Error Detected " + "during POST: " + "port status reg 0x%x, " + "port_smphr reg 0x%x, " + "error 1=0x%x, error 2=0x%x\n", + reg_data.word0, + portsmphr_reg.word0, + phba->work_status[0], + phba->work_status[1]); + port_error = -ENODEV; + } + break; + case LPFC_SLI_INTF_IF_TYPE_1: + default: + break; + } } - - phba->sli4_hba.ue_mask_lo = readl(phba->sli4_hba.UEMASKLOregaddr); - phba->sli4_hba.ue_mask_hi = readl(phba->sli4_hba.UEMASKHIregaddr); - /* With uncoverable error, log the error message and return error */ - uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr); - uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr); - if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) || - (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1422 HBA Unrecoverable error: " - "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " - "ue_mask_lo_reg=0x%x, ue_mask_hi_reg=0x%x\n", - uerrlo_reg.word0, uerrhi_reg.word0, - phba->sli4_hba.ue_mask_lo, - phba->sli4_hba.ue_mask_hi); - return -ENODEV; - } - return port_error; } /** * lpfc_sli4_bar0_register_memmap - Set up SLI4 BAR0 register memory map. * @phba: pointer to lpfc hba data structure. + * @if_type: The SLI4 interface type getting configured. * * This routine is invoked to set up SLI4 BAR0 PCI config space register * memory map. **/ static void -lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba) -{ - phba->sli4_hba.UERRLOregaddr = phba->sli4_hba.conf_regs_memmap_p + - LPFC_UERR_STATUS_LO; - phba->sli4_hba.UERRHIregaddr = phba->sli4_hba.conf_regs_memmap_p + - LPFC_UERR_STATUS_HI; - phba->sli4_hba.UEMASKLOregaddr = phba->sli4_hba.conf_regs_memmap_p + - LPFC_UE_MASK_LO; - phba->sli4_hba.UEMASKHIregaddr = phba->sli4_hba.conf_regs_memmap_p + - LPFC_UE_MASK_HI; - phba->sli4_hba.SLIINTFregaddr = phba->sli4_hba.conf_regs_memmap_p + - LPFC_SLI_INTF; +lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type) +{ + switch (if_type) { + case LPFC_SLI_INTF_IF_TYPE_0: + phba->sli4_hba.u.if_type0.UERRLOregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_UERR_STATUS_LO; + phba->sli4_hba.u.if_type0.UERRHIregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_UERR_STATUS_HI; + phba->sli4_hba.u.if_type0.UEMASKLOregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_UE_MASK_LO; + phba->sli4_hba.u.if_type0.UEMASKHIregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_UE_MASK_HI; + phba->sli4_hba.SLIINTFregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF; + break; + case LPFC_SLI_INTF_IF_TYPE_2: + phba->sli4_hba.u.if_type2.ERR1regaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_1; + phba->sli4_hba.u.if_type2.ERR2regaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_2; + phba->sli4_hba.u.if_type2.CTRLregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_CNTRL; + phba->sli4_hba.u.if_type2.STATUSregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_STATUS; + phba->sli4_hba.SLIINTFregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF; + phba->sli4_hba.PSMPHRregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_IF2_SMPHR; + phba->sli4_hba.RQDBregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL; + phba->sli4_hba.WQDBregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_WQ_DOORBELL; + phba->sli4_hba.EQCQDBregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_EQCQ_DOORBELL; + phba->sli4_hba.MQDBregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_MQ_DOORBELL; + phba->sli4_hba.BMBXregaddr = + phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX; + break; + case LPFC_SLI_INTF_IF_TYPE_1: + default: + dev_printk(KERN_ERR, &phba->pcidev->dev, + "FATAL - unsupported SLI4 interface type - %d\n", + if_type); + break; + } } /** @@ -5497,16 +5561,14 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba) static void lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba) { - - phba->sli4_hba.STAregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_STATE; + phba->sli4_hba.PSMPHRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + + LPFC_SLIPORT_IF0_SMPHR; phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_ISR0; + LPFC_HST_ISR0; phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_IMR0; + LPFC_HST_IMR0; phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_ISCR0; - return; + LPFC_HST_ISCR0; } /** @@ -5746,11 +5808,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) } /** - * lpfc_dev_endian_order_setup - Notify the port of the host's endian order. + * lpfc_setup_endian_order - Write endian order to an SLI4 if_type 0 port. * @phba: pointer to lpfc hba data structure. * - * This routine is invoked to setup the host-side endian order to the - * HBA consistent with the SLI-4 interface spec. + * This routine is invoked to setup the port-side endian order when + * the port if_type is 0. This routine has no function for other + * if_types. * * Return codes * 0 - successful @@ -5761,34 +5824,44 @@ static int lpfc_setup_endian_order(struct lpfc_hba *phba) { LPFC_MBOXQ_t *mboxq; - uint32_t rc = 0; + uint32_t if_type, rc = 0; uint32_t endian_mb_data[2] = {HOST_ENDIAN_LOW_WORD0, HOST_ENDIAN_HIGH_WORD1}; - mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0492 Unable to allocate memory for issuing " - "SLI_CONFIG_SPECIAL mailbox command\n"); - return -ENOMEM; - } + if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); + switch (if_type) { + case LPFC_SLI_INTF_IF_TYPE_0: + mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0492 Unable to allocate memory for " + "issuing SLI_CONFIG_SPECIAL mailbox " + "command\n"); + return -ENOMEM; + } - /* - * The SLI4_CONFIG_SPECIAL mailbox command requires the first two - * words to contain special data values and no other data. - */ - memset(mboxq, 0, sizeof(LPFC_MBOXQ_t)); - memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data)); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0493 SLI_CONFIG_SPECIAL mailbox failed with " - "status x%x\n", - rc); - rc = -EIO; + /* + * The SLI4_CONFIG_SPECIAL mailbox command requires the first + * two words to contain special data values and no other data. + */ + memset(mboxq, 0, sizeof(LPFC_MBOXQ_t)); + memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data)); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0493 SLI_CONFIG_SPECIAL mailbox " + "failed with status x%x\n", + rc); + rc = -EIO; + } + mempool_free(mboxq, phba->mbox_mem_pool); + break; + case LPFC_SLI_INTF_IF_TYPE_2: + case LPFC_SLI_INTF_IF_TYPE_1: + default: + break; } - - mempool_free(mboxq, phba->mbox_mem_pool); return rc; } @@ -6620,36 +6693,124 @@ int lpfc_pci_function_reset(struct lpfc_hba *phba) { LPFC_MBOXQ_t *mboxq; - uint32_t rc = 0; + uint32_t rc = 0, if_type; uint32_t shdr_status, shdr_add_status; + uint32_t rdy_chk, num_resets = 0, reset_again = 0; union lpfc_sli4_cfg_shdr *shdr; + struct lpfc_register reg_data; - mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0494 Unable to allocate memory for issuing " - "SLI_FUNCTION_RESET mailbox command\n"); - return -ENOMEM; - } + if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); + switch (if_type) { + case LPFC_SLI_INTF_IF_TYPE_0: + mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0494 Unable to allocate memory for " + "issuing SLI_FUNCTION_RESET mailbox " + "command\n"); + return -ENOMEM; + } - /* Set up PCI function reset SLI4_CONFIG mailbox-ioctl command */ - lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_FUNCTION_RESET, 0, - LPFC_SLI4_MBX_EMBED); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) - &mboxq->u.mqe.un.sli4_config.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0495 SLI_FUNCTION_RESET mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; + /* Setup PCI function reset mailbox-ioctl command */ + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_FUNCTION_RESET, 0, + LPFC_SLI4_MBX_EMBED); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + shdr = (union lpfc_sli4_cfg_shdr *) + &mboxq->u.mqe.un.sli4_config.header.cfg_shdr; + shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, + &shdr->response); + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); + if (shdr_status || shdr_add_status || rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0495 SLI_FUNCTION_RESET mailbox " + "failed with status x%x add_status x%x," + " mbx status x%x\n", + shdr_status, shdr_add_status, rc); + rc = -ENXIO; + } + break; + case LPFC_SLI_INTF_IF_TYPE_2: + for (num_resets = 0; + num_resets < MAX_IF_TYPE_2_RESETS; + num_resets++) { + reg_data.word0 = 0; + bf_set(lpfc_sliport_ctrl_end, ®_data, + LPFC_SLIPORT_LITTLE_ENDIAN); + bf_set(lpfc_sliport_ctrl_ip, ®_data, + LPFC_SLIPORT_INIT_PORT); + writel(reg_data.word0, phba->sli4_hba.u.if_type2. + CTRLregaddr); + + /* + * Poll the Port Status Register and wait for RDY for + * up to 10 seconds. If the port doesn't respond, treat + * it as an error. If the port responds with RN, start + * the loop again. + */ + for (rdy_chk = 0; rdy_chk < 1000; rdy_chk++) { + reg_data.word0 = + readl(phba->sli4_hba.u.if_type2. + STATUSregaddr); + if (bf_get(lpfc_sliport_status_rdy, ®_data)) + break; + if (bf_get(lpfc_sliport_status_rn, ®_data)) { + reset_again++; + break; + } + msleep(10); + } + + /* + * If the port responds to the init request with + * reset needed, delay for a bit and restart the loop. + */ + if (reset_again) { + msleep(10); + reset_again = 0; + continue; + } + + /* Detect any port errors. */ + reg_data.word0 = readl(phba->sli4_hba.u.if_type2. + STATUSregaddr); + if ((bf_get(lpfc_sliport_status_err, ®_data)) || + (rdy_chk >= 1000)) { + phba->work_status[0] = readl( + phba->sli4_hba.u.if_type2.ERR1regaddr); + phba->work_status[1] = readl( + phba->sli4_hba.u.if_type2.ERR2regaddr); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2890 Port Error Detected " + "during Port Reset: " + "port status reg 0x%x, " + "error 1=0x%x, error 2=0x%x\n", + reg_data.word0, + phba->work_status[0], + phba->work_status[1]); + rc = -ENODEV; + } + + /* + * Terminate the outer loop provided the Port indicated + * ready within 10 seconds. + */ + if (rdy_chk < 1000) + break; + } + break; + case LPFC_SLI_INTF_IF_TYPE_1: + default: + break; } + + /* Catch the not-ready port failure after a port reset. */ + if (num_resets >= MAX_IF_TYPE_2_RESETS) + rc = -ENODEV; + return rc; } @@ -6740,6 +6901,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) struct pci_dev *pdev; unsigned long bar0map_len, bar1map_len, bar2map_len; int error = -ENODEV; + uint32_t if_type; /* Obtain PCI device reference */ if (!phba->pcidev) @@ -6756,61 +6918,105 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) } } - /* Get the bus address of SLI4 device Bar0, Bar1, and Bar2 and the - * number of bytes required by each mapping. They are actually - * mapping to the PCI BAR regions 0 or 1, 2, and 4 by the SLI4 device. + /* + * The BARs and register set definitions and offset locations are + * dependent on the if_type. + */ + if (pci_read_config_dword(pdev, LPFC_SLI_INTF, + &phba->sli4_hba.sli_intf.word0)) { + return error; + } + + /* There is no SLI3 failback for SLI4 devices. */ + if (bf_get(lpfc_sli_intf_valid, &phba->sli4_hba.sli_intf) != + LPFC_SLI_INTF_VALID) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2894 SLI_INTF reg contents invalid " + "sli_intf reg 0x%x\n", + phba->sli4_hba.sli_intf.word0); + return error; + } + + if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); + /* + * Get the bus address of SLI4 device Bar regions and the + * number of bytes required by each mapping. The mapping of the + * particular PCI BARs regions is dependent on the type of + * SLI4 device. */ if (pci_resource_start(pdev, 0)) { phba->pci_bar0_map = pci_resource_start(pdev, 0); bar0map_len = pci_resource_len(pdev, 0); + + /* + * Map SLI4 PCI Config Space Register base to a kernel virtual + * addr + */ + phba->sli4_hba.conf_regs_memmap_p = + ioremap(phba->pci_bar0_map, bar0map_len); + if (!phba->sli4_hba.conf_regs_memmap_p) { + dev_printk(KERN_ERR, &pdev->dev, + "ioremap failed for SLI4 PCI config " + "registers.\n"); + goto out; + } + /* Set up BAR0 PCI config space register memory map */ + lpfc_sli4_bar0_register_memmap(phba, if_type); } else { phba->pci_bar0_map = pci_resource_start(pdev, 1); bar0map_len = pci_resource_len(pdev, 1); - } - phba->pci_bar1_map = pci_resource_start(pdev, 2); - bar1map_len = pci_resource_len(pdev, 2); - - phba->pci_bar2_map = pci_resource_start(pdev, 4); - bar2map_len = pci_resource_len(pdev, 4); - - /* Map SLI4 PCI Config Space Register base to a kernel virtual addr */ - phba->sli4_hba.conf_regs_memmap_p = + if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { + dev_printk(KERN_ERR, &pdev->dev, + "FATAL - No BAR0 mapping for SLI4, if_type 2\n"); + goto out; + } + phba->sli4_hba.conf_regs_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len); - if (!phba->sli4_hba.conf_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for SLI4 PCI config registers.\n"); - goto out; + if (!phba->sli4_hba.conf_regs_memmap_p) { + dev_printk(KERN_ERR, &pdev->dev, + "ioremap failed for SLI4 PCI config " + "registers.\n"); + goto out; + } + lpfc_sli4_bar0_register_memmap(phba, if_type); } - /* Map SLI4 HBA Control Register base to a kernel virtual address. */ - phba->sli4_hba.ctrl_regs_memmap_p = + if (pci_resource_start(pdev, 2)) { + /* + * Map SLI4 if type 0 HBA Control Register base to a kernel + * virtual address and setup the registers. + */ + phba->pci_bar1_map = pci_resource_start(pdev, 2); + bar1map_len = pci_resource_len(pdev, 2); + phba->sli4_hba.ctrl_regs_memmap_p = ioremap(phba->pci_bar1_map, bar1map_len); - if (!phba->sli4_hba.ctrl_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, + if (!phba->sli4_hba.ctrl_regs_memmap_p) { + dev_printk(KERN_ERR, &pdev->dev, "ioremap failed for SLI4 HBA control registers.\n"); - goto out_iounmap_conf; + goto out_iounmap_conf; + } + lpfc_sli4_bar1_register_memmap(phba); } - /* Map SLI4 HBA Doorbell Register base to a kernel virtual address. */ - phba->sli4_hba.drbl_regs_memmap_p = + if (pci_resource_start(pdev, 4)) { + /* + * Map SLI4 if type 0 HBA Doorbell Register base to a kernel + * virtual address and setup the registers. + */ + phba->pci_bar2_map = pci_resource_start(pdev, 4); + bar2map_len = pci_resource_len(pdev, 4); + phba->sli4_hba.drbl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len); - if (!phba->sli4_hba.drbl_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, + if (!phba->sli4_hba.drbl_regs_memmap_p) { + dev_printk(KERN_ERR, &pdev->dev, "ioremap failed for SLI4 HBA doorbell registers.\n"); - goto out_iounmap_ctrl; + goto out_iounmap_ctrl; + } + error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0); + if (error) + goto out_iounmap_all; } - /* Set up BAR0 PCI config space register memory map */ - lpfc_sli4_bar0_register_memmap(phba); - - /* Set up BAR1 register memory map */ - lpfc_sli4_bar1_register_memmap(phba); - - /* Set up BAR2 register memory map */ - error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0); - if (error) - goto out_iounmap_all; - return 0; out_iounmap_all: @@ -8424,7 +8630,11 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const |