From 026abb87a5586c838a47aca7198d78e356b6351e Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 13 Dec 2011 13:20:45 -0500 Subject: [SCSI] lpfc 8.3.28: Miscellaneous fixes in sysfs and mgmt interfaces Miscellaneous fixes in sysfs and mgmt interfaces: - Added SLI4 INTF_TYPE and SLI_FAMILY as sub-field to the fwrev sysfs attribute (CR 124103) - Added a sysfs attribute "protocol" to report SLI4 port link protocol type (CR 124102) - Increment mix-and-match minor number by 1 for added "protocol" sysfs attribute. (124102) - Move the link speed check into the generic sli3/sli4 code path. (CR 124185, 124122) - Deleted check for inExtWLen (CR 122523) - Add the word "offline" to message 2889 (CR 124385) - Conditionalize the firmware upgrade/downgrade so that it is only attempted for SLI4 type 2 boards (CR 124406) - Return an error if the mbox sysfs is called. (CR 124210) - When port_state is less than LPFC_VPORT_READY, report FC_PORTSTATE_BYPASSED (CR 120018) - Added driver support for performing persistent linkdown based on configure region 23 (CR 124534) - Added restore state and error log when sysfs board_mode attribute access failed (CR 124158) - Added support for SLI4_CONFIG non-embedded COMN_GET_CNTL_ADDL_ATTR pass-through (CR 124466) - Rejecting un-supported multi-buffer mailbox commands (CR 124771) - Byte swap the extended data request and response data for extended mailbox data (CR 125081) Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_sli.c | 149 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 122 insertions(+), 27 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_sli.c') diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4d4104f38c98..1be13e757eda 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4566,7 +4566,7 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, phba->fc_map[2] = LPFC_FCOE_FCF_MAP2; mqe = &mboxq->u.mqe; - if (lpfc_dump_fcoe_param(phba, mboxq)) + if (lpfc_sli4_dump_cfg_rg23(phba, mboxq)) return -ENOMEM; mp = (struct lpfc_dmabuf *) mboxq->context1; @@ -6205,7 +6205,11 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = 0; phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi); + + /* Check if the port is configured to be disabled */ + lpfc_sli_read_link_ste(phba); } + /* * The port is ready, set the host's link state to LINK_DOWN * in preparation for link interrupts. @@ -6213,7 +6217,19 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); phba->link_state = LPFC_LINK_DOWN; spin_unlock_irq(&phba->hbalock); - if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { + if (!(phba->hba_flag & HBA_FCOE_MODE) && + (phba->hba_flag & LINK_DISABLED)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, + "3103 Adapter Link is disabled.\n"); + lpfc_down_link(phba, mboxq); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, + "3104 Adapter failed to issue " + "DOWN_LINK mbox cmd, rc:x%x\n", rc); + goto out_unset_queue; + } + } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); if (rc) goto out_unset_queue; @@ -15252,45 +15268,42 @@ lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *phba) } /** - * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled. + * lpfc_sli_get_config_region23 - Get sli3 port region 23 data. * @phba: pointer to lpfc hba data structure. + * @rgn23_data: pointer to configure region 23 data. * - * This function read region 23 and parse TLV for port status to - * decide if the user disaled the port. If the TLV indicates the - * port is disabled, the hba_flag is set accordingly. + * This function gets SLI3 port configure region 23 data through memory dump + * mailbox command. When it successfully retrieves data, the size of the data + * will be returned, otherwise, 0 will be returned. **/ -void -lpfc_sli_read_link_ste(struct lpfc_hba *phba) +static uint32_t +lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) { LPFC_MBOXQ_t *pmb = NULL; MAILBOX_t *mb; - uint8_t *rgn23_data = NULL; - uint32_t offset = 0, data_size, sub_tlv_len, tlv_offset; + uint32_t offset = 0; int rc; + if (!rgn23_data) + return 0; + pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2600 lpfc_sli_read_serdes_param failed to" - " allocate mailbox memory\n"); - goto out; + "2600 failed to allocate mailbox memory\n"); + return 0; } mb = &pmb->u.mb; - /* Get adapter Region 23 data */ - rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL); - if (!rgn23_data) - goto out; - do { lpfc_dump_mem(phba, pmb, offset, DMP_REGION_23); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2601 lpfc_sli_read_link_ste failed to" - " read config region 23 rc 0x%x Status 0x%x\n", - rc, mb->mbxStatus); + "2601 failed to read config " + "region 23, rc 0x%x Status 0x%x\n", + rc, mb->mbxStatus); mb->un.varDmp.word_cnt = 0; } /* @@ -15303,13 +15316,96 @@ lpfc_sli_read_link_ste(struct lpfc_hba *phba) mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset; lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - rgn23_data + offset, - mb->un.varDmp.word_cnt); + rgn23_data + offset, + mb->un.varDmp.word_cnt); offset += mb->un.varDmp.word_cnt; } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE); - data_size = offset; - offset = 0; + mempool_free(pmb, phba->mbox_mem_pool); + return offset; +} + +/** + * lpfc_sli4_get_config_region23 - Get sli4 port region 23 data. + * @phba: pointer to lpfc hba data structure. + * @rgn23_data: pointer to configure region 23 data. + * + * This function gets SLI4 port configure region 23 data through memory dump + * mailbox command. When it successfully retrieves data, the size of the data + * will be returned, otherwise, 0 will be returned. + **/ +static uint32_t +lpfc_sli4_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) +{ + LPFC_MBOXQ_t *mboxq = NULL; + struct lpfc_dmabuf *mp = NULL; + struct lpfc_mqe *mqe; + uint32_t data_length = 0; + int rc; + + if (!rgn23_data) + return 0; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3105 failed to allocate mailbox memory\n"); + return 0; + } + + if (lpfc_sli4_dump_cfg_rg23(phba, mboxq)) + goto out; + mqe = &mboxq->u.mqe; + mp = (struct lpfc_dmabuf *) mboxq->context1; + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (rc) + goto out; + data_length = mqe->un.mb_words[5]; + if (data_length == 0) + goto out; + if (data_length > DMP_RGN23_SIZE) { + data_length = 0; + goto out; + } + lpfc_sli_pcimem_bcopy((char *)mp->virt, rgn23_data, data_length); +out: + mempool_free(mboxq, phba->mbox_mem_pool); + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + return data_length; +} + +/** + * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled. + * @phba: pointer to lpfc hba data structure. + * + * This function read region 23 and parse TLV for port status to + * decide if the user disaled the port. If the TLV indicates the + * port is disabled, the hba_flag is set accordingly. + **/ +void +lpfc_sli_read_link_ste(struct lpfc_hba *phba) +{ + uint8_t *rgn23_data = NULL; + uint32_t if_type, data_size, sub_tlv_len, tlv_offset; + uint32_t offset = 0; + + /* Get adapter Region 23 data */ + rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL); + if (!rgn23_data) + goto out; + + if (phba->sli_rev < LPFC_SLI_REV4) + data_size = lpfc_sli_get_config_region23(phba, rgn23_data); + else { + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type == LPFC_SLI_INTF_IF_TYPE_0) + goto out; + data_size = lpfc_sli4_get_config_region23(phba, rgn23_data); + } if (!data_size) goto out; @@ -15373,9 +15469,8 @@ lpfc_sli_read_link_ste(struct lpfc_hba *phba) goto out; } } + out: - if (pmb) - mempool_free(pmb, phba->mbox_mem_pool); kfree(rgn23_data); return; } -- cgit v1.2.3 From ff78d8f97c85a568c0799b06137a4171db45b923 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 13 Dec 2011 13:21:35 -0500 Subject: [SCSI] lpfc 8.3.28: SLI fixes and added SLI4 support Adapter (SLI) interface fixes: - Modify WQ handling to use entry_repost (CR 123981) - Fix for ABTS. Do not free original IOCB whenever ABTS fails. (CR 115829) - Check board for FCoE before reading FCoE paramaters (CR124731) - Add support for SLI4 FC Loop mode (CR 124721) - Add support for resource count changes during fw reset. (CR 125888, 125675) - Increase CQE count from 256 to 1024. (CR 126149) Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 23 +++++ drivers/scsi/lpfc/lpfc_crtn.h | 2 + drivers/scsi/lpfc/lpfc_els.c | 18 ++-- drivers/scsi/lpfc/lpfc_hbadisc.c | 1 - drivers/scsi/lpfc/lpfc_init.c | 52 ++++++++--- drivers/scsi/lpfc/lpfc_sli.c | 184 +++++++++++++++++---------------------- drivers/scsi/lpfc/lpfc_sli4.h | 2 +- 7 files changed, 156 insertions(+), 126 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_sli.c') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 7bf492e156d9..f6697cb0e216 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -2777,6 +2777,14 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, if (val >= 0 && val <= 6) { prev_val = phba->cfg_topology; phba->cfg_topology = val; + if (phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G && + val == 4) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "3113 Loop mode not supported at speed %d\n", + phba->cfg_link_speed); + phba->cfg_topology = prev_val; + return -EINVAL; + } if (nolip) return strlen(buf); @@ -3222,6 +3230,14 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, val); return -EINVAL; } + if (val == LPFC_USER_LINK_SPEED_16G && + phba->fc_topology == LPFC_TOPOLOGY_LOOP) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3112 lpfc_link_speed attribute cannot be set " + "to %d. Speed is not supported in loop mode.\n", + val); + return -EINVAL; + } if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) && (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) { prev_val = phba->cfg_link_speed; @@ -3266,6 +3282,13 @@ lpfc_param_show(link_speed) static int lpfc_link_speed_init(struct lpfc_hba *phba, int val) { + if (val == LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3111 lpfc_link_speed of %d cannot " + "support loop mode, setting topology to default.\n", + val); + phba->cfg_topology = 0; + } if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) && (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) { phba->cfg_link_speed = val; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index f74afa23e0dd..9237ff154234 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -453,3 +453,5 @@ int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int); uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *); int lpfc_sli4_queue_create(struct lpfc_hba *); void lpfc_sli4_queue_destroy(struct lpfc_hba *); +int lpfc_sli4_read_config(struct lpfc_hba *phba); +int lpfc_scsi_buf_update(struct lpfc_hba *phba); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 445826a4c981..846ebfd37b5e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -909,15 +909,15 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ if (phba->alpa_map[0] == 0) { vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS; - if ((phba->sli_rev == LPFC_SLI_REV4) && - (!(vport->fc_flag & FC_VFI_REGISTERED) || - (vport->fc_prevDID != vport->fc_myDID))) { - if (vport->fc_flag & FC_VFI_REGISTERED) - lpfc_sli4_unreg_all_rpis(vport); - lpfc_issue_reg_vfi(vport); - lpfc_nlp_put(ndlp); - goto out; - } + } + if ((phba->sli_rev == LPFC_SLI_REV4) && + (!(vport->fc_flag & FC_VFI_REGISTERED) || + (vport->fc_prevDID != vport->fc_myDID))) { + if (vport->fc_flag & FC_VFI_REGISTERED) + lpfc_sli4_unreg_all_rpis(vport); + lpfc_issue_reg_vfi(vport); + lpfc_nlp_put(ndlp); + goto out; } goto flogifail; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 091f68e5cb70..cf4408f9a2cb 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -2858,7 +2858,6 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) if (vport->port_state == LPFC_FABRIC_CFG_LINK) { /* For private loop just start discovery and we are done. */ if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && - (phba->alpa_map[0] == 0) && !(vport->fc_flag & FC_PUBLIC_LOOP)) { /* Use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index d247eb015526..6096c9a091d1 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -62,7 +62,6 @@ static int lpfc_post_rcv_buf(struct lpfc_hba *); static int lpfc_sli4_queue_verify(struct lpfc_hba *); static int lpfc_create_bootstrap_mbox(struct lpfc_hba *); static int lpfc_setup_endian_order(struct lpfc_hba *); -static int lpfc_sli4_read_config(struct lpfc_hba *); static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *); static void lpfc_free_sgl_list(struct lpfc_hba *); static int lpfc_init_sgl_list(struct lpfc_hba *); @@ -2654,6 +2653,32 @@ lpfc_offline(struct lpfc_hba *phba) lpfc_destroy_vport_work_array(phba, vports); } +/** + * lpfc_scsi_buf_update - Update the scsi_buffers that are already allocated. + * @phba: pointer to lpfc hba data structure. + * + * This routine goes through all the scsi buffers in the system and updates the + * Physical XRIs assigned to the SCSI buffer because these may change after any + * firmware reset + * + * Return codes + * 0 - successful (for now, it always returns 0) + **/ +int +lpfc_scsi_buf_update(struct lpfc_hba *phba) +{ + struct lpfc_scsi_buf *sb, *sb_next; + + spin_lock_irq(&phba->hbalock); + spin_lock(&phba->scsi_buf_list_lock); + list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) + sb->cur_iocbq.sli4_xritag = + phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag]; + spin_unlock(&phba->scsi_buf_list_lock); + spin_unlock_irq(&phba->hbalock); + return 0; +} + /** * lpfc_scsi_free - Free all the SCSI buffers and IOCBs from driver lists * @phba: pointer to lpfc hba data structure. @@ -5021,15 +5046,8 @@ lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba) struct lpfc_rpi_hdr *rpi_hdr; INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_hdr_list); - /* - * If the SLI4 port supports extents, posting the rpi header isn't - * required. Set the expected maximum count and let the actual value - * get set when extents are fully allocated. - */ - if (!phba->sli4_hba.rpi_hdrs_in_use) { - phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.max_rpi; + if (!phba->sli4_hba.rpi_hdrs_in_use) return rc; - } if (phba->sli4_hba.extents_in_use) return -EIO; @@ -5923,7 +5941,7 @@ lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba) * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ -static int +int lpfc_sli4_read_config(struct lpfc_hba *phba) { LPFC_MBOXQ_t *pmb; @@ -5955,6 +5973,20 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) rc = -EIO; } else { rd_config = &pmb->u.mqe.un.rd_config; + if (bf_get(lpfc_mbx_rd_conf_lnk_ldv, rd_config)) { + phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_VAL; + phba->sli4_hba.lnk_info.lnk_tp = + bf_get(lpfc_mbx_rd_conf_lnk_type, rd_config); + phba->sli4_hba.lnk_info.lnk_no = + bf_get(lpfc_mbx_rd_conf_lnk_numb, rd_config); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3081 lnk_type:%d, lnk_numb:%d\n", + phba->sli4_hba.lnk_info.lnk_tp, + phba->sli4_hba.lnk_info.lnk_no); + } else + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3082 Mailbox (x%x) returned ldv:x0\n", + bf_get(lpfc_mqe_command, &pmb->u.mqe)); phba->sli4_hba.extents_in_use = bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config); phba->sli4_hba.max_cfg_param.max_xri = diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1be13e757eda..4c4d77356bb2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -97,7 +97,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) if (((q->host_index + 1) % q->entry_count) == q->hba_index) return -ENOMEM; /* set consumption flag every once in a while */ - if (!((q->host_index + 1) % LPFC_RELEASE_NOTIFICATION_INTERVAL)) + if (!((q->host_index + 1) % q->entry_repost)) bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); @@ -4551,9 +4551,9 @@ lpfc_sli_hba_setup_error: * data structure. **/ static int -lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, - LPFC_MBOXQ_t *mboxq) +lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba) { + LPFC_MBOXQ_t *mboxq; struct lpfc_dmabuf *mp; struct lpfc_mqe *mqe; uint32_t data_length; @@ -4565,10 +4565,16 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, phba->fc_map[1] = LPFC_FCOE_FCF_MAP1; phba->fc_map[2] = LPFC_FCOE_FCF_MAP2; - mqe = &mboxq->u.mqe; - if (lpfc_sli4_dump_cfg_rg23(phba, mboxq)) + mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) return -ENOMEM; + mqe = &mboxq->u.mqe; + if (lpfc_sli4_dump_cfg_rg23(phba, mboxq)) { + rc = -ENOMEM; + goto out_free_mboxq; + } + mp = (struct lpfc_dmabuf *) mboxq->context1; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); @@ -4596,19 +4602,25 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, if (rc) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - return -EIO; + rc = -EIO; + goto out_free_mboxq; } data_length = mqe->un.mb_words[5]; if (data_length > DMP_RGN23_SIZE) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - return -EIO; + rc = -EIO; + goto out_free_mboxq; } lpfc_parse_fcoe_conf(phba, mp->virt, data_length); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - return 0; + rc = 0; + +out_free_mboxq: + mempool_free(mboxq, phba->mbox_mem_pool); + return rc; } /** @@ -4706,7 +4718,6 @@ static int lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba) { LPFC_MBOXQ_t *mboxq; - struct lpfc_mbx_read_config *rd_config; struct lpfc_mbx_get_cntl_attributes *mbx_cntl_attr; struct lpfc_controller_attribute *cntl_attr; struct lpfc_mbx_get_port_name *get_port_name; @@ -4724,33 +4735,11 @@ lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba) mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) return -ENOMEM; - /* obtain link type and link number via READ_CONFIG */ - lpfc_read_config(phba, mboxq); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc == MBX_SUCCESS) { - rd_config = &mboxq->u.mqe.un.rd_config; - if (bf_get(lpfc_mbx_rd_conf_lnk_ldv, rd_config)) { - phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_VAL; - phba->sli4_hba.lnk_info.lnk_tp = - bf_get(lpfc_mbx_rd_conf_lnk_type, rd_config); - phba->sli4_hba.lnk_info.lnk_no = - bf_get(lpfc_mbx_rd_conf_lnk_numb, rd_config); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3081 lnk_type:%d, lnk_numb:%d\n", - phba->sli4_hba.lnk_info.lnk_tp, - phba->sli4_hba.lnk_info.lnk_no); - goto retrieve_ppname; - } else - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3082 Mailbox (x%x) returned ldv:x0\n", - bf_get(lpfc_mqe_command, - &mboxq->u.mqe)); - } else - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3083 Mailbox (x%x) failed, status:x%x\n", - bf_get(lpfc_mqe_command, &mboxq->u.mqe), - bf_get(lpfc_mqe_status, &mboxq->u.mqe)); + phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL; + lpfc_sli4_read_config(phba); + if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) + goto retrieve_ppname; /* obtain link type and link number via COMMON_GET_CNTL_ATTRIBUTES */ reqlen = sizeof(struct lpfc_mbx_get_cntl_attributes); @@ -5457,6 +5446,8 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) uint16_t count, base; unsigned long longs; + if (!phba->sli4_hba.rpi_hdrs_in_use) + phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.max_rpi; if (phba->sli4_hba.extents_in_use) { /* * The port supports resource extents. The XRI, VPI, VFI, RPI @@ -5538,9 +5529,10 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) * need any action - just exit. */ if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) == - LPFC_IDX_RSRC_RDY) - return 0; - + LPFC_IDX_RSRC_RDY) { + lpfc_sli4_dealloc_resource_identifiers(phba); + lpfc_sli4_remove_rpis(phba); + } /* RPIs. */ count = phba->sli4_hba.max_cfg_param.max_rpi; base = phba->sli4_hba.max_cfg_param.rpi_base; @@ -5880,14 +5872,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) if (!mboxq) return -ENOMEM; - /* - * Continue initialization with default values even if driver failed - * to read FCoE param config regions - */ - if (lpfc_sli4_read_fcoe_params(phba, mboxq)) - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_INIT, - "2570 Failed to read FCoE parameters\n"); - /* Issue READ_REV to collect vpd and FW information. */ vpd_size = SLI4_PAGE_SIZE; vpd = kzalloc(vpd_size, GFP_KERNEL); @@ -5924,6 +5908,16 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) goto out_free_mbox; } + /* + * Continue initialization with default values even if driver failed + * to read FCoE param config regions, only read parameters if the + * board is FCoE + */ + if (phba->hba_flag & HBA_FCOE_MODE && + lpfc_sli4_read_fcoe_params(phba)) + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_INIT, + "2570 Failed to read FCoE parameters\n"); + /* * Retrieve sli4 device physical port name, failure of doing it * is considered as non-fatal. @@ -6044,6 +6038,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) "rc = x%x\n", rc); goto out_free_mbox; } + /* update physical xri mappings in the scsi buffers */ + lpfc_scsi_buf_update(phba); /* Read the port's service parameters. */ rc = lpfc_read_sparam(phba, mboxq, vport->vpi); @@ -7632,6 +7628,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, int numBdes, i; struct ulp_bde64 bde; struct lpfc_nodelist *ndlp; + uint32_t *pcmd; fip = phba->hba_flag & HBA_FIP_SUPPORT; /* The fcp commands will set command type */ @@ -7685,6 +7682,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, iocbq->iocb.ulpCommand); return IOCB_ERROR; } + wqe->els_req.payload_len = xmit_len; /* Els_reguest64 has a TMO */ bf_set(wqe_tmo, &wqe->els_req.wqe_com, @@ -7699,9 +7697,25 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_ct, &wqe->els_req.wqe_com, ct); bf_set(wqe_pu, &wqe->els_req.wqe_com, 0); /* CCP CCPE PV PRI in word10 were set in the memcpy */ - if (command_type == ELS_COMMAND_FIP) { + if (command_type == ELS_COMMAND_FIP) els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK) >> LPFC_FIP_ELS_ID_SHIFT); + pcmd = (uint32_t *) (((struct lpfc_dmabuf *) + iocbq->context2)->virt); + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { + if (pcmd && (*pcmd == ELS_CMD_FLOGI || + *pcmd == ELS_CMD_PLOGI)) { + bf_set(els_req64_sp, &wqe->els_req, 1); + bf_set(els_req64_sid, &wqe->els_req, + iocbq->vport->fc_myDID); + bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->vpi_ids[phba->pport->vpi]); + } else if (iocbq->context1) { + bf_set(wqe_ct, &wqe->els_req.wqe_com, 0); + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); + } } bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); @@ -7862,6 +7876,16 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0); bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); + pcmd = (uint32_t *) (((struct lpfc_dmabuf *) + iocbq->context2)->virt); + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { + bf_set(els_req64_sp, &wqe->els_req, 1); + bf_set(els_req64_sid, &wqe->els_req, + iocbq->vport->fc_myDID); + bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); + bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + phba->vpi_ids[phba->pport->vpi]); + } command_type = OTHER_COMMAND; break; case CMD_CLOSE_XRI_CN: @@ -8839,12 +8863,14 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { IOCB_t *irsp = &rspiocb->iocb; uint16_t abort_iotag, abort_context; - struct lpfc_iocbq *abort_iocb; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - - abort_iocb = NULL; + struct lpfc_iocbq *abort_iocb = NULL; if (irsp->ulpStatus) { + + /* + * Assume that the port already completed and returned, or + * will return the iocb. Just Log the message. + */ abort_context = cmdiocb->iocb.un.acxri.abortContextTag; abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag; @@ -8862,68 +8888,15 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ abort_iocb = phba->sli.iocbq_lookup[abort_context]; - /* - * If the iocb is not found in Firmware queue the iocb - * might have completed already. Do not free it again. - */ - if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - if (irsp->un.ulpWord[4] != IOERR_NO_XRI) { - spin_unlock_irq(&phba->hbalock); - lpfc_sli_release_iocbq(phba, cmdiocb); - return; - } - /* For SLI4 the ulpContext field for abort IOCB - * holds the iotag of the IOCB being aborted so - * the local abort_context needs to be reset to - * match the aborted IOCBs ulpContext. - */ - if (abort_iocb && phba->sli_rev == LPFC_SLI_REV4) - abort_context = abort_iocb->iocb.ulpContext; - } - lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI, "0327 Cannot abort els iocb %p " "with tag %x context %x, abort status %x, " "abort code %x\n", abort_iocb, abort_iotag, abort_context, irsp->ulpStatus, irsp->un.ulpWord[4]); - /* - * make sure we have the right iocbq before taking it - * off the txcmplq and try to call completion routine. - */ - if (!abort_iocb || - abort_iocb->iocb.ulpContext != abort_context || - (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0) - spin_unlock_irq(&phba->hbalock); - else if (phba->sli_rev < LPFC_SLI_REV4) { - /* - * leave the SLI4 aborted command on the txcmplq - * list and the command complete WCQE's XB bit - * will tell whether the SGL (XRI) can be released - * immediately or to the aborted SGL list for the - * following abort XRI from the HBA. - */ - list_del_init(&abort_iocb->list); - if (abort_iocb->iocb_flag & LPFC_IO_ON_Q) { - abort_iocb->iocb_flag &= ~LPFC_IO_ON_Q; - pring->txcmplq_cnt--; - } - - /* Firmware could still be in progress of DMAing - * payload, so don't free data buffer till after - * a hbeat. - */ - abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; - abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; - spin_unlock_irq(&phba->hbalock); - abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; - abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED; - (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb); - } else - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->hbalock); } - lpfc_sli_release_iocbq(phba, cmdiocb); return; } @@ -12167,6 +12140,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, wq->subtype = subtype; wq->host_index = 0; wq->hba_index = 0; + wq->entry_repost = LPFC_RELEASE_NOTIFICATION_INTERVAL; /* link the wq onto the parent cq child list */ list_add_tail(&wq->list, &cq->child_list); diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index d5cffd8af340..7d444c444db4 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -291,7 +291,7 @@ struct lpfc_bmbx { #define LPFC_RQE_SIZE 8 #define LPFC_EQE_DEF_COUNT 1024 -#define LPFC_CQE_DEF_COUNT 256 +#define LPFC_CQE_DEF_COUNT 1024 #define LPFC_WQE_DEF_COUNT 256 #define LPFC_MQE_DEF_COUNT 16 #define LPFC_RQE_DEF_COUNT 512 -- cgit v1.2.3 From cb69f7decc3777822b240c46890a209df288c7bb Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 13 Dec 2011 13:21:57 -0500 Subject: [SCSI] lpfc 8.3.28: Add support for ABTS failure handling Add support for ABTS failure handling: - Add asynchronous ABTS notification event feature to driver (CR 124578) - Change driver message 3092 and 3116 to KERN_WARNING (CR 124768) - Alter the SCR ELS command to use the temporary RPI and the Destination DID for SLI4-FC (CR 126070) Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_crtn.h | 4 +- drivers/scsi/lpfc/lpfc_els.c | 50 --------- drivers/scsi/lpfc/lpfc_hbadisc.c | 67 ++++++++++++ drivers/scsi/lpfc/lpfc_hw.h | 13 ++- drivers/scsi/lpfc/lpfc_mbox.c | 4 + drivers/scsi/lpfc/lpfc_scsi.c | 4 +- drivers/scsi/lpfc/lpfc_sli.c | 214 ++++++++++++++++++++++++++++++++------- 7 files changed, 263 insertions(+), 93 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_sli.c') diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 9237ff154234..bcc021f3c8eb 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -106,7 +106,7 @@ void lpfc_cleanup(struct lpfc_vport *); void lpfc_disc_timeout(unsigned long); struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); - +struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); void lpfc_worker_wake_up(struct lpfc_hba *); int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); int lpfc_do_work(void *); @@ -455,3 +455,5 @@ int lpfc_sli4_queue_create(struct lpfc_hba *); void lpfc_sli4_queue_destroy(struct lpfc_hba *); int lpfc_sli4_read_config(struct lpfc_hba *phba); int lpfc_scsi_buf_update(struct lpfc_hba *phba); +void lpfc_sli4_abts_err_handler(struct lpfc_hba *, struct lpfc_nodelist *, + struct sli4_wcqe_xri_aborted *); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 846ebfd37b5e..46876941bac6 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -6595,56 +6595,6 @@ dropit: phba->fc_stat.elsRcvDrop++; } -/** - * lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier - * @phba: pointer to lpfc hba data structure. - * @vpi: host virtual N_Port identifier. - * - * This routine finds a vport on a HBA (referred by @phba) through a - * @vpi. The function walks the HBA's vport list and returns the address - * of the vport with the matching @vpi. - * - * Return code - * NULL - No vport with the matching @vpi found - * Otherwise - Address to the vport with the matching @vpi. - **/ -struct lpfc_vport * -lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) -{ - struct lpfc_vport *vport; - unsigned long flags; - int i = 0; - - /* The physical ports are always vpi 0 - translate is unnecessary. */ - if (vpi > 0) { - /* - * Translate the physical vpi to the logical vpi. The - * vport stores the logical vpi. - */ - for (i = 0; i < phba->max_vpi; i++) { - if (vpi == phba->vpi_ids[i]) - break; - } - - if (i >= phba->max_vpi) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "2936 Could not find Vport mapped " - "to vpi %d\n", vpi); - return NULL; - } - } - - spin_lock_irqsave(&phba->hbalock, flags); - list_for_each_entry(vport, &phba->port_list, listentry) { - if (vport->vpi == i) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return vport; - } - } - spin_unlock_irqrestore(&phba->hbalock, flags); - return NULL; -} - /** * lpfc_els_unsol_event - Process an unsolicited event from an els sli ring * @phba: pointer to lpfc hba data structure. diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index cf4408f9a2cb..99c76677e394 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5352,6 +5352,73 @@ lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn) return ndlp; } +/* + * This routine looks up the ndlp lists for the given RPI. If the rpi + * is found, the routine returns the node element list pointer else + * return NULL. + */ +struct lpfc_nodelist * +lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_nodelist *ndlp; + + spin_lock_irq(shost->host_lock); + ndlp = __lpfc_findnode_rpi(vport, rpi); + spin_unlock_irq(shost->host_lock); + return ndlp; +} + +/** + * lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier + * @phba: pointer to lpfc hba data structure. + * @vpi: the physical host virtual N_Port identifier. + * + * This routine finds a vport on a HBA (referred by @phba) through a + * @vpi. The function walks the HBA's vport list and returns the address + * of the vport with the matching @vpi. + * + * Return code + * NULL - No vport with the matching @vpi found + * Otherwise - Address to the vport with the matching @vpi. + **/ +struct lpfc_vport * +lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) +{ + struct lpfc_vport *vport; + unsigned long flags; + int i = 0; + + /* The physical ports are always vpi 0 - translate is unnecessary. */ + if (vpi > 0) { + /* + * Translate the physical vpi to the logical vpi. The + * vport stores the logical vpi. + */ + for (i = 0; i < phba->max_vpi; i++) { + if (vpi == phba->vpi_ids[i]) + break; + } + + if (i >= phba->max_vpi) { + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + "2936 Could not find Vport mapped " + "to vpi %d\n", vpi); + return NULL; + } + } + + spin_lock_irqsave(&phba->hbalock, flags); + list_for_each_entry(vport, &phba->port_list, listentry) { + if (vport->vpi == i) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return vport; + } + } + spin_unlock_irqrestore(&phba->hbalock, flags); + return NULL; +} + void lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t did) diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 046edc4ab35f..2dd464b0f29e 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -2819,7 +2819,8 @@ typedef struct { #ifdef __BIG_ENDIAN_BITFIELD uint32_t rsvd1 : 19; /* Reserved */ uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd2 : 3; /* Reserved */ + uint32_t casabt : 1; /* Configure async abts status notice */ + uint32_t rsvd2 : 2; /* Reserved */ uint32_t cbg : 1; /* Configure BlockGuard */ uint32_t cmv : 1; /* Configure Max VPIs */ uint32_t ccrp : 1; /* Config Command Ring Polling */ @@ -2839,14 +2840,16 @@ typedef struct { uint32_t ccrp : 1; /* Config Command Ring Polling */ uint32_t cmv : 1; /* Configure Max VPIs */ uint32_t cbg : 1; /* Configure BlockGuard */ - uint32_t rsvd2 : 3; /* Reserved */ + uint32_t rsvd2 : 2; /* Reserved */ + uint32_t casabt : 1; /* Configure async abts status notice */ uint32_t cdss : 1; /* Configure Data Security SLI */ uint32_t rsvd1 : 19; /* Reserved */ #endif #ifdef __BIG_ENDIAN_BITFIELD uint32_t rsvd3 : 19; /* Reserved */ uint32_t gdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd4 : 3; /* Reserved */ + uint32_t gasabt : 1; /* Grant async abts status notice */ + uint32_t rsvd4 : 2; /* Reserved */ uint32_t gbg : 1; /* Grant BlockGuard */ uint32_t gmv : 1; /* Grant Max VPIs */ uint32_t gcrp : 1; /* Grant Command Ring Polling */ @@ -2866,7 +2869,8 @@ typedef struct { uint32_t gcrp : 1; /* Grant Command Ring Polling */ uint32_t gmv : 1; /* Grant Max VPIs */ uint32_t gbg : 1; /* Grant BlockGuard */ - uint32_t rsvd4 : 3; /* Reserved */ + uint32_t rsvd4 : 2; /* Reserved */ + uint32_t gasabt : 1; /* Grant async abts status notice */ uint32_t gdss : 1; /* Configure Data Security SLI */ uint32_t rsvd3 : 19; /* Reserved */ #endif @@ -3465,6 +3469,7 @@ typedef struct { } ASYNCSTAT_FIELDS; #define ASYNC_TEMP_WARN 0x100 #define ASYNC_TEMP_SAFE 0x101 +#define ASYNC_STATUS_CN 0x102 /* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7) or CMD_IOCB_RCV_SEQ64_CX (0xB5) */ diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 0228f04061da..328782efc839 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1293,6 +1293,10 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) phba->sli_rev = LPFC_SLI_REV2; mb->un.varCfgPort.sli_mode = phba->sli_rev; + /* If this is an SLI3 port, configure async status notification. */ + if (phba->sli_rev == LPFC_SLI_REV3) + mb->un.varCfgPort.casabt = 1; + /* Now setup pcb */ phba->pcb->type = TYPE_NATIVE_SLI2; phba->pcb->feature = FEATURE_INITIAL_SLI2; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 2e1e54e5c3ae..f1af3f9dead4 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -681,8 +681,10 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, rrq_empty = list_empty(&phba->active_rrq_list); spin_unlock_irqrestore(&phba->hbalock, iflag); - if (ndlp) + if (ndlp) { lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1); + lpfc_sli4_abts_err_handler(phba, ndlp, axri); + } lpfc_release_scsi_buf_s4(phba, psb); if (rrq_empty) lpfc_worker_wake_up(phba); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4c4d77356bb2..97bbafb21bc2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4339,6 +4339,11 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; spin_unlock_irq(&phba->hbalock); done = 1; + + if ((pmb->u.mb.un.varCfgPort.casabt == 1) && + (pmb->u.mb.un.varCfgPort.gasabt == 0)) + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "3110 Port did not grant ASABT\n"); } } if (!done) { @@ -7704,6 +7709,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, iocbq->context2)->virt); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { if (pcmd && (*pcmd == ELS_CMD_FLOGI || + *pcmd == ELS_CMD_SCR || *pcmd == ELS_CMD_PLOGI)) { bf_set(els_req64_sp, &wqe->els_req, 1); bf_set(els_req64_sid, &wqe->els_req, @@ -8213,6 +8219,137 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) return 0; } +/* lpfc_sli_abts_recover_port - Recover a port that failed an ABTS. + * @vport: pointer to virtual port object. + * @ndlp: nodelist pointer for the impacted rport. + * + * The driver calls this routine in response to a XRI ABORT CQE + * event from the port. In this event, the driver is required to + * recover its login to the rport even though its login may be valid + * from the driver's perspective. The failed ABTS notice from the + * port indicates the rport is not responding. + */ +static void +lpfc_sli_abts_recover_port(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp) +{ + struct Scsi_Host *shost; + struct lpfc_hba *phba; + unsigned long flags = 0; + + shost = lpfc_shost_from_vport(vport); + phba = vport->phba; + if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { + lpfc_printf_log(phba, KERN_INFO, + LOG_SLI, "3093 No rport recovery needed. " + "rport in state 0x%x\n", + ndlp->nlp_state); + return; + } + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3094 Start rport recovery on shost id 0x%x " + "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " + "flags 0x%x\n", + shost->host_no, ndlp->nlp_DID, + vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state, + ndlp->nlp_flag); + /* + * The rport is not responding. Don't attempt ADISC recovery. + * Remove the FCP-2 flag to force a PLOGI. + */ + spin_lock_irqsave(shost->host_lock, flags); + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + spin_unlock_irqrestore(shost->host_lock, flags); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RECOVERY); + lpfc_cancel_retry_delay_tmo(vport, ndlp); + spin_lock_irqsave(shost->host_lock, flags); + ndlp->nlp_flag |= NLP_NPR_2B_DISC; + spin_unlock_irqrestore(shost->host_lock, flags); + lpfc_disc_start(vport); +} + +/* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. + * @phba: Pointer to HBA context object. + * @iocbq: Pointer to iocb object. + * + * The async_event handler calls this routine when it receives + * an ASYNC_STATUS_CN event from the port. The port generates + * this event when an Abort Sequence request to an rport fails + * twice in succession. The abort could be originated by the + * driver or by the port. The ABTS could have been for an ELS + * or FCP IO. The port only generates this event when an ABTS + * fails to complete after one retry. + */ +static void +lpfc_sli_abts_err_handler(struct lpfc_hba *phba, + struct lpfc_iocbq *iocbq) +{ + struct lpfc_nodelist *ndlp = NULL; + uint16_t rpi = 0, vpi = 0; + struct lpfc_vport *vport = NULL; + + /* The rpi in the ulpContext is vport-sensitive. */ + vpi = iocbq->iocb.un.asyncstat.sub_ctxt_tag; + rpi = iocbq->iocb.ulpContext; + + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3092 Port generated ABTS async event " + "on vpi %d rpi %d status 0x%x\n", + vpi, rpi, iocbq->iocb.ulpStatus); + + vport = lpfc_find_vport_by_vpid(phba, vpi); + if (!vport) + goto err_exit; + ndlp = lpfc_findnode_rpi(vport, rpi); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + goto err_exit; + + if (iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) + lpfc_sli_abts_recover_port(vport, ndlp); + return; + + err_exit: + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3095 Event Context not found, no " + "action on vpi %d rpi %d status 0x%x, reason 0x%x\n", + iocbq->iocb.ulpContext, iocbq->iocb.ulpStatus, + vpi, rpi); +} + +/* lpfc_sli4_abts_err_handler - handle a failed ABTS request from an SLI4 port. + * @phba: pointer to HBA context object. + * @ndlp: nodelist pointer for the impacted rport. + * @axri: pointer to the wcqe containing the failed exchange. + * + * The driver calls this routine when it receives an ABORT_XRI_FCP CQE from the + * port. The port generates this event when an abort exchange request to an + * rport fails twice in succession with no reply. The abort could be originated + * by the driver or by the port. The ABTS could have been for an ELS or FCP IO. + */ +void +lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, + struct lpfc_nodelist *ndlp, + struct sli4_wcqe_xri_aborted *axri) +{ + struct lpfc_vport *vport; + + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3115 Node Context not found, driver " + "ignoring abts err event\n"); + vport = ndlp->vport; + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3116 Port generated FCP XRI ABORT event on " + "vpi %d rpi %d xri x%x status 0x%x\n", + ndlp->vport->vpi, ndlp->nlp_rpi, + bf_get(lpfc_wcqe_xa_xri, axri), + bf_get(lpfc_wcqe_xa_status, axri)); + + if (bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) + lpfc_sli_abts_recover_port(vport, ndlp); +} + /** * lpfc_sli_async_event_handler - ASYNC iocb handler function * @phba: Pointer to HBA context object. @@ -8232,63 +8369,58 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, { IOCB_t *icmd; uint16_t evt_code; - uint16_t temp; struct temp_event temp_event_data; struct Scsi_Host *shost; uint32_t *iocb_w; icmd = &iocbq->iocb; evt_code = icmd->un.asyncstat.evt_code; - temp = icmd->ulpContext; - if ((evt_code != ASYNC_TEMP_WARN) && - (evt_code != ASYNC_TEMP_SAFE)) { + switch (evt_code) { + case ASYNC_TEMP_WARN: + case ASYNC_TEMP_SAFE: + temp_event_data.data = (uint32_t) icmd->ulpContext; + temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; + if (evt_code == ASYNC_TEMP_WARN) { + temp_event_data.event_code = LPFC_THRESHOLD_TEMP; + lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, + "0347 Adapter is very hot, please take " + "corrective action. temperature : %d Celsius\n", + (uint32_t) icmd->ulpContext); + } else { + temp_event_data.event_code = LPFC_NORMAL_TEMP; + lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, + "0340 Adapter temperature is OK now. " + "temperature : %d Celsius\n", + (uint32_t) icmd->ulpContext); + } + + /* Send temperature change event to applications */ + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), (char *) &temp_event_data, + LPFC_NL_VENDOR_ID); + break; + case ASYNC_STATUS_CN: + lpfc_sli_abts_err_handler(phba, iocbq); + break; + default: iocb_w = (uint32_t *) icmd; - lpfc_printf_log(phba, - KERN_ERR, - LOG_SLI, + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0346 Ring %d handler: unexpected ASYNC_STATUS" " evt_code 0x%x\n" "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" "W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n" "W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n" "W12 0x%08x W13 0x%08x W14 0x%08x W15 0x%08x\n", - pring->ringno, - icmd->un.asyncstat.evt_code, + pring->ringno, icmd->un.asyncstat.evt_code, iocb_w[0], iocb_w[1], iocb_w[2], iocb_w[3], iocb_w[4], iocb_w[5], iocb_w[6], iocb_w[7], iocb_w[8], iocb_w[9], iocb_w[10], iocb_w[11], iocb_w[12], iocb_w[13], iocb_w[14], iocb_w[15]); - return; - } - temp_event_data.data = (uint32_t)temp; - temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; - if (evt_code == ASYNC_TEMP_WARN) { - temp_event_data.event_code = LPFC_THRESHOLD_TEMP; - lpfc_printf_log(phba, - KERN_ERR, - LOG_TEMP, - "0347 Adapter is very hot, please take " - "corrective action. temperature : %d Celsius\n", - temp); - } - if (evt_code == ASYNC_TEMP_SAFE) { - temp_event_data.event_code = LPFC_NORMAL_TEMP; - lpfc_printf_log(phba, - KERN_ERR, - LOG_TEMP, - "0340 Adapter temperature is OK now. " - "temperature : %d Celsius\n", - temp); + break; } - - /* Send temperature change event to applications */ - shost = lpfc_shost_from_vport(phba->pport); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(temp_event_data), (char *) &temp_event_data, - LPFC_NL_VENDOR_ID); - } @@ -9247,6 +9379,14 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3096 ABORT_XRI_CN completing on xri x%x " + "original iotag x%x, abort cmd iotag x%x " + "status 0x%x, reason 0x%x\n", + cmdiocb->iocb.un.acxri.abortContextTag, + cmdiocb->iocb.un.acxri.abortIoTag, + cmdiocb->iotag, rspiocb->iocb.ulpStatus, + rspiocb->iocb.un.ulpWord[4]); lpfc_sli_release_iocbq(phba, cmdiocb); return; } -- cgit v1.2.3 From 2e90f4b5a2a0ce5ab72c0c81c74269bd0a62522b Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 13 Dec 2011 13:22:37 -0500 Subject: [SCSI] lpfc 8.3.28: Critical Miscellaneous fixes - Make lpfc_sli4_pci_mem_unset interface type aware (CR 124390) - Convert byte count to word count when calling __iowrite32_copy (CR 122550) - Checked the ERR1 and ERR2 registers for error attention due to SLI Port state affected by forced debug dump. (CR 122986, 122426, 124859) - Use the lpfc_readl routine instead of the readl for the port status register read in lpfc_handle_eratt_s4 (CR 125403) - Call lpfc_sli4_queue_destroy inside of lpfc_sli4_brdreset before doing a pci function reset (CR 125124, 125168, 125572, 125622) - Zero out the HBQ when it is allocated (CR 125663) - Alter port reset log messages to indicate error type (CR 125989) - Added proper NULL pointer checking to all the places that accessing the queue memory (CR 125832) Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_compat.h | 5 +- drivers/scsi/lpfc/lpfc_debugfs.c | 172 +++++++++++++++++++++++++-------------- drivers/scsi/lpfc/lpfc_init.c | 164 ++++++++++++++++++++++++++----------- drivers/scsi/lpfc/lpfc_mem.c | 4 +- drivers/scsi/lpfc/lpfc_sli.c | 135 +++++++++++++++++++++++------- drivers/scsi/lpfc/lpfc_sli4.h | 9 ++ 6 files changed, 350 insertions(+), 139 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_sli.c') diff --git a/drivers/scsi/lpfc/lpfc_compat.h b/drivers/scsi/lpfc/lpfc_compat.h index 75e2e569dede..c88e556ea62e 100644 --- a/drivers/scsi/lpfc/lpfc_compat.h +++ b/drivers/scsi/lpfc/lpfc_compat.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -82,7 +82,8 @@ lpfc_memcpy_from_slim( void *dest, void __iomem *src, unsigned int bytes) static inline void lpfc_memcpy_to_slim( void __iomem *dest, void *src, unsigned int bytes) { - __iowrite32_copy(dest, src, bytes); + /* convert bytes in argument list to word count for copy function */ + __iowrite32_copy(dest, src, bytes / sizeof(uint32_t)); } static inline void diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 28382596fb9a..3587a3fe8fcb 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1997,7 +1997,8 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, /* Get slow-path event queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path EQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.sp_eq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tEQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2006,12 +2007,17 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.sp_eq->entry_size, phba->sli4_hba.sp_eq->host_index, phba->sli4_hba.sp_eq->hba_index); + } /* Get fast-path event queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Fast-path EQ information:\n"); - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.fp_eq) { + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; + fcp_qidx++) { + if (phba->sli4_hba.fp_eq[fcp_qidx]) { + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tEQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2020,16 +2026,19 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.fp_eq[fcp_qidx]->entry_size, phba->sli4_hba.fp_eq[fcp_qidx]->host_index, phba->sli4_hba.fp_eq[fcp_qidx]->hba_index); + } + } } len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); /* Get mailbox complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path MBX CQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.mbx_cq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated EQID[%02d]:\n", phba->sli4_hba.mbx_cq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tCQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2038,14 +2047,16 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.mbx_cq->entry_size, phba->sli4_hba.mbx_cq->host_index, phba->sli4_hba.mbx_cq->hba_index); + } /* Get slow-path complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path ELS CQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.els_cq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated EQID[%02d]:\n", phba->sli4_hba.els_cq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tCQID [%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2054,16 +2065,21 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.els_cq->entry_size, phba->sli4_hba.els_cq->host_index, phba->sli4_hba.els_cq->hba_index); + } /* Get fast-path complete queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Fast-path FCP CQ information:\n"); fcp_qidx = 0; - do { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.fcp_cq) { + do { + if (phba->sli4_hba.fcp_cq[fcp_qidx]) { + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated EQID[%02d]:\n", phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tCQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2072,16 +2088,20 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.fcp_cq[fcp_qidx]->entry_size, phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); - } while (++fcp_qidx < phba->cfg_fcp_eq_count); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + } + } while (++fcp_qidx < phba->cfg_fcp_eq_count); + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); + } /* Get mailbox queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path MBX MQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.mbx_wq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated CQID[%02d]:\n", phba->sli4_hba.mbx_wq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tWQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2090,14 +2110,16 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.mbx_wq->entry_size, phba->sli4_hba.mbx_wq->host_index, phba->sli4_hba.mbx_wq->hba_index); + } /* Get slow-path work queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path ELS WQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.els_wq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated CQID[%02d]:\n", phba->sli4_hba.els_wq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tWQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", @@ -2106,15 +2128,22 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.els_wq->entry_size, phba->sli4_hba.els_wq->host_index, phba->sli4_hba.els_wq->hba_index); + } /* Get fast-path work queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Fast-path FCP WQ information:\n"); - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.fcp_wq) { + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; + fcp_qidx++) { + if (!phba->sli4_hba.fcp_wq[fcp_qidx]) + continue; + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated CQID[%02d]:\n", phba->sli4_hba.fcp_wq[fcp_qidx]->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tWQID[%02d], " "QE-COUNT[%04d], WQE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2123,16 +2152,19 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.fcp_wq[fcp_qidx]->entry_size, phba->sli4_hba.fcp_wq[fcp_qidx]->host_index, phba->sli4_hba.fcp_wq[fcp_qidx]->hba_index); + } + len += snprintf(pbuffer+len, + LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); } - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); /* Get receive queue information */ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Slow-path RQ information:\n"); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + if (phba->sli4_hba.hdr_rq && phba->sli4_hba.dat_rq) { + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "Associated CQID[%02d]:\n", phba->sli4_hba.hdr_rq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tHQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2141,7 +2173,7 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.hdr_rq->entry_size, phba->sli4_hba.hdr_rq->host_index, phba->sli4_hba.hdr_rq->hba_index); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, + len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\tDQID[%02d], " "QE-COUNT[%04d], QE-SIZE[%04d], " "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", @@ -2150,7 +2182,7 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, phba->sli4_hba.dat_rq->entry_size, phba->sli4_hba.dat_rq->host_index, phba->sli4_hba.dat_rq->hba_index); - + } return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); } @@ -2360,7 +2392,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, switch (quetp) { case LPFC_IDIAG_EQ: /* Slow-path event queue */ - if (phba->sli4_hba.sp_eq->queue_id == queid) { + if (phba->sli4_hba.sp_eq && + phba->sli4_hba.sp_eq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.sp_eq, index, count); @@ -2370,23 +2403,29 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* Fast-path event queue */ - for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { - if (phba->sli4_hba.fp_eq[qidx]->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( + if (phba->sli4_hba.fp_eq) { + for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { + if (phba->sli4_hba.fp_eq[qidx] && + phba->sli4_hba.fp_eq[qidx]->queue_id == + queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( phba->sli4_hba.fp_eq[qidx], index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.fp_eq[qidx]; - goto pass_check; + if (rc) + goto error_out; + idiag.ptr_private = + phba->sli4_hba.fp_eq[qidx]; + goto pass_check; + } } } goto error_out; break; case LPFC_IDIAG_CQ: /* MBX complete queue */ - if (phba->sli4_hba.mbx_cq->queue_id == queid) { + if (phba->sli4_hba.mbx_cq && + phba->sli4_hba.mbx_cq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.mbx_cq, index, count); @@ -2396,7 +2435,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* ELS complete queue */ - if (phba->sli4_hba.els_cq->queue_id == queid) { + if (phba->sli4_hba.els_cq && + phba->sli4_hba.els_cq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.els_cq, index, count); @@ -2406,25 +2446,30 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* FCP complete queue */ - qidx = 0; - do { - if (phba->sli4_hba.fcp_cq[qidx]->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( + if (phba->sli4_hba.fcp_cq) { + qidx = 0; + do { + if (phba->sli4_hba.fcp_cq[qidx] && + phba->sli4_hba.fcp_cq[qidx]->queue_id == + queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( phba->sli4_hba.fcp_cq[qidx], index, count); - if (rc) - goto error_out; - idiag.ptr_private = + if (rc) + goto error_out; + idiag.ptr_private = phba->sli4_hba.fcp_cq[qidx]; - goto pass_check; - } - } while (++qidx < phba->cfg_fcp_eq_count); + goto pass_check; + } + } while (++qidx < phba->cfg_fcp_eq_count); + } goto error_out; break; case LPFC_IDIAG_MQ: /* MBX work queue */ - if (phba->sli4_hba.mbx_wq->queue_id == queid) { + if (phba->sli4_hba.mbx_wq && + phba->sli4_hba.mbx_wq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.mbx_wq, index, count); @@ -2433,10 +2478,12 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, idiag.ptr_private = phba->sli4_hba.mbx_wq; goto pass_check; } + goto error_out; break; case LPFC_IDIAG_WQ: /* ELS work queue */ - if (phba->sli4_hba.els_wq->queue_id == queid) { + if (phba->sli4_hba.els_wq && + phba->sli4_hba.els_wq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.els_wq, index, count); @@ -2446,24 +2493,30 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* FCP work queue */ - for (qidx = 0; qidx < phba->cfg_fcp_wq_count; qidx++) { - if (phba->sli4_hba.fcp_wq[qidx]->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( + if (phba->sli4_hba.fcp_wq) { + for (qidx = 0; qidx < phba->cfg_fcp_wq_count; qidx++) { + if (!phba->sli4_hba.fcp_wq[qidx]) + continue; + if (phba->sli4_hba.fcp_wq[qidx]->queue_id == + queid) { + /* Sanity check */ + rc = lpfc_idiag_que_param_check( phba->sli4_hba.fcp_wq[qidx], index, count); - if (rc) - goto error_out; - idiag.ptr_private = - phba->sli4_hba.fcp_wq[qidx]; - goto pass_check; + if (rc) + goto error_out; + idiag.ptr_private = + phba->sli4_hba.fcp_wq[qidx]; + goto pass_check; + } } } goto error_out; break; case LPFC_IDIAG_RQ: /* HDR queue */ - if (phba->sli4_hba.hdr_rq->queue_id == queid) { + if (phba->sli4_hba.hdr_rq && + phba->sli4_hba.hdr_rq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.hdr_rq, index, count); @@ -2473,7 +2526,8 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, goto pass_check; } /* DAT queue */ - if (phba->sli4_hba.dat_rq->queue_id == queid) { + if (phba->sli4_hba.dat_rq && + phba->sli4_hba.dat_rq->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( phba->sli4_hba.dat_rq, index, count); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 6096c9a091d1..cb714d2342d4 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1417,7 +1417,10 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) uint32_t event_data; struct Scsi_Host *shost; uint32_t if_type; - struct lpfc_register portstat_reg; + 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; int rc; /* If the pci channel is offline, ignore possible errors, since @@ -1429,27 +1432,29 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) if (!phba->cfg_enable_hba_reset) return; - /* Send an internal error event to mgmt application */ - lpfc_board_errevt_to_mgmt(phba); - - /* For now, the actual action for SLI4 device handling is not - * specified yet, just treated it as adaptor hardware failure - */ - 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); - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); switch (if_type) { case LPFC_SLI_INTF_IF_TYPE_0: + pci_rd_rc1 = lpfc_readl( + phba->sli4_hba.u.if_type0.UERRLOregaddr, + &uerrlo_reg); + pci_rd_rc2 = lpfc_readl( + phba->sli4_hba.u.if_type0.UEMASKLOregaddr, + &uemasklo_reg); + /* consider PCI bus read error as pci_channel_offline */ + if (pci_rd_rc1 == -EIO && pci_rd_rc2 == -EIO) + return; lpfc_sli4_offline_eratt(phba); break; case LPFC_SLI_INTF_IF_TYPE_2: - portstat_reg.word0 = - readl(phba->sli4_hba.u.if_type2.STATUSregaddr); - + pci_rd_rc1 = lpfc_readl( + phba->sli4_hba.u.if_type2.STATUSregaddr, + &portstat_reg.word0); + /* consider PCI bus read error as pci_channel_offline */ + if (pci_rd_rc1 == -EIO) + return; + reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr); + reg_err2 = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) { /* TODO: Register for Overtemp async events. */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -1459,8 +1464,20 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) phba->over_temp_state = HBA_OVER_TEMP; spin_unlock_irq(&phba->hbalock); lpfc_sli4_offline_eratt(phba); - return; + break; } + if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && + reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3143 Port Down: Firmware Restarted\n"); + else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && + reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3144 Port Down: Debug Dump\n"); + else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && + reg_err2 == SLIPORT_ERR2_REG_FUNC_PROVISON) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3145 Port Down: Provisioning\n"); /* * On error status condition, driver need to wait for port * ready before performing reset. @@ -1469,14 +1486,19 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) if (!rc) { /* need reset: attempt for port recovery */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2887 Port Error: Attempting " - "Port Recovery\n"); + "2887 Reset Needed: Attempting Port " + "Recovery...\n"); lpfc_offline_prep(phba); lpfc_offline(phba); lpfc_sli_brdrestart(phba); if (lpfc_online(phba) == 0) { lpfc_unblock_mgmt_io(phba); - return; + /* don't report event on forced debug dump */ + if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && + reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP) + return; + else + break; } /* fall through for not able to recover */ } @@ -1486,6 +1508,16 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) default: break; } + lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "3123 Report dump event to upper layer\n"); + /* Send an internal error event to mgmt application */ + lpfc_board_errevt_to_mgmt(phba); + + 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); } /** @@ -6475,6 +6507,7 @@ out_free_fcp_wq: phba->sli4_hba.fcp_wq[fcp_wqidx] = NULL; } kfree(phba->sli4_hba.fcp_wq); + phba->sli4_hba.fcp_wq = NULL; out_free_els_wq: lpfc_sli4_queue_free(phba->sli4_hba.els_wq); phba->sli4_hba.els_wq = NULL; @@ -6487,6 +6520,7 @@ out_free_fcp_cq: phba->sli4_hba.fcp_cq[fcp_cqidx] = NULL; } kfree(phba->sli4_hba.fcp_cq); + phba->sli4_hba.fcp_cq = NULL; out_free_els_cq: lpfc_sli4_queue_free(phba->sli4_hba.els_cq); phba->sli4_hba.els_cq = NULL; @@ -6499,6 +6533,7 @@ out_free_fp_eq: phba->sli4_hba.fp_eq[fcp_eqidx] = NULL; } kfree(phba->sli4_hba.fp_eq); + phba->sli4_hba.fp_eq = NULL; out_free_sp_eq: lpfc_sli4_queue_free(phba->sli4_hba.sp_eq); phba->sli4_hba.sp_eq = NULL; @@ -6532,8 +6567,10 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) phba->sli4_hba.els_wq = NULL; /* Release FCP work queue */ - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) - lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_qidx]); + if (phba->sli4_hba.fcp_wq != NULL) + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; + fcp_qidx++) + lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_qidx]); kfree(phba->sli4_hba.fcp_wq); phba->sli4_hba.fcp_wq = NULL; @@ -6553,15 +6590,18 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) /* Release FCP response complete queue */ fcp_qidx = 0; - do - lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]); - while (++fcp_qidx < phba->cfg_fcp_eq_count); + if (phba->sli4_hba.fcp_cq != NULL) + do + lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]); + while (++fcp_qidx < phba->cfg_fcp_eq_count); kfree(phba->sli4_hba.fcp_cq); phba->sli4_hba.fcp_cq = NULL; /* Release fast-path event queue */ - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) - lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]); + if (phba->sli4_hba.fp_eq != NULL) + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; + fcp_qidx++) + lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]); kfree(phba->sli4_hba.fp_eq); phba->sli4_hba.fp_eq = NULL; @@ -6614,6 +6654,11 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.sp_eq->queue_id); /* Set up fast-path event queue */ + if (!phba->sli4_hba.fp_eq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3147 Fast-path EQs not allocated\n"); + goto out_destroy_sp_eq; + } for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { if (!phba->sli4_hba.fp_eq[fcp_eqidx]) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -6678,6 +6723,12 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.sp_eq->queue_id); /* Set up fast-path FCP Response Complete Queue */ + if (!phba->sli4_hba.fcp_cq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3148 Fast-path FCP CQ array not " + "allocated\n"); + goto out_destroy_els_cq; + } fcp_cqidx = 0; do { if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) { @@ -6757,6 +6808,12 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.els_cq->queue_id); /* Set up fast-path FCP Work Queue */ + if (!phba->sli4_hba.fcp_wq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3149 Fast-path FCP WQ array not " + "allocated\n"); + goto out_destroy_els_wq; + } for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) { if (!phba->sli4_hba.fcp_wq[fcp_wqidx]) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -6818,18 +6875,21 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) out_destroy_fcp_wq: for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_wqidx]); +out_destroy_els_wq: lpfc_wq_destroy(phba, phba->sli4_hba.els_wq); out_destroy_mbx_wq: lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq); out_destroy_fcp_cq: for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]); +out_destroy_els_cq: lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); out_destroy_mbx_cq: lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); out_destroy_fp_eq: for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_eqidx]); +out_destroy_sp_eq: lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); out_error: return rc; @@ -6866,13 +6926,18 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba) /* Unset ELS complete queue */ lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); /* Unset FCP response complete queue */ - fcp_qidx = 0; - do { - lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]); - } while (++fcp_qidx < phba->cfg_fcp_eq_count); + if (phba->sli4_hba.fcp_cq) { + fcp_qidx = 0; + do { + lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]); + } while (++fcp_qidx < phba->cfg_fcp_eq_count); + } /* Unset fast-path event queue */ - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) - lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_qidx]); + if (phba->sli4_hba.fp_eq) { + for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; + fcp_qidx++) + lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_qidx]); + } /* Unset slow-path event queue */ lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); } @@ -7411,22 +7476,25 @@ out: static void lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba) { - struct pci_dev *pdev; - - /* Obtain PCI device reference */ - if (!phba->pcidev) - return; - else - pdev = phba->pcidev; - - /* Free coherent DMA memory allocated */ - - /* Unmap I/O memory space */ - iounmap(phba->sli4_hba.drbl_regs_memmap_p); - iounmap(phba->sli4_hba.ctrl_regs_memmap_p); - iounmap(phba->sli4_hba.conf_regs_memmap_p); + uint32_t if_type; + if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - return; + switch (if_type) { + case LPFC_SLI_INTF_IF_TYPE_0: + iounmap(phba->sli4_hba.drbl_regs_memmap_p); + iounmap(phba->sli4_hba.ctrl_regs_memmap_p); + iounmap(phba->sli4_hba.conf_regs_memmap_p); + break; + case LPFC_SLI_INTF_IF_TYPE_2: + iounmap(phba->sli4_hba.conf_regs_memmap_p); + 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; + } } /** diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 10d5b5e41499..ade763d3930a 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -389,7 +389,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba) { struct hbq_dmabuf *hbqbp; - hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); + hbqbp = kzalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); if (!hbqbp) return NULL; @@ -441,7 +441,7 @@ lpfc_sli4_rb_alloc(struct lpfc_hba *phba) { struct hbq_dmabuf *dma_buf; - dma_buf = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); + dma_buf = kzalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); if (!dma_buf) return NULL; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 97bbafb21bc2..e27cb44b3ec2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -89,10 +89,15 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) static uint32_t lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) { - union lpfc_wqe *temp_wqe = q->qe[q->host_index].wqe; + union lpfc_wqe *temp_wqe; struct lpfc_register doorbell; uint32_t host_index; + /* sanity check on queue memory */ + if (unlikely(!q)) + return -ENOMEM; + temp_wqe = q->qe[q->host_index].wqe; + /* If the host has not yet processed the next entry then we are done */ if (((q->host_index + 1) % q->entry_count) == q->hba_index) return -ENOMEM; @@ -134,6 +139,10 @@ lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index) { uint32_t released = 0; + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; + if (q->hba_index == index) return 0; do { @@ -158,10 +167,15 @@ lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index) static uint32_t lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe) { - struct lpfc_mqe *temp_mqe = q->qe[q->host_index].mqe; + struct lpfc_mqe *temp_mqe; struct lpfc_register doorbell; uint32_t host_index; + /* sanity check on queue memory */ + if (unlikely(!q)) + return -ENOMEM; + temp_mqe = q->qe[q->host_index].mqe; + /* If the host has not yet processed the next entry then we are done */ if (((q->host_index + 1) % q->entry_count) == q->hba_index) return -ENOMEM; @@ -195,6 +209,10 @@ lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe) static uint32_t lpfc_sli4_mq_release(struct lpfc_queue *q) { + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; + /* Clear the mailbox pointer for completion */ q->phba->mbox = NULL; q->hba_index = ((q->hba_index + 1) % q->entry_count); @@ -213,7 +231,12 @@ lpfc_sli4_mq_release(struct lpfc_queue *q) static struct lpfc_eqe * lpfc_sli4_eq_get(struct lpfc_queue *q) { - struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe; + struct lpfc_eqe *eqe; + + /* sanity check on queue memory */ + if (unlikely(!q)) + return NULL; + eqe = q->qe[q->hba_index].eqe; /* If the next EQE is not valid then we are done */ if (!bf_get_le32(lpfc_eqe_valid, eqe)) @@ -248,6 +271,10 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm) struct lpfc_eqe *temp_eqe; struct lpfc_register doorbell; + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; + /* while there are valid entries */ while (q->hba_index != q->host_index) { temp_eqe = q->qe[q->host_index].eqe; @@ -288,6 +315,10 @@ lpfc_sli4_cq_get(struct lpfc_queue *q) { struct lpfc_cqe *cqe; + /* sanity check on queue memory */ + if (unlikely(!q)) + return NULL; + /* If the next CQE is not valid then we are done */ if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe)) return NULL; @@ -322,6 +353,9 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm) struct lpfc_cqe *temp_qe; struct lpfc_register doorbell; + /* sanity check on queue memory */ + if (unlikely(!q)) + return 0; /* while there are valid entries */ while (q->hba_index != q->host_index) { temp_qe = q->qe[q->host_index].cqe; @@ -359,11 +393,17 @@ static int lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, struct lpfc_rqe *hrqe, struct lpfc_rqe *drqe) { - struct lpfc_rqe *temp_hrqe = hq->qe[hq->host_index].rqe; - struct lpfc_rqe *temp_drqe = dq->qe[dq->host_index].rqe; + struct lpfc_rqe *temp_hrqe; + struct lpfc_rqe *temp_drqe; struct lpfc_register doorbell; int put_index = hq->host_index; + /* sanity check on queue memory */ + if (unlikely(!hq) || unlikely(!dq)) + return -ENOMEM; + temp_hrqe = hq->qe[hq->host_index].rqe; + temp_drqe = dq->qe[dq->host_index].rqe; + if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ) return -EINVAL; if (hq->host_index != dq->host_index) @@ -402,6 +442,10 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, static uint32_t lpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq) { + /* sanity check on queue memory */ + if (unlikely(!hq) || unlikely(!dq)) + return 0; + if ((hq->type != LPFC_HRQ) || (dq->type != LPFC_DRQ)) return 0; hq->hba_index = ((hq->hba_index + 1) % hq->entry_count); @@ -3851,7 +3895,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; uint16_t cfg_value; - uint8_t qindx; /* Reset HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -3867,19 +3910,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~(LPFC_PROCESS_LA); phba->fcf.fcf_flag = 0; - /* Clean up the child queue list for the CQs */ - list_del_init(&phba->sli4_hba.mbx_wq->list); - list_del_init(&phba->sli4_hba.els_wq->list); - list_del_init(&phba->sli4_hba.hdr_rq->list); - list_del_init(&phba->sli4_hba.dat_rq->list); - list_del_init(&phba->sli4_hba.mbx_cq->list); - list_del_init(&phba->sli4_hba.els_cq->list); - for (qindx = 0; qindx < phba->cfg_fcp_wq_count; qindx++) - list_del_init(&phba->sli4_hba.fcp_wq[qindx]->list); - qindx = 0; - do - list_del_init(&phba->sli4_hba.fcp_cq[qindx]->list); - while (++qindx < phba->cfg_fcp_eq_count); spin_unlock_irq(&phba->hbalock); /* Now physically reset the device */ @@ -3892,6 +3922,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); /* Perform FCoE PCI function reset */ + lpfc_sli4_queue_destroy(phba); lpfc_pci_function_reset(phba); /* Restore PCI cmd register */ @@ -4869,14 +4900,19 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM); lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM); fcp_eqidx = 0; - do - lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx], - LPFC_QUEUE_REARM); - while (++fcp_eqidx < phba->cfg_fcp_eq_count); + if (phba->sli4_hba.fcp_cq) { + do + lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx], + LPFC_QUEUE_REARM); + while (++fcp_eqidx < phba->cfg_fcp_eq_count); + } lpfc_sli4_eq_release(phba->sli4_hba.sp_eq, LPFC_QUEUE_REARM); - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) - lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx], - LPFC_QUEUE_REARM); + if (phba->sli4_hba.fp_eq) { + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; + fcp_eqidx++) + lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx], + LPFC_QUEUE_REARM); + } } /** @@ -8083,6 +8119,8 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, */ if (piocb->iocb_flag & LPFC_IO_FCP) piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); + if (unlikely(!phba->sli4_hba.fcp_wq)) + return IOCB_ERROR; if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], &wqe)) return IOCB_ERROR; @@ -9900,7 +9938,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) phba->work_status[1] = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2885 Port Error Detected: " + "2885 Port Status Event: " "port status reg 0x%x, " "port smphr reg 0x%x, " "error 1=0x%x, error 2=0x%x\n", @@ -10906,6 +10944,9 @@ static void lpfc_sli4_sp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_wcqe_release *wcqe) { + /* sanity check on queue memory */ + if (unlikely(!phba->sli4_hba.els_wq)) + return; /* Check for the slow-path ELS work queue */ if (bf_get(lpfc_wcqe_r_wq_id, wcqe) == phba->sli4_hba.els_wq->queue_id) lpfc_sli4_wq_release(phba->sli4_hba.els_wq, @@ -10995,6 +11036,10 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) uint32_t status, rq_id; unsigned long iflags; + /* sanity check on queue memory */ + if (unlikely(!hrq) || unlikely(!drq)) + return workposted; + if (bf_get(lpfc_cqe_code, rcqe) == CQE_CODE_RECEIVE_V1) rq_id = bf_get(lpfc_rcqe_rq_id_v1, rcqe); else @@ -11129,6 +11174,9 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) /* Search for completion queue pointer matching this cqid */ speq = phba->sli4_hba.sp_eq; + /* sanity check on queue memory */ + if (unlikely(!speq)) + return; list_for_each_entry(childq, &speq->child_list, list) { if (childq->queue_id == cqid) { cq = childq; @@ -11370,12 +11418,18 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, return; } + if (unlikely(!phba->sli4_hba.fcp_cq)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3146 Fast-path completion queues " + "does not exist\n"); + return; + } cq = phba->sli4_hba.fcp_cq[fcp_cqidx]; if (unlikely(!cq)) { if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0367 Fast-path completion queue " - "does not exist\n"); + "(%d) does not exist\n", fcp_cqidx); return; } @@ -11546,6 +11600,8 @@ lpfc_sli4_fp_intr_handler(int irq, void *dev_id) /* Get to the EQ struct associated with this vector */ fpeq = phba->sli4_hba.fp_eq[fcp_eqidx]; + if (unlikely(!fpeq)) + return IRQ_NONE; /* Check device state for handling interrupt */ if (unlikely(lpfc_intr_state_check(phba))) { @@ -11764,6 +11820,9 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) uint16_t dmult; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + /* sanity check on queue memory */ + if (!eq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -11880,6 +11939,9 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, union lpfc_sli4_cfg_shdr *shdr; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + /* sanity check on queue memory */ + if (!cq || !eq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -12062,6 +12124,9 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, union lpfc_sli4_cfg_shdr *shdr; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + /* sanity check on queue memory */ + if (!mq || !cq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -12212,6 +12277,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; struct dma_address *page; + /* sanity check on queue memory */ + if (!wq || !cq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -12304,6 +12372,9 @@ lpfc_rq_adjust_repost(struct lpfc_hba *phba, struct lpfc_queue *rq, int qno) { uint32_t cnt; + /* sanity check on queue memory */ + if (!rq) + return; cnt = lpfc_hbq_defs[qno]->entry_count; /* Recalc repost for RQs based on buffers initially posted */ @@ -12349,6 +12420,9 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, union lpfc_sli4_cfg_shdr *shdr; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + /* sanity check on queue memory */ + if (!hrq || !drq || !cq) + return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -12550,6 +12624,7 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!eq) return -ENODEV; mbox = mempool_alloc(eq->phba->mbox_mem_pool, GFP_KERNEL); @@ -12605,6 +12680,7 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!cq) return -ENODEV; mbox = mempool_alloc(cq->phba->mbox_mem_pool, GFP_KERNEL); @@ -12658,6 +12734,7 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!mq) return -ENODEV; mbox = mempool_alloc(mq->phba->mbox_mem_pool, GFP_KERNEL); @@ -12711,6 +12788,7 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!wq) return -ENODEV; mbox = mempool_alloc(wq->phba->mbox_mem_pool, GFP_KERNEL); @@ -12764,6 +12842,7 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + /* sanity check on queue memory */ if (!hrq || !drq) return -ENODEV; mbox = mempool_alloc(hrq->phba->mbox_mem_pool, GFP_KERNEL); diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 7d444c444db4..3f266e2c54e0 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -420,7 +420,16 @@ struct lpfc_sli4_hba { void __iomem *STATUSregaddr; void __iomem *CTRLregaddr; void __iomem *ERR1regaddr; +#define SLIPORT_ERR1_REG_ERR_CODE_1 0x1 +#define SLIPORT_ERR1_REG_ERR_CODE_2 0x2 void __iomem *ERR2regaddr; +#define SLIPORT_ERR2_REG_FW_RESTART 0x0 +#define SLIPORT_ERR2_REG_FUNC_PROVISON 0x1 +#define SLIPORT_ERR2_REG_FORCED_DUMP 0x2 +#define SLIPORT_ERR2_REG_FAILURE_EQ 0x3 +#define SLIPORT_ERR2_REG_FAILURE_CQ 0x4 +#define SLIPORT_ERR2_REG_FAILURE_BUS 0x5 +#define SLIPORT_ERR2_REG_FAILURE_RQ 0x6 } if_type2; } u; -- cgit v1.2.3 From 1b51197d0fd0c06877c6df1bba84ac4008a7fc60 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 13 Dec 2011 13:23:09 -0500 Subject: [SCSI] lpfc 8.3.28: Add Loopback support for SLI4 adapters - Add Basic support for SLI4 Loopback. (CR 124951, 125766, 124951, 125843, 125832, 125843) - Added missing protection in setting/clearing of phba->link_flag bit field (CR 125994) - Use link type and link number obtained from READ_CONFIG mailbox command. (CR 126264) Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_bsg.c | 358 +++++++++++++++++++++++++++++---------- drivers/scsi/lpfc/lpfc_crtn.h | 9 +- drivers/scsi/lpfc/lpfc_els.c | 125 +++++++++++--- drivers/scsi/lpfc/lpfc_hbadisc.c | 60 +++---- drivers/scsi/lpfc/lpfc_hw.h | 2 +- drivers/scsi/lpfc/lpfc_hw4.h | 7 +- drivers/scsi/lpfc/lpfc_init.c | 40 ++++- drivers/scsi/lpfc/lpfc_mbox.c | 8 + drivers/scsi/lpfc/lpfc_sli.c | 28 ++- 9 files changed, 470 insertions(+), 167 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_sli.c') diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index c13e54760cb1..56a86baece5b 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -916,9 +916,11 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } else { switch (cmd) { case ELX_LOOPBACK_DATA: - diag_cmd_data_free(phba, - (struct lpfc_dmabufext *) - dmabuf); + if (phba->sli_rev < + LPFC_SLI_REV4) + diag_cmd_data_free(phba, + (struct lpfc_dmabufext + *)dmabuf); break; case ELX_LOOPBACK_XRI_SETUP: if ((phba->sli_rev == @@ -1000,7 +1002,8 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, error_ct_unsol_exit: if (!list_empty(&head)) list_del(&head); - if (evt_req_id == SLI_CT_ELX_LOOPBACK) + if ((phba->sli_rev < LPFC_SLI_REV4) && + (evt_req_id == SLI_CT_ELX_LOOPBACK)) return 0; return 1; } @@ -1566,7 +1569,7 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) struct diag_mode_set *loopback_mode; uint32_t link_flags; uint32_t timeout; - LPFC_MBOXQ_t *pmboxq; + LPFC_MBOXQ_t *pmboxq = NULL; int mbxstatus = MBX_SUCCESS; int i = 0; int rc = 0; @@ -1615,7 +1618,6 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) rc = -ETIMEDOUT; goto loopback_mode_exit; } - msleep(10); } @@ -1635,7 +1637,9 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) rc = -ENODEV; else { + spin_lock_irq(&phba->hbalock); phba->link_flag |= LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); /* wait for the link attention interrupt */ msleep(100); @@ -1659,7 +1663,7 @@ loopback_mode_exit: /* * Let SLI layer release mboxq if mbox command completed after timeout. */ - if (mbxstatus != MBX_TIMEOUT) + if (pmboxq && mbxstatus != MBX_TIMEOUT) mempool_free(pmboxq, phba->mbox_mem_pool); job_error: @@ -1700,11 +1704,16 @@ lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag) rc = -ENOMEM; goto link_diag_state_set_out; } + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3128 Set link to diagnostic state:x%x (x%x/x%x)\n", + diag, phba->sli4_hba.lnk_info.lnk_tp, + phba->sli4_hba.lnk_info.lnk_no); + link_diag_state = &pmboxq->u.mqe.un.link_diag_state; bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req, - phba->sli4_hba.link_state.number); + phba->sli4_hba.lnk_info.lnk_no); bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req, - phba->sli4_hba.link_state.type); + phba->sli4_hba.lnk_info.lnk_tp); if (diag) bf_set(lpfc_mbx_set_diag_state_diag, &link_diag_state->u.req, 1); @@ -1726,6 +1735,79 @@ link_diag_state_set_out: return rc; } +/** + * lpfc_sli4_bsg_set_internal_loopback - set sli4 internal loopback diagnostic + * @phba: Pointer to HBA context object. + * + * This function is responsible for issuing a sli4 mailbox command for setting + * up internal loopback diagnostic. + */ +static int +lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba) +{ + LPFC_MBOXQ_t *pmboxq; + uint32_t req_len, alloc_len; + struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback; + int mbxstatus = MBX_SUCCESS, rc = 0; + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) + return -ENOMEM; + req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, + LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK, + req_len, LPFC_SLI4_MBX_EMBED); + if (alloc_len != req_len) { + mempool_free(pmboxq, phba->mbox_mem_pool); + return -ENOMEM; + } + link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; + bf_set(lpfc_mbx_set_diag_state_link_num, + &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_no); + bf_set(lpfc_mbx_set_diag_state_link_type, + &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp); + bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req, + LPFC_DIAG_LOOPBACK_TYPE_SERDES); + + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); + if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3127 Failed setup loopback mode mailbox " + "command, rc:x%x, status:x%x\n", mbxstatus, + pmboxq->u.mb.mbxStatus); + rc = -ENODEV; + } + if (pmboxq && (mbxstatus != MBX_TIMEOUT)) + mempool_free(pmboxq, phba->mbox_mem_pool); + return rc; +} + +/** + * lpfc_sli4_diag_fcport_reg_setup - setup port registrations for diagnostic + * @phba: Pointer to HBA context object. + * + * This function set up SLI4 FC port registrations for diagnostic run, which + * includes all the rpis, vfi, and also vpi. + */ +static int +lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) +{ + int rc; + + if (phba->pport->fc_flag & FC_VFI_REGISTERED) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3136 Port still had vfi registered: " + "mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n", + phba->pport->fc_myDID, phba->fcf.fcfi, + phba->sli4_hba.vfi_ids[phba->pport->vfi], + phba->vpi_ids[phba->pport->vpi]); + return -EINVAL; + } + rc = lpfc_issue_reg_vfi(phba->pport); + return rc; +} + /** * lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command * @phba: Pointer to HBA context object. @@ -1738,10 +1820,8 @@ static int lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) { struct diag_mode_set *loopback_mode; - uint32_t link_flags, timeout, req_len, alloc_len; - struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback; - LPFC_MBOXQ_t *pmboxq = NULL; - int mbxstatus = MBX_SUCCESS, i, rc = 0; + uint32_t link_flags, timeout; + int i, rc = 0; /* no data to return just the return code */ job->reply->reply_payload_rcv_len = 0; @@ -1762,65 +1842,100 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) if (rc) goto job_error; + /* indicate we are in loobpack diagnostic mode */ + spin_lock_irq(&phba->hbalock); + phba->link_flag |= LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); + + /* reset port to start frome scratch */ + rc = lpfc_selective_reset(phba); + if (rc) + goto job_error; + /* bring the link to diagnostic mode */ + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3129 Bring link to diagnostic state.\n"); loopback_mode = (struct diag_mode_set *) job->request->rqst_data.h_vendor.vendor_cmd; link_flags = loopback_mode->type; timeout = loopback_mode->timeout * 100; rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); - if (rc) + if (rc) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3130 Failed to bring link to diagnostic " + "state, rc:x%x\n", rc); goto loopback_mode_exit; + } /* wait for link down before proceeding */ i = 0; while (phba->link_state != LPFC_LINK_DOWN) { if (i++ > timeout) { rc = -ETIMEDOUT; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3131 Timeout waiting for link to " + "diagnostic mode, timeout:%d ms\n", + timeout * 10); goto loopback_mode_exit; } msleep(10); } + /* set up loopback mode */ - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) { - rc = -ENOMEM; - goto loopback_mode_exit; - } - req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK, - req_len, LPFC_SLI4_MBX_EMBED); - if (alloc_len != req_len) { - rc = -ENOMEM; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3132 Set up loopback mode:x%x\n", link_flags); + + if (link_flags == INTERNAL_LOOP_BACK) + rc = lpfc_sli4_bsg_set_internal_loopback(phba); + else if (link_flags == EXTERNAL_LOOP_BACK) + rc = lpfc_hba_init_link_fc_topology(phba, + FLAGS_TOPOLOGY_MODE_PT_PT, + MBX_NOWAIT); + else { + rc = -EINVAL; + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "3141 Loopback mode:x%x not supported\n", + link_flags); goto loopback_mode_exit; } - link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; - bf_set(lpfc_mbx_set_diag_state_link_num, - &link_diag_loopback->u.req, phba->sli4_hba.link_state.number); - bf_set(lpfc_mbx_set_diag_state_link_type, - &link_diag_loopback->u.req, phba->sli4_hba.link_state.type); - if (link_flags == INTERNAL_LOOP_BACK) - bf_set(lpfc_mbx_set_diag_lpbk_type, - &link_diag_loopback->u.req, - LPFC_DIAG_LOOPBACK_TYPE_INTERNAL); - else - bf_set(lpfc_mbx_set_diag_lpbk_type, - &link_diag_loopback->u.req, - LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL); - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); - if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) - rc = -ENODEV; - else { - phba->link_flag |= LS_LOOPBACK_MODE; + if (!rc) { /* wait for the link attention interrupt */ msleep(100); i = 0; + while (phba->link_state < LPFC_LINK_UP) { + if (i++ > timeout) { + rc = -ETIMEDOUT; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3137 Timeout waiting for link up " + "in loopback mode, timeout:%d ms\n", + timeout * 10); + break; + } + msleep(10); + } + } + + /* port resource registration setup for loopback diagnostic */ + if (!rc) { + /* set up a none zero myDID for loopback test */ + phba->pport->fc_myDID = 1; + rc = lpfc_sli4_diag_fcport_reg_setup(phba); + } else + goto loopback_mode_exit; + + if (!rc) { + /* wait for the port ready */ + msleep(100); + i = 0; while (phba->link_state != LPFC_HBA_READY) { if (i++ > timeout) { rc = -ETIMEDOUT; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3133 Timeout waiting for port " + "loopback mode ready, timeout:%d ms\n", + timeout * 10); break; } msleep(10); @@ -1828,14 +1943,14 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) } loopback_mode_exit: + /* clear loopback diagnostic mode */ + if (rc) { + spin_lock_irq(&phba->hbalock); + phba->link_flag &= ~LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); + } lpfc_bsg_diag_mode_exit(phba); - /* - * Let SLI layer release mboxq if mbox command completed after timeout. - */ - if (pmboxq && (mbxstatus != MBX_TIMEOUT)) - mempool_free(pmboxq, phba->mbox_mem_pool); - job_error: /* make error code available to userspace */ job->reply->result = rc; @@ -1879,7 +1994,6 @@ lpfc_bsg_diag_loopback_mode(struct fc_bsg_job *job) rc = -ENODEV; return rc; - } /** @@ -1895,7 +2009,9 @@ lpfc_sli4_bsg_diag_mode_end(struct fc_bsg_job *job) struct Scsi_Host *shost; struct lpfc_vport *vport; struct lpfc_hba *phba; - int rc; + struct diag_mode_set *loopback_mode_end_cmd; + uint32_t timeout; + int rc, i; shost = job->shost; if (!shost) @@ -1913,11 +2029,47 @@ lpfc_sli4_bsg_diag_mode_end(struct fc_bsg_job *job) LPFC_SLI_INTF_IF_TYPE_2) return -ENODEV; + /* clear loopback diagnostic mode */ + spin_lock_irq(&phba->hbalock); + phba->link_flag &= ~LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); + loopback_mode_end_cmd = (struct diag_mode_set *) + job->request->rqst_data.h_vendor.vendor_cmd; + timeout = loopback_mode_end_cmd->timeout * 100; + rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); + if (rc) { + lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, + "3139 Failed to bring link to diagnostic " + "state, rc:x%x\n", rc); + goto loopback_mode_end_exit; + } + + /* wait for link down before proceeding */ + i = 0; + while (phba->link_state != LPFC_LINK_DOWN) { + if (i++ > timeout) { + rc = -ETIMEDOUT; + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, + "3140 Timeout waiting for link to " + "diagnostic mode_end, timeout:%d ms\n", + timeout * 10); + /* there is nothing much we can do here */ + break; + } + msleep(10); + } - if (!rc) - rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); + /* reset port resource registrations */ + rc = lpfc_selective_reset(phba); + phba->pport->fc_myDID = 0; +loopback_mode_end_exit: + /* make return code available to userspace */ + job->reply->result = rc; + /* complete the job back to userspace if no error */ + if (rc == 0) + job->job_done(job); return rc; } @@ -2012,9 +2164,9 @@ lpfc_sli4_bsg_link_diag_test(struct fc_bsg_job *job) } run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test; bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req, - phba->sli4_hba.link_state.number); + phba->sli4_hba.lnk_info.lnk_no); bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req, - phba->sli4_hba.link_state.type); + phba->sli4_hba.lnk_info.lnk_tp); bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req, link_diag_test_cmd->test_id); bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req, @@ -2091,10 +2243,18 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) if (!mbox) return -ENOMEM; - if (phba->sli_rev == LPFC_SLI_REV4) + if (phba->sli_rev < LPFC_SLI_REV4) + status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, + (uint8_t *)&phba->pport->fc_sparam, + mbox, *rpi); + else { *rpi = lpfc_sli4_alloc_rpi(phba); - status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, - (uint8_t *)&phba->pport->fc_sparam, mbox, *rpi); + status = lpfc_reg_rpi(phba, phba->pport->vpi, + phba->pport->fc_myDID, + (uint8_t *)&phba->pport->fc_sparam, + mbox, *rpi); + } + if (status) { mempool_free(mbox, phba->mbox_mem_pool); if (phba->sli_rev == LPFC_SLI_REV4) @@ -2117,7 +2277,8 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) return -ENODEV; } - *rpi = mbox->u.mb.un.varWords[0]; + if (phba->sli_rev < LPFC_SLI_REV4) + *rpi = mbox->u.mb.un.varWords[0]; lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); kfree(dmabuff); @@ -2142,7 +2303,12 @@ static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) if (mbox == NULL) return -ENOMEM; - lpfc_unreg_login(phba, 0, rpi, mbox); + if (phba->sli_rev < LPFC_SLI_REV4) + lpfc_unreg_login(phba, 0, rpi, mbox); + else + lpfc_unreg_login(phba, phba->pport->vpi, + phba->sli4_hba.rpi_ids[rpi], mbox); + status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { @@ -2630,15 +2796,15 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) uint32_t full_size; size_t segment_len = 0, segment_offset = 0, current_offset = 0; uint16_t rpi = 0; - struct lpfc_iocbq *cmdiocbq, *rspiocbq; - IOCB_t *cmd, *rsp; + struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL; + IOCB_t *cmd, *rsp = NULL; struct lpfc_sli_ct_request *ctreq; struct lpfc_dmabuf *txbmp; struct ulp_bde64 *txbpl = NULL; struct lpfc_dmabufext *txbuffer = NULL; struct list_head head; struct lpfc_dmabuf *curr; - uint16_t txxri, rxxri; + uint16_t txxri = 0, rxxri; uint32_t num_bde; uint8_t *ptr = NULL, *rx_databuf = NULL; int rc = 0; @@ -2665,7 +2831,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) rc = -EINVAL; goto loopback_test_exit; } - diag_mode = (struct diag_mode_test *) job->request->rqst_data.h_vendor.vendor_cmd; @@ -2720,18 +2885,19 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) if (rc) goto loopback_test_exit; - rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); - if (rc) { - lpfcdiag_loop_self_unreg(phba, rpi); - goto loopback_test_exit; - } + if (phba->sli_rev < LPFC_SLI_REV4) { + rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); + if (rc) { + lpfcdiag_loop_self_unreg(phba, rpi); + goto loopback_test_exit; + } - rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); - if (rc) { - lpfcdiag_loop_self_unreg(phba, rpi); - goto loopback_test_exit; + rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); + if (rc) { + lpfcdiag_loop_self_unreg(phba, rpi); + goto loopback_test_exit; + } } - evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, SLI_CT_ELX_LOOPBACK); if (!evt) { @@ -2746,7 +2912,8 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) spin_unlock_irqrestore(&phba->ct_ev_lock, flags); cmdiocbq = lpfc_sli_get_iocbq(phba); - rspiocbq = lpfc_sli_get_iocbq(phba); + if (phba->sli_rev < LPFC_SLI_REV4) + rspiocbq = lpfc_sli_get_iocbq(phba); txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (txbmp) { @@ -2759,14 +2926,18 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) } } - if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer || - !txbmp->virt) { + if (!cmdiocbq || !txbmp || !txbpl || !txbuffer || !txbmp->virt) { + rc = -ENOMEM; + goto err_loopback_test_exit; + } + if ((phba->sli_rev < LPFC_SLI_REV4) && !rspiocbq) { rc = -ENOMEM; goto err_loopback_test_exit; } cmd = &cmdiocbq->iocb; - rsp = &rspiocbq->iocb; + if (phba->sli_rev < LPFC_SLI_REV4) + rsp = &rspiocbq->iocb; INIT_LIST_HEAD(&head); list_add_tail(&head, &txbuffer->dma.list); @@ -2796,7 +2967,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) list_del(&head); /* Build the XMIT_SEQUENCE iocb */ - num_bde = (uint32_t)txbuffer->flag; cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); @@ -2813,16 +2983,27 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) cmd->ulpBdeCount = 1; cmd->ulpLe = 1; cmd->ulpClass = CLASS3; - cmd->ulpContext = txxri; + if (phba->sli_rev < LPFC_SLI_REV4) { + cmd->ulpContext = txxri; + } else { + cmd->un.xseq64.bdl.ulpIoTag32 = 0; + cmd->un.ulpWord[3] = phba->sli4_hba.rpi_ids[rpi]; + cmdiocbq->context3 = txbmp; + cmdiocbq->sli4_xritag = NO_XRI; + cmd->unsli3.rcvsli3.ox_id = 0xffff; + } cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; cmdiocbq->vport = phba->pport; - iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); - if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) { + if ((iocb_stat != IOCB_SUCCESS) || ((phba->sli_rev < LPFC_SLI_REV4) && + (rsp->ulpStatus != IOCB_SUCCESS))) { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "3126 Failed loopback test issue iocb: " + "iocb_stat:x%x\n", iocb_stat); rc = -EIO; goto err_loopback_test_exit; } @@ -2832,9 +3013,12 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) evt->wq, !list_empty(&evt->events_to_see), ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); evt->waiting = 0; - if (list_empty(&evt->events_to_see)) + if (list_empty(&evt->events_to_see)) { rc = (time_left) ? -EINTR : -ETIMEDOUT; - else { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "3125 Not receiving unsolicited event, " + "rc:x%x\n", rc); + } else { spin_lock_irqsave(&phba->ct_ev_lock, flags); list_move(evt->events_to_see.prev, &evt->events_to_get); evdat = list_entry(evt->events_to_get.prev, @@ -2891,7 +3075,7 @@ loopback_test_exit: job->reply->result = rc; job->dd_data = NULL; /* complete the job back to userspace if no error */ - if (rc == 0) + if (rc == IOCB_SUCCESS) job->job_done(job); return rc; } @@ -3078,7 +3262,9 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, && (mb->un.varWords[1] == 1)) { phba->wait_4_mlo_maint_flg = 1; } else if (mb->un.varWords[0] == SETVAR_MLORST) { + spin_lock_irq(&phba->hbalock); phba->link_flag &= ~LS_LOOPBACK_MODE; + spin_unlock_irq(&phba->hbalock); phba->fc_topology = LPFC_TOPOLOGY_PT_PT; } break; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index bcc021f3c8eb..26924b7a6cde 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -78,6 +78,7 @@ void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_unregister_vfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *, @@ -453,7 +454,11 @@ int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int); uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *); int lpfc_sli4_queue_create(struct lpfc_hba *); void lpfc_sli4_queue_destroy(struct lpfc_hba *); -int lpfc_sli4_read_config(struct lpfc_hba *phba); -int lpfc_scsi_buf_update(struct lpfc_hba *phba); void lpfc_sli4_abts_err_handler(struct lpfc_hba *, struct lpfc_nodelist *, struct sli4_wcqe_xri_aborted *); +int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t); +int lpfc_issue_reg_vfi(struct lpfc_vport *); +int lpfc_issue_unreg_vfi(struct lpfc_vport *); +int lpfc_selective_reset(struct lpfc_hba *); +int lpfc_sli4_read_config(struct lpfc_hba *phba); +int lpfc_scsi_buf_update(struct lpfc_hba *phba); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 0b662db23284..7afc757338de 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -421,13 +421,13 @@ fail: * @vport: pointer to a host virtual N_Port data structure. * * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for - * the @vport. This mailbox command is necessary for FCoE only. + * the @vport. This mailbox command is necessary for SLI4 port only. * * Return code * 0 - successfully issued REG_VFI for @vport * A failure code otherwise. **/ -static int +int lpfc_issue_reg_vfi(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; @@ -438,10 +438,14 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) int rc = 0; sp = &phba->fc_fabparam; - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - rc = -ENODEV; - goto fail; + /* move forward in case of SLI4 FC port loopback test */ + if ((phba->sli_rev == LPFC_SLI_REV4) && + !(phba->link_flag & LS_LOOPBACK_MODE)) { + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + rc = -ENODEV; + goto fail; + } } dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); @@ -486,6 +490,54 @@ fail: return rc; } +/** + * lpfc_issue_unreg_vfi - Unregister VFI for this vport's fabric login + * @vport: pointer to a host virtual N_Port data structure. + * + * This routine issues a UNREG_VFI mailbox with the vfi, vpi, fcfi triplet for + * the @vport. This mailbox command is necessary for SLI4 port only. + * + * Return code + * 0 - successfully issued REG_VFI for @vport + * A failure code otherwise. + **/ +int +lpfc_issue_unreg_vfi(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + struct Scsi_Host *shost; + LPFC_MBOXQ_t *mboxq; + int rc; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2556 UNREG_VFI mbox allocation failed" + "HBA state x%x\n", phba->pport->port_state); + return -ENOMEM; + } + + lpfc_unreg_vfi(mboxq, vport); + mboxq->vport = vport; + mboxq->mbox_cmpl = lpfc_unregister_vfi_cmpl; + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2557 UNREG_VFI issue mbox failed rc x%x " + "HBA state x%x\n", + rc, phba->pport->port_state); + mempool_free(mboxq, phba->mbox_mem_pool); + return -EIO; + } + + shost = lpfc_shost_from_vport(vport); + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VFI_REGISTERED; + spin_unlock_irq(shost->host_lock); + return 0; +} + /** * lpfc_check_clean_addr_bit - Check whether assigned FCID is clean. * @vport: pointer to a host virtual N_Port data structure. @@ -615,7 +667,9 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "1816 FLOGI NPIV supported, " "response data 0x%x\n", sp->cmn.response_multiple_NPort); + spin_lock_irq(&phba->hbalock); phba->link_flag |= LS_NPIV_FAB_SUPPORTED; + spin_unlock_irq(&phba->hbalock); } else { /* Because we asked f/w for NPIV it still expects us to call reg_vnpid atleast for the physcial host */ @@ -623,7 +677,9 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, LOG_ELS | LOG_VPORT, "1817 Fabric does not support NPIV " "- configuring single port mode.\n"); + spin_lock_irq(&phba->hbalock); phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED; + spin_unlock_irq(&phba->hbalock); } } @@ -686,11 +742,16 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_do_scr_ns_plogi(phba, vport); } else if (vport->fc_flag & FC_VFI_REGISTERED) lpfc_issue_init_vpi(vport); - else + else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3135 Need register VFI: (x%x/%x)\n", + vport->fc_prevDID, vport->fc_myDID); lpfc_issue_reg_vfi(vport); + } } return 0; } + /** * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port * @vport: pointer to a host virtual N_Port data structure. @@ -907,9 +968,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no * alpa map would take too long otherwise. */ - if (phba->alpa_map[0] == 0) { + if (phba->alpa_map[0] == 0) vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS; - } if ((phba->sli_rev == LPFC_SLI_REV4) && (!(vport->fc_flag & FC_VFI_REGISTERED) || (vport->fc_prevDID != vport->fc_myDID))) { @@ -1164,8 +1224,7 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { icmd = &iocb->iocb; - if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR && - icmd->un.elsreq64.bdl.ulpIoTag32) { + if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { ndlp = (struct lpfc_nodelist *)(iocb->context1); if (ndlp && NLP_CHK_NODE_ACT(ndlp) && (ndlp->nlp_DID == Fabric_DID)) @@ -4879,23 +4938,31 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, sizeof(struct lpfc_name)); if (!rc) { - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + if (phba->sli_rev < LPFC_SLI_REV4) { + mbox = mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!mbox) + return 1; + lpfc_linkdown(phba); + lpfc_init_link(phba, mbox, + phba->cfg_topology, + phba->cfg_link_speed); + mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mbox, + MBX_NOWAIT); + lpfc_set_loopback_flag(phba); + if (rc == MBX_NOT_FINISHED) + mempool_free(mbox, phba->mbox_mem_pool); return 1; - - lpfc_linkdown(phba); - lpfc_init_link(phba, mbox, - phba->cfg_topology, - phba->cfg_link_speed); - mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - lpfc_set_loopback_flag(phba); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); + } else { + /* abort the flogi coming back to ourselves + * due to external loopback on the port. + */ + lpfc_els_abort_flogi(phba); + return 0; } - return 1; } else if (rc > 0) { /* greater than */ spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_PT2PT_PLOGI; @@ -5850,8 +5917,12 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, vport->fc_myDID = vport->fc_prevDID; if (phba->sli_rev < LPFC_SLI_REV4) lpfc_issue_fabric_reglogin(vport); - else + else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3138 Need register VFI: (x%x/%x)\n", + vport->fc_prevDID, vport->fc_myDID); lpfc_issue_reg_vfi(vport); + } } } return 0; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index d96498581ebe..678a4b11059c 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1074,6 +1074,12 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mempool_free(pmb, phba->mbox_mem_pool); + /* don't perform discovery for SLI4 loopback diagnostic test */ + if ((phba->sli_rev == LPFC_SLI_REV4) && + !(phba->hba_flag & HBA_FCOE_MODE) && + (phba->link_flag & LS_LOOPBACK_MODE)) + return; + if (phba->fc_topology == LPFC_TOPOLOGY_LOOP && vport->fc_flag & FC_PUBLIC_LOOP && !(vport->fc_flag & FC_LBIT)) { @@ -2847,10 +2853,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_disc_list_loopmap(vport); /* Start discovery */ lpfc_disc_start(vport); - goto fail_free_mem; + goto out_free_mem; } lpfc_vport_set_state(vport, FC_VPORT_FAILED); - goto fail_free_mem; + goto out_free_mem; } /* The VPI is implicitly registered when the VFI is registered */ spin_lock_irq(shost->host_lock); @@ -2860,6 +2866,13 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(shost->host_lock); + /* In case SLI4 FC loopback test, we are ready */ + if ((phba->sli_rev == LPFC_SLI_REV4) && + (phba->link_flag & LS_LOOPBACK_MODE)) { + phba->link_state = LPFC_HBA_READY; + goto out_free_mem; + } + if (vport->port_state == LPFC_FABRIC_CFG_LINK) { /* For private loop just start discovery and we are done. */ if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && @@ -2874,7 +2887,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) } } -fail_free_mem: +out_free_mem: mempool_free(mboxq, phba->mbox_mem_pool); lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); kfree(dmabuf); @@ -3235,15 +3248,14 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else if (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_DOWN) { phba->fc_stat.LinkDown++; - if (phba->link_flag & LS_LOOPBACK_MODE) { + if (phba->link_flag & LS_LOOPBACK_MODE) lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1308 Link Down Event in loop back mode " "x%x received " "Data: x%x x%x x%x\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag); - } - else { + else lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1305 Link Down Event x%x received " "Data: x%x x%x x%x x%x x%x\n", @@ -3251,7 +3263,6 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) phba->pport->port_state, vport->fc_flag, bf_get(lpfc_mbx_read_top_mm, la), bf_get(lpfc_mbx_read_top_fa, la)); - } lpfc_mbx_issue_link_down(phba); } if ((bf_get(lpfc_mbx_read_top_mm, la)) && @@ -5682,7 +5693,7 @@ out: * * This function frees memory associated with the mailbox command. */ -static void +void lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { struct lpfc_vport *vport = mboxq->vport; @@ -5734,7 +5745,6 @@ lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) int lpfc_unregister_fcf_prep(struct lpfc_hba *phba) { - LPFC_MBOXQ_t *mbox; struct lpfc_vport **vports; struct lpfc_nodelist *ndlp; struct Scsi_Host *shost; @@ -5770,35 +5780,9 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba) /* Cleanup any outstanding ELS commands */ lpfc_els_flush_all_cmd(phba); - /* Unregister VFI */ - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2556 UNREG_VFI mbox allocation failed" - "HBA state x%x\n", phba->pport->port_state); - return -ENOMEM; - } - - lpfc_unreg_vfi(mbox, phba->pport); - mbox->vport = phba->pport; - mbox->mbox_cmpl = lpfc_unregister_vfi_cmpl; - - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2557 UNREG_VFI issue mbox failed rc x%x " - "HBA state x%x\n", - rc, phba->pport->port_state); - mempool_free(mbox, phba->mbox_mem_pool); - return -EIO; - } - - shost = lpfc_shost_from_vport(phba->pport); - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); - - return 0; + /* Unregister the physical port VFI */ + rc = lpfc_issue_unreg_vfi(phba->pport); + return rc; } /** diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 73fc5318641b..7245bead3755 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1858,8 +1858,8 @@ typedef struct { uint8_t fabric_AL_PA; /* If using a Fabric Assigned AL_PA */ #endif -#define FLAGS_LOCAL_LB 0x01 /* link_flags (=1) ENDEC loopback */ #define FLAGS_TOPOLOGY_MODE_LOOP_PT 0x00 /* Attempt loop then pt-pt */ +#define FLAGS_LOCAL_LB 0x01 /* link_flags (=1) ENDEC loopback */ #define FLAGS_TOPOLOGY_MODE_PT_PT 0x02 /* Attempt pt-pt only */ #define FLAGS_TOPOLOGY_MODE_LOOP 0x04 /* Attempt loop only */ #define FLAGS_TOPOLOGY_MODE_PT_LOOP 0x06 /* Attempt pt-pt then loop */ diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 43c4c56f9e68..e5bfa7f334e3 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1351,11 +1351,11 @@ struct lpfc_mbx_set_link_diag_loopback { struct { uint32_t word0; #define lpfc_mbx_set_diag_lpbk_type_SHIFT 0 -#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000001 +#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000003 #define lpfc_mbx_set_diag_lpbk_type_WORD word0 #define LPFC_DIAG_LOOPBACK_TYPE_DISABLE 0x0 #define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL 0x1 -#define LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL 0x2 +#define LPFC_DIAG_LOOPBACK_TYPE_SERDES 0x2 #define lpfc_mbx_set_diag_lpbk_link_num_SHIFT 16 #define lpfc_mbx_set_diag_lpbk_link_num_MASK 0x0000003F #define lpfc_mbx_set_diag_lpbk_link_num_WORD word0 @@ -3324,6 +3324,9 @@ struct wqe_rctl_dfctl { #define wqe_la_SHIFT 3 #define wqe_la_MASK 0x000000001 #define wqe_la_WORD word5 +#define wqe_xo_SHIFT 6 +#define wqe_xo_MASK 0x000000001 +#define wqe_xo_WORD word5 #define wqe_ls_SHIFT 7 #define wqe_ls_MASK 0x000000001 #define wqe_ls_WORD word5 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index cb714d2342d4..dfea2dada02c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -627,6 +627,28 @@ lpfc_config_port_post(struct lpfc_hba *phba) **/ int lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag) +{ + return lpfc_hba_init_link_fc_topology(phba, phba->cfg_topology, flag); +} + +/** + * lpfc_hba_init_link_fc_topology - Initialize FC link with desired topology + * @phba: pointer to lpfc hba data structure. + * @fc_topology: desired fc topology. + * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT + * + * This routine will issue the INIT_LINK mailbox command call. + * It is available to other drivers through the lpfc_hba data + * structure for use as a delayed link up mechanism with the + * module parameter lpfc_suppress_link_up. + * + * Return code + * 0 - success + * Any other value - error + **/ +int +lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, + uint32_t flag) { struct lpfc_vport *vport = phba->pport; LPFC_MBOXQ_t *pmb; @@ -661,9 +683,10 @@ lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag) phba->cfg_link_speed); phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; } - lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); + lpfc_init_link(phba, pmb, fc_topology, phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - lpfc_set_loopback_flag(phba); + if (phba->sli_rev < LPFC_SLI_REV4) + lpfc_set_loopback_flag(phba); rc = lpfc_sli_issue_mbox(phba, pmb, flag); if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -6654,9 +6677,10 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.sp_eq->queue_id); /* Set up fast-path event queue */ - if (!phba->sli4_hba.fp_eq) { + if (phba->cfg_fcp_eq_count && !phba->sli4_hba.fp_eq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3147 Fast-path EQs not allocated\n"); + rc = -ENOMEM; goto out_destroy_sp_eq; } for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { @@ -6664,6 +6688,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0522 Fast-path EQ (%d) not " "allocated\n", fcp_eqidx); + rc = -ENOMEM; goto out_destroy_fp_eq; } rc = lpfc_eq_create(phba, phba->sli4_hba.fp_eq[fcp_eqidx], @@ -6688,6 +6713,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.mbx_cq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0528 Mailbox CQ not allocated\n"); + rc = -ENOMEM; goto out_destroy_fp_eq; } rc = lpfc_cq_create(phba, phba->sli4_hba.mbx_cq, phba->sli4_hba.sp_eq, @@ -6707,6 +6733,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.els_cq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0530 ELS CQ not allocated\n"); + rc = -ENOMEM; goto out_destroy_mbx_cq; } rc = lpfc_cq_create(phba, phba->sli4_hba.els_cq, phba->sli4_hba.sp_eq, @@ -6727,6 +6754,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3148 Fast-path FCP CQ array not " "allocated\n"); + rc = -ENOMEM; goto out_destroy_els_cq; } fcp_cqidx = 0; @@ -6735,6 +6763,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0526 Fast-path FCP CQ (%d) not " "allocated\n", fcp_cqidx); + rc = -ENOMEM; goto out_destroy_fcp_cq; } if (phba->cfg_fcp_eq_count) @@ -6773,6 +6802,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.mbx_wq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0538 Slow-path MQ not allocated\n"); + rc = -ENOMEM; goto out_destroy_fcp_cq; } rc = lpfc_mq_create(phba, phba->sli4_hba.mbx_wq, @@ -6792,6 +6822,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.els_wq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0536 Slow-path ELS WQ not allocated\n"); + rc = -ENOMEM; goto out_destroy_mbx_wq; } rc = lpfc_wq_create(phba, phba->sli4_hba.els_wq, @@ -6812,6 +6843,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3149 Fast-path FCP WQ array not " "allocated\n"); + rc = -ENOMEM; goto out_destroy_els_wq; } for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) { @@ -6819,6 +6851,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0534 Fast-path FCP WQ (%d) not " "allocated\n", fcp_wqidx); + rc = -ENOMEM; goto out_destroy_fcp_wq; } rc = lpfc_wq_create(phba, phba->sli4_hba.fcp_wq[fcp_wqidx], @@ -6849,6 +6882,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) if (!phba->sli4_hba.hdr_rq || !phba->sli4_hba.dat_rq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0540 Receive Queue not allocated\n"); + rc = -ENOMEM; goto out_destroy_fcp_wq; } diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 328782efc839..20336f09fb3c 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -2133,6 +2133,14 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam); reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID); + lpfc_printf_vlog(vport, KERN_INFO, LOG_MBOX, + "3134 Register VFI, mydid:x%x, fcfi:%d, " + " vfi:%d, vpi:%d, fc_pname:%x%x\n", + vport->fc_myDID, + vport->phba->fcf.fcfi, + vport->phba->sli4_hba.vfi_ids[vport->vfi], + vport->phba->vpi_ids[vport->vpi], + reg_vfi->wwn[0], reg_vfi->wwn[1]); } /** diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e27cb44b3ec2..23a27592388c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3619,8 +3619,8 @@ lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask) * lpfc_reset_barrier - Make HBA ready for HBA reset * @phba: Pointer to HBA context object. * - * This function is called before resetting an HBA. This - * function requests HBA to quiesce DMAs before a reset. + * This function is called before resetting an HBA. This function is called + * with hbalock held and requests HBA to quiesce DMAs before a reset. **/ void lpfc_reset_barrier(struct lpfc_hba *phba) { @@ -6267,9 +6267,12 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) goto out_unset_queue; } } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { - rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); - if (rc) - goto out_unset_queue; + /* don't perform init_link on SLI4 FC port loopback test */ + if (!(phba->link_flag & LS_LOOPBACK_MODE)) { + rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); + if (rc) + goto out_unset_queue; + } } mempool_free(mboxq, phba->mbox_mem_pool); return rc; @@ -7540,6 +7543,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, struct ulp_bde64 *bpl = NULL; struct ulp_bde64 bde; struct sli4_sge *sgl = NULL; + struct lpfc_dmabuf *dmabuf; IOCB_t *icmd; int numBdes = 0; int i = 0; @@ -7558,9 +7562,12 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, * have not been byteswapped yet so there is no * need to swap them back. */ - bpl = (struct ulp_bde64 *) - ((struct lpfc_dmabuf *)piocbq->context3)->virt; + if (piocbq->context3) + dmabuf = (struct lpfc_dmabuf *)piocbq->context3; + else + return xritag; + bpl = (struct ulp_bde64 *)dmabuf->virt; if (!bpl) return xritag; @@ -7670,6 +7677,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, struct ulp_bde64 bde; struct lpfc_nodelist *ndlp; uint32_t *pcmd; + uint32_t if_type; fip = phba->hba_flag & HBA_FIP_SUPPORT; /* The fcp commands will set command type */ @@ -7743,7 +7751,9 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, >> LPFC_FIP_ELS_ID_SHIFT); pcmd = (uint32_t *) (((struct lpfc_dmabuf *) iocbq->context2)->virt); - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { if (pcmd && (*pcmd == ELS_CMD_FLOGI || *pcmd == ELS_CMD_SCR || *pcmd == ELS_CMD_PLOGI)) { @@ -7776,6 +7786,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, /* The entire sequence is transmitted for this IOCB */ xmit_len = total_len; cmnd = CMD_XMIT_SEQUENCE64_CR; + if (phba->link_flag & LS_LOOPBACK_MODE) + bf_set(wqe_xo, &wqe->xmit_sequence.wge_ctl, 1); case CMD_XMIT_SEQUENCE64_CR: /* word3 iocb=io_tag32 wqe=reserved */ wqe->xmit_sequence.rsvd3 = 0; -- cgit v1.2.3