diff options
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 59 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 20 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 65 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 116 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 29 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 294 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 88 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nvme.c | 356 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nvme.h | 17 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nvmet.c | 71 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nvmet.h | 10 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 193 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 14 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 2 |
18 files changed, 964 insertions, 386 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 231302273257..61fb46da05d4 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -55,9 +55,10 @@ struct lpfc_sli2_slim; #define LPFC_MAX_SG_SLI4_SEG_CNT_DIF 128 /* sg element count per scsi cmnd */ #define LPFC_MAX_SG_SEG_CNT_DIF 512 /* sg element count per scsi cmnd */ #define LPFC_MAX_SG_SEG_CNT 4096 /* sg element count per scsi cmnd */ +#define LPFC_MIN_SG_SEG_CNT 32 /* sg element count per scsi cmnd */ #define LPFC_MAX_SGL_SEG_CNT 512 /* SGL element count per scsi cmnd */ #define LPFC_MAX_BPL_SEG_CNT 4096 /* BPL element count per scsi cmnd */ -#define LPFC_MAX_NVME_SEG_CNT 128 /* max SGL element cnt per NVME cmnd */ +#define LPFC_MAX_NVME_SEG_CNT 256 /* max SGL element cnt per NVME cmnd */ #define LPFC_MAX_SGE_SIZE 0x80000000 /* Maximum data allowed in a SGE */ #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ @@ -705,7 +706,6 @@ struct lpfc_hba { * capability */ #define HBA_NVME_IOQ_FLUSH 0x80000 /* NVME IO queues flushed. */ -#define NVME_XRI_ABORT_EVENT 0x100000 uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; @@ -945,6 +945,8 @@ struct lpfc_hba { struct list_head lpfc_nvme_buf_list_get; struct list_head lpfc_nvme_buf_list_put; uint32_t total_nvme_bufs; + uint32_t get_nvme_bufs; + uint32_t put_nvme_bufs; struct list_head lpfc_iocb_list; uint32_t total_iocbq_bufs; struct list_head active_rrq_list; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 82f6e219ee34..d188fb565a32 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -148,6 +148,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = vport->phba; struct lpfc_nvmet_tgtport *tgtp; struct nvme_fc_local_port *localport; + struct lpfc_nvme_lport *lport; struct lpfc_nodelist *ndlp; struct nvme_fc_remote_port *nrport; uint64_t data1, data2, data3, tot; @@ -198,10 +199,15 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, } len += snprintf(buf+len, PAGE_SIZE-len, - "LS: Xmt %08x Drop %08x Cmpl %08x Err %08x\n", + "LS: Xmt %08x Drop %08x Cmpl %08x\n", atomic_read(&tgtp->xmt_ls_rsp), atomic_read(&tgtp->xmt_ls_drop), - atomic_read(&tgtp->xmt_ls_rsp_cmpl), + atomic_read(&tgtp->xmt_ls_rsp_cmpl)); + + len += snprintf(buf + len, PAGE_SIZE - len, + "LS: RSP Abort %08x xb %08x Err %08x\n", + atomic_read(&tgtp->xmt_ls_rsp_aborted), + atomic_read(&tgtp->xmt_ls_rsp_xb_set), atomic_read(&tgtp->xmt_ls_rsp_error)); len += snprintf(buf+len, PAGE_SIZE-len, @@ -236,6 +242,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, atomic_read(&tgtp->xmt_fcp_rsp_drop)); len += snprintf(buf+len, PAGE_SIZE-len, + "FCP Rsp Abort: %08x xb %08x xricqe %08x\n", + atomic_read(&tgtp->xmt_fcp_rsp_aborted), + atomic_read(&tgtp->xmt_fcp_rsp_xb_set), + atomic_read(&tgtp->xmt_fcp_xri_abort_cqe)); + + len += snprintf(buf + len, PAGE_SIZE - len, "ABORT: Xmt %08x Cmpl %08x\n", atomic_read(&tgtp->xmt_fcp_abort), atomic_read(&tgtp->xmt_fcp_abort_cmpl)); @@ -271,6 +283,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, wwn_to_u64(vport->fc_portname.u.wwn)); return len; } + lport = (struct lpfc_nvme_lport *)localport->private; len = snprintf(buf, PAGE_SIZE, "NVME Initiator Enabled\n"); spin_lock_irq(shost->host_lock); @@ -347,9 +360,16 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, len += snprintf(buf + len, PAGE_SIZE - len, "\nNVME Statistics\n"); len += snprintf(buf+len, PAGE_SIZE-len, - "LS: Xmt %016x Cmpl %016x\n", + "LS: Xmt %010x Cmpl %010x Abort %08x\n", atomic_read(&phba->fc4NvmeLsRequests), - atomic_read(&phba->fc4NvmeLsCmpls)); + atomic_read(&phba->fc4NvmeLsCmpls), + atomic_read(&lport->xmt_ls_abort)); + + len += snprintf(buf + len, PAGE_SIZE - len, + "LS XMIT: Err %08x CMPL: xb %08x Err %08x\n", + atomic_read(&lport->xmt_ls_err), + atomic_read(&lport->cmpl_ls_xb), + atomic_read(&lport->cmpl_ls_err)); tot = atomic_read(&phba->fc4NvmeIoCmpls); data1 = atomic_read(&phba->fc4NvmeInputRequests); @@ -360,8 +380,22 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, data1, data2, data3); len += snprintf(buf+len, PAGE_SIZE-len, - " Cmpl %016llx Outstanding %016llx\n", - tot, (data1 + data2 + data3) - tot); + " noxri %08x nondlp %08x qdepth %08x " + "wqerr %08x\n", + atomic_read(&lport->xmt_fcp_noxri), + atomic_read(&lport->xmt_fcp_bad_ndlp), + atomic_read(&lport->xmt_fcp_qdepth), + atomic_read(&lport->xmt_fcp_wqerr)); + + len += snprintf(buf + len, PAGE_SIZE - len, + " Cmpl %016llx Outstanding %016llx Abort %08x\n", + tot, ((data1 + data2 + data3) - tot), + atomic_read(&lport->xmt_fcp_abort)); + + len += snprintf(buf + len, PAGE_SIZE - len, + "FCP CMPL: xb %08x Err %08x\n", + atomic_read(&lport->cmpl_fcp_xb), + atomic_read(&lport->cmpl_fcp_err)); return len; } @@ -3366,12 +3400,13 @@ LPFC_ATTR_R(suppress_rsp, 1, 0, 1, /* * lpfc_nvmet_mrq: Specify number of RQ pairs for processing NVMET cmds + * lpfc_nvmet_mrq = 0 driver will calcualte optimal number of RQ pairs * lpfc_nvmet_mrq = 1 use a single RQ pair * lpfc_nvmet_mrq >= 2 use specified RQ pairs for MRQ * */ LPFC_ATTR_R(nvmet_mrq, - 1, 1, 16, + LPFC_NVMET_MRQ_AUTO, LPFC_NVMET_MRQ_AUTO, LPFC_NVMET_MRQ_MAX, "Specify number of RQ pairs for processing NVMET cmds"); /* @@ -5139,7 +5174,7 @@ LPFC_ATTR(delay_discovery, 0, 0, 1, * this parameter will be limited to 128 if BlockGuard is enabled under SLI4 * and will be limited to 512 if BlockGuard is enabled under SLI3. */ -LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT, +LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_MIN_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count"); /* @@ -6362,6 +6397,9 @@ lpfc_nvme_mod_param_dep(struct lpfc_hba *phba) phba->cfg_nvmet_fb_size = LPFC_NVMET_FB_SZ_MAX; } + if (!phba->cfg_nvmet_mrq) + phba->cfg_nvmet_mrq = phba->cfg_nvme_io_channel; + /* Adjust lpfc_nvmet_mrq to avoid running out of WQE slots */ if (phba->cfg_nvmet_mrq > phba->cfg_nvme_io_channel) { phba->cfg_nvmet_mrq = phba->cfg_nvme_io_channel; @@ -6369,10 +6407,13 @@ lpfc_nvme_mod_param_dep(struct lpfc_hba *phba) "6018 Adjust lpfc_nvmet_mrq to %d\n", phba->cfg_nvmet_mrq); } + if (phba->cfg_nvmet_mrq > LPFC_NVMET_MRQ_MAX) + phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_MAX; + } else { /* Not NVME Target mode. Turn off Target parameters. */ phba->nvmet_support = 0; - phba->cfg_nvmet_mrq = 0; + phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_OFF; phba->cfg_nvmet_fb_size = 0; } diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 4e858b38529a..559f9aa0ed08 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -254,6 +254,8 @@ void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctxp); int lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, struct fc_frame_header *fc_hdr); +void lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba); +void lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba); void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *, uint16_t); int lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index f77673ab4a84..9d20d2c208c7 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -471,6 +471,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) "Parse GID_FTrsp: did:x%x flg:x%x x%x", Did, ndlp->nlp_flag, vport->fc_flag); + ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); /* By default, the driver expects to support FCP FC4 */ if (fc4_type == FC_TYPE_FCP) ndlp->nlp_fc4_type |= NLP_FC4_FCP; @@ -685,6 +686,25 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_els_flush_rscn(vport); goto out; } + + spin_lock_irq(shost->host_lock); + if (vport->fc_flag & FC_RSCN_DEFERRED) { + vport->fc_flag &= ~FC_RSCN_DEFERRED; + spin_unlock_irq(shost->host_lock); + + /* + * Skip processing the NS response + * Re-issue the NS cmd + */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "0151 Process Deferred RSCN Data: x%x x%x\n", + vport->fc_flag, vport->fc_rscn_id_cnt); + lpfc_els_handle_rscn(vport); + + goto out; + } + spin_unlock_irq(shost->host_lock); + if (irsp->ulpStatus) { /* Check for retry */ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 2bf5ad3b1512..17ea3bb04266 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -750,6 +750,8 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) struct lpfc_hba *phba = vport->phba; struct lpfc_nvmet_tgtport *tgtp; struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; + struct nvme_fc_local_port *localport; + struct lpfc_nvme_lport *lport; uint64_t tot, data1, data2, data3; int len = 0; int cnt; @@ -775,10 +777,15 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) } len += snprintf(buf + len, size - len, - "LS: Xmt %08x Drop %08x Cmpl %08x Err %08x\n", + "LS: Xmt %08x Drop %08x Cmpl %08x\n", atomic_read(&tgtp->xmt_ls_rsp), atomic_read(&tgtp->xmt_ls_drop), - atomic_read(&tgtp->xmt_ls_rsp_cmpl), + atomic_read(&tgtp->xmt_ls_rsp_cmpl)); + + len += snprintf(buf + len, size - len, + "LS: RSP Abort %08x xb %08x Err %08x\n", + atomic_read(&tgtp->xmt_ls_rsp_aborted), + atomic_read(&tgtp->xmt_ls_rsp_xb_set), atomic_read(&tgtp->xmt_ls_rsp_error)); len += snprintf(buf + len, size - len, @@ -812,6 +819,12 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) atomic_read(&tgtp->xmt_fcp_rsp_drop)); len += snprintf(buf + len, size - len, + "FCP Rsp Abort: %08x xb %08x xricqe %08x\n", + atomic_read(&tgtp->xmt_fcp_rsp_aborted), + atomic_read(&tgtp->xmt_fcp_rsp_xb_set), + atomic_read(&tgtp->xmt_fcp_xri_abort_cqe)); + + len += snprintf(buf + len, size - len, "ABORT: Xmt %08x Cmpl %08x\n", atomic_read(&tgtp->xmt_fcp_abort), atomic_read(&tgtp->xmt_fcp_abort_cmpl)); @@ -885,8 +898,38 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) data1, data2, data3); len += snprintf(buf + len, size - len, - " Cmpl %016llx Outstanding %016llx\n", + " Cmpl %016llx Outstanding %016llx\n", tot, (data1 + data2 + data3) - tot); + + localport = vport->localport; + if (!localport) + return len; + lport = (struct lpfc_nvme_lport *)localport->private; + if (!lport) + return len; + + len += snprintf(buf + len, size - len, + "LS Xmt Err: Abrt %08x Err %08x " + "Cmpl Err: xb %08x Err %08x\n", + atomic_read(&lport->xmt_ls_abort), + atomic_read(&lport->xmt_ls_err), + atomic_read(&lport->cmpl_ls_xb), + atomic_read(&lport->cmpl_ls_err)); + + len += snprintf(buf + len, size - len, + "FCP Xmt Err: noxri %06x nondlp %06x " + "qdepth %06x wqerr %06x Abrt %06x\n", + atomic_read(&lport->xmt_fcp_noxri), + atomic_read(&lport->xmt_fcp_bad_ndlp), + atomic_read(&lport->xmt_fcp_qdepth), + atomic_read(&lport->xmt_fcp_wqerr), + atomic_read(&lport->xmt_fcp_abort)); + + len += snprintf(buf + len, size - len, + "FCP Cmpl Err: xb %08x Err %08x\n", + atomic_read(&lport->cmpl_fcp_xb), + atomic_read(&lport->cmpl_fcp_err)); + } return len; @@ -3213,7 +3256,7 @@ lpfc_idiag_cqs_for_eq(struct lpfc_hba *phba, char *pbuffer, return 1; } - if (eqidx < phba->cfg_nvmet_mrq) { + if ((eqidx < phba->cfg_nvmet_mrq) && phba->nvmet_support) { /* NVMET CQset */ qp = phba->sli4_hba.nvmet_cqset[eqidx]; *len = __lpfc_idiag_print_cq(qp, "NVMET CQset", pbuffer, *len); @@ -3246,7 +3289,7 @@ __lpfc_idiag_print_eq(struct lpfc_queue *qp, char *eqtype, len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n%s EQ info: EQ-STAT[max:x%x noE:x%x " - "bs:x%x proc:x%llx eqd %d]\n", + "cqe_proc:x%x eqe_proc:x%llx eqd %d]\n", eqtype, qp->q_cnt_1, qp->q_cnt_2, qp->q_cnt_3, (unsigned long long)qp->q_cnt_4, qp->q_mode); len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, @@ -3366,6 +3409,12 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, if (len >= max_cnt) goto too_big; + qp = phba->sli4_hba.hdr_rq; + len = __lpfc_idiag_print_rqpair(qp, phba->sli4_hba.dat_rq, + "ELS RQpair", pbuffer, len); + if (len >= max_cnt) + goto too_big; + /* Slow-path NVME LS response CQ */ qp = phba->sli4_hba.nvmels_cq; len = __lpfc_idiag_print_cq(qp, "NVME LS", @@ -3383,12 +3432,6 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, if (len >= max_cnt) goto too_big; - qp = phba->sli4_hba.hdr_rq; - len = __lpfc_idiag_print_rqpair(qp, phba->sli4_hba.dat_rq, - "RQpair", pbuffer, len); - if (len >= max_cnt) - goto too_big; - goto out; } diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index f9a566eaef04..5a7547f9d8d8 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -134,6 +134,8 @@ struct lpfc_nodelist { struct lpfc_scsicmd_bkt *lat_data; /* Latency data */ uint32_t fc4_prli_sent; uint32_t upcall_flags; +#define NLP_WAIT_FOR_UNREG 0x1 + uint32_t nvme_fb_size; /* NVME target's supported byte cnt */ #define NVME_FB_BIT_SHIFT 9 /* PRLI Rsp first burst in 512B units. */ }; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 39d5b146202e..234c7c015982 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -858,6 +858,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, vport->fc_flag |= FC_PT2PT; spin_unlock_irq(shost->host_lock); + /* If we are pt2pt with another NPort, force NPIV off! */ + phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; + /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */ if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) { lpfc_unregister_fcf_prep(phba); @@ -916,28 +919,29 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); - } else + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + goto fail; + + lpfc_config_link(phba, mbox); + + mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; + mbox->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + mempool_free(mbox, phba->mbox_mem_pool); + goto fail; + } + } else { /* This side will wait for the PLOGI, decrement ndlp reference * count indicating that ndlp can be released when other * references to it are done. */ lpfc_nlp_put(ndlp); - /* If we are pt2pt with another NPort, force NPIV off! */ - phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - goto fail; - - lpfc_config_link(phba, mbox); - - mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; - mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - goto fail; + /* Start discovery - this should just do CLEAR_LA */ + lpfc_disc_start(vport); } return 0; @@ -1030,30 +1034,31 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, stop_rr_fcf_flogi: /* FLOGI failure */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2858 FLOGI failure Status:x%x/x%x TMO:x%x " - "Data x%x x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, phba->hba_flag, - phba->fcf.fcf_flag); + if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT && + ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == + IOERR_LOOP_OPEN_FAILURE))) + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "2858 FLOGI failure Status:x%x/x%x " + "TMO:x%x Data x%x x%x\n", + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->ulpTimeout, phba->hba_flag, + phba->fcf.fcf_flag); /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; - /* FLOGI failure */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout); - - /* If this is not a loop open failure, bail out */ if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT && ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == IOERR_LOOP_OPEN_FAILURE))) goto flogifail; + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, + "0150 FLOGI failure Status:x%x/x%x TMO:x%x\n", + irsp->ulpStatus, irsp->un.ulpWord[4], + irsp->ulpTimeout); + /* FLOGI failed, so there is no fabric */ spin_lock_irq(shost->host_lock); vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); @@ -1670,6 +1675,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, /* Two ndlps cannot have the same did on the nodelist */ ndlp->nlp_DID = keepDID; + lpfc_nlp_set_state(vport, ndlp, keep_nlp_state); if (phba->sli_rev == LPFC_SLI_REV4 && active_rrqs_xri_bitmap) memcpy(ndlp->active_rrqs_xri_bitmap, @@ -2088,6 +2094,10 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp = (struct lpfc_nodelist *) cmdiocb->context1; spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_PRLI_SND; + + /* Driver supports multiple FC4 types. Counters matter. */ + vport->fc_prli_sent--; + ndlp->fc4_prli_sent--; spin_unlock_irq(shost->host_lock); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -2095,9 +2105,6 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID); - /* Ddriver supports multiple FC4 types. Counters matter. */ - vport->fc_prli_sent--; - /* PRLI completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0103 PRLI completes to NPort x%06x " @@ -2111,7 +2118,6 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (irsp->ulpStatus) { /* Check for retry */ - ndlp->fc4_prli_sent--; if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ goto out; @@ -2190,6 +2196,15 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_fc4_type |= NLP_FC4_NVME; local_nlp_type = ndlp->nlp_fc4_type; + /* This routine will issue 1 or 2 PRLIs, so zero all the ndlp + * fields here before any of them can complete. + */ + ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); + ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + ndlp->nlp_flag &= ~NLP_FIRSTBURST; + ndlp->nvme_fb_size = 0; + send_next_prli: if (local_nlp_type & NLP_FC4_FCP) { /* Payload is 4 + 16 = 20 x14 bytes. */ @@ -2298,6 +2313,13 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, elsiocb->iocb_cmpl = lpfc_cmpl_els_prli; spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_PRLI_SND; + + /* The vport counters are used for lpfc_scan_finished, but + * the ndlp is used to track outstanding PRLIs for different + * FC4 types. + */ + vport->fc_prli_sent++; + ndlp->fc4_prli_sent++; spin_unlock_irq(shost->host_lock); if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) { @@ -2308,12 +2330,6 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 1; } - /* The vport counters are used for lpfc_scan_finished, but - * the ndlp is used to track outstanding PRLIs for different - * FC4 types. - */ - vport->fc_prli_sent++; - ndlp->fc4_prli_sent++; /* The driver supports 2 FC4 types. Make sure * a PRLI is issued for all types before exiting. @@ -2951,8 +2967,8 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) /* This will cause the callback-function lpfc_cmpl_els_cmd to * trigger the release of node. */ - - lpfc_nlp_put(ndlp); + if (!(vport->fc_flag & FC_PT2PT)) + lpfc_nlp_put(ndlp); return 0; } @@ -6172,9 +6188,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); /* send RECOVERY event for ALL nodes that match RSCN payload */ lpfc_rscn_recovery_check(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_DEFERRED; - spin_unlock_irq(shost->host_lock); return 0; } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -6849,7 +6862,7 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 1; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; + *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof(uint32_t); /* Skip past command */ /* use the command's xri in the response */ @@ -8060,13 +8073,6 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_exp = LSEXP_NOTHING_MORE; break; } - - /* NVMET accepts NVME PRLI only. Reject FCP PRLI */ - if (cmd == ELS_CMD_PRLI && phba->nvmet_support) { - rjt_err = LSRJT_CMD_UNSUPPORTED; - rjt_exp = LSEXP_REQ_UNSUPPORTED; - break; - } lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI); break; case ELS_CMD_LIRR: @@ -8149,9 +8155,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_nlp_put(ndlp); break; case ELS_CMD_REC: - /* receive this due to exchange closed */ - rjt_err = LSRJT_UNABLE_TPC; - rjt_exp = LSEXP_INVALID_OX_RX; + /* receive this due to exchange closed */ + rjt_err = LSRJT_UNABLE_TPC; + rjt_exp = LSEXP_INVALID_OX_RX; break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 2bafde2b7cfe..b159a5c4e388 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -640,8 +640,6 @@ lpfc_work_done(struct lpfc_hba *phba) lpfc_handle_rrq_active(phba); if (phba->hba_flag & FCP_XRI_ABORT_EVENT) lpfc_sli4_fcp_xri_abort_event_proc(phba); - if (phba->hba_flag & NVME_XRI_ABORT_EVENT) - lpfc_sli4_nvme_xri_abort_event_proc(phba); if (phba->hba_flag & ELS_XRI_ABORT_EVENT) lpfc_sli4_els_xri_abort_event_proc(phba); if (phba->hba_flag & ASYNC_EVENT) @@ -4178,12 +4176,14 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (ndlp->nlp_fc4_type & NLP_FC4_NVME) { vport->phba->nport_event_cnt++; - if (vport->phba->nvmet_support == 0) - /* Start devloss */ - lpfc_nvme_unregister_port(vport, ndlp); - else + if (vport->phba->nvmet_support == 0) { + /* Start devloss if target. */ + if (ndlp->nlp_type & NLP_NVME_TARGET) + lpfc_nvme_unregister_port(vport, ndlp); + } else { /* NVMET has no upcall. */ lpfc_nlp_put(ndlp); + } } } @@ -4207,11 +4207,13 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_fc4_type & NLP_FC4_NVME) { if (vport->phba->nvmet_support == 0) { /* Register this rport with the transport. - * Initiators take the NDLP ref count in - * the register. + * Only NVME Target Rports are registered with + * the transport. */ - vport->phba->nport_event_cnt++; - lpfc_nvme_register_port(vport, ndlp); + if (ndlp->nlp_type & NLP_NVME_TARGET) { + vport->phba->nport_event_cnt++; + lpfc_nvme_register_port(vport, ndlp); + } } else { /* Just take an NDLP ref count since the * target does not register rports. @@ -5838,9 +5840,12 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) if (filter(ndlp, param)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "3185 FIND node filter %p DID " - "Data: x%p x%x x%x\n", + "ndlp %p did x%x flg x%x st x%x " + "xri x%x type x%x rpi x%x\n", filter, ndlp, ndlp->nlp_DID, - ndlp->nlp_flag); + ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_xri, ndlp->nlp_type, + ndlp->nlp_rpi); return ndlp; } } diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 2b145966c73f..73c2f6971d2b 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1122,6 +1122,7 @@ struct cq_context { #define LPFC_CQ_CNT_256 0x0 #define LPFC_CQ_CNT_512 0x1 #define LPFC_CQ_CNT_1024 0x2 +#define LPFC_CQ_CNT_WORD7 0x3 uint32_t word1; #define lpfc_cq_eq_id_SHIFT 22 /* Version 0 Only */ #define lpfc_cq_eq_id_MASK 0x000000FF @@ -1129,7 +1130,7 @@ struct cq_context { #define lpfc_cq_eq_id_2_SHIFT 0 /* Version 2 Only */ #define lpfc_cq_eq_id_2_MASK 0x0000FFFF #define lpfc_cq_eq_id_2_WORD word1 - uint32_t reserved0; + uint32_t lpfc_cq_context_count; /* Version 2 Only */ uint32_t reserved1; }; @@ -1193,6 +1194,9 @@ struct lpfc_mbx_cq_create_set { #define lpfc_mbx_cq_create_set_arm_SHIFT 31 #define lpfc_mbx_cq_create_set_arm_MASK 0x00000001 #define lpfc_mbx_cq_create_set_arm_WORD word2 +#define lpfc_mbx_cq_create_set_cq_cnt_SHIFT 16 +#define lpfc_mbx_cq_create_set_cq_cnt_MASK 0x00007FFF +#define lpfc_mbx_cq_create_set_cq_cnt_WORD word2 #define lpfc_mbx_cq_create_set_num_cq_SHIFT 0 #define lpfc_mbx_cq_create_set_num_cq_MASK 0x0000FFFF #define lpfc_mbx_cq_create_set_num_cq_WORD word2 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 2b7ea7e53e12..f539c554588c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1034,6 +1034,7 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) LIST_HEAD(nvmet_aborts); unsigned long iflag = 0; struct lpfc_sglq *sglq_entry = NULL; + int cnt; lpfc_sli_hbqbuf_free_all(phba); @@ -1090,11 +1091,14 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, iflag); if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + cnt = 0; list_for_each_entry_safe(psb, psb_next, &nvme_aborts, list) { psb->pCmd = NULL; psb->status = IOSTAT_SUCCESS; + cnt++; } spin_lock_irqsave(&phba->nvme_buf_list_put_lock, iflag); + phba->put_nvme_bufs += cnt; list_splice(&nvme_aborts, &phba->lpfc_nvme_buf_list_put); spin_unlock_irqrestore(&phba->nvme_buf_list_put_lock, iflag); @@ -3339,6 +3343,7 @@ lpfc_nvme_free(struct lpfc_hba *phba) list_for_each_entry_safe(lpfc_ncmd, lpfc_ncmd_next, &phba->lpfc_nvme_buf_list_put, list) { list_del(&lpfc_ncmd->list); + phba->put_nvme_bufs--; dma_pool_free(phba->lpfc_sg_dma_buf_pool, lpfc_ncmd->data, lpfc_ncmd->dma_handle); kfree(lpfc_ncmd); @@ -3350,6 +3355,7 @@ lpfc_nvme_free(struct lpfc_hba *phba) list_for_each_entry_safe(lpfc_ncmd, lpfc_ncmd_next, &phba->lpfc_nvme_buf_list_get, list) { list_del(&lpfc_ncmd->list); + phba->get_nvme_bufs--; dma_pool_free(phba->lpfc_sg_dma_buf_pool, lpfc_ncmd->data, lpfc_ncmd->dma_handle); kfree(lpfc_ncmd); @@ -3754,9 +3760,11 @@ lpfc_sli4_nvme_sgl_update(struct lpfc_hba *phba) uint16_t i, lxri, els_xri_cnt; uint16_t nvme_xri_cnt, nvme_xri_max; LIST_HEAD(nvme_sgl_list); - int rc; + int rc, cnt; phba->total_nvme_bufs = 0; + phba->get_nvme_bufs = 0; + phba->put_nvme_bufs = 0; if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) return 0; @@ -3780,6 +3788,9 @@ lpfc_sli4_nvme_sgl_update(struct lpfc_hba *phba) spin_lock(&phba->nvme_buf_list_put_lock); list_splice_init(&phba->lpfc_nvme_buf_list_get, &nvme_sgl_list); list_splice(&phba->lpfc_nvme_buf_list_put, &nvme_sgl_list); + cnt = phba->get_nvme_bufs + phba->put_nvme_bufs; + phba->get_nvme_bufs = 0; + phba->put_nvme_bufs = 0; spin_unlock(&phba->nvme_buf_list_put_lock); spin_unlock_irq(&phba->nvme_buf_list_get_lock); @@ -3824,6 +3835,7 @@ lpfc_sli4_nvme_sgl_update(struct lpfc_hba *phba) spin_lock_irq(&phba->nvme_buf_list_get_lock); spin_lock(&phba->nvme_buf_list_put_lock); list_splice_init(&nvme_sgl_list, &phba->lpfc_nvme_buf_list_get); + phba->get_nvme_bufs = cnt; INIT_LIST_HEAD(&phba->lpfc_nvme_buf_list_put); spin_unlock(&phba->nvme_buf_list_put_lock); spin_unlock_irq(&phba->nvme_buf_list_get_lock); @@ -5609,8 +5621,10 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) /* Initialize the NVME buffer list used by driver for NVME IO */ spin_lock_init(&phba->nvme_buf_list_get_lock); INIT_LIST_HEAD(&phba->lpfc_nvme_buf_list_get); + phba->get_nvme_bufs = 0; spin_lock_init(&phba->nvme_buf_list_put_lock); INIT_LIST_HEAD(&phba->lpfc_nvme_buf_list_put); + phba->put_nvme_bufs = 0; } /* Initialize the fabric iocb list */ @@ -5806,6 +5820,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) struct lpfc_mqe *mqe; int longs; int fof_vectors = 0; + int extra; uint64_t wwn; phba->sli4_hba.num_online_cpu = num_online_cpus(); @@ -5860,13 +5875,21 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) */ /* + * 1 for cmd, 1 for rsp, NVME adds an extra one + * for boundary conditions in its max_sgl_segment template. + */ + extra = 2; + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) + extra++; + + /* * It doesn't matter what family our adapter is in, we are * limited to 2 Pages, 512 SGEs, for our SGL. * There are going to be 2 reserved SGEs: 1 FCP cmnd + 1 FCP rsp */ max_buf_size = (2 * SLI4_PAGE_SIZE); - if (phba->cfg_sg_seg_cnt > LPFC_MAX_SGL_SEG_CNT - 2) - phba->cfg_sg_seg_cnt = LPFC_MAX_SGL_SEG_CNT - 2; + if (phba->cfg_sg_seg_cnt > LPFC_MAX_SGL_SEG_CNT - extra) + phba->cfg_sg_seg_cnt = LPFC_MAX_SGL_SEG_CNT - extra; /* * Since lpfc_sg_seg_cnt is module param, the sg_dma_buf_size @@ -5899,14 +5922,14 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) */ phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) + - ((phba->cfg_sg_seg_cnt + 2) * + ((phba->cfg_sg_seg_cnt + extra) * sizeof(struct sli4_sge)); /* Total SGEs for scsi_sg_list */ - phba->cfg_total_seg_cnt = phba->cfg_sg_seg_cnt + 2; + phba->cfg_total_seg_cnt = phba->cfg_sg_seg_cnt + extra; /* - * NOTE: if (phba->cfg_sg_seg_cnt + 2) <= 256 we only + * NOTE: if (phba->cfg_sg_seg_cnt + extra) <= 256 we only * need to post 1 page for the SGL. */ } @@ -5947,9 +5970,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_nvme_buf_list); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_nvmet_io_wait_list); - - /* Fast-path XRI aborted CQ Event work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_nvme_xri_aborted_work_queue); } /* This abort list used by worker thread */ @@ -7936,8 +7956,12 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) phba->cfg_fcp_io_channel = io_channel; if (phba->cfg_nvme_io_channel > io_channel) phba->cfg_nvme_io_channel = io_channel; - if (phba->cfg_nvme_io_channel < phba->cfg_nvmet_mrq) - phba->cfg_nvmet_mrq = phba->cfg_nvme_io_channel; + if (phba->nvmet_support) { + if (phba->cfg_nvme_io_channel < phba->cfg_nvmet_mrq) + phba->cfg_nvmet_mrq = phba->cfg_nvme_io_channel; + } + if (phba->cfg_nvmet_mrq > LPFC_NVMET_MRQ_MAX) + phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_MAX; lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2574 IO channels: irqs %d fcp %d nvme %d MRQ: %d\n", @@ -7958,10 +7982,10 @@ static int lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx) { struct lpfc_queue *qdesc; - int cnt; - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, + phba->sli4_hba.cq_esize, + LPFC_CQE_EXP_COUNT); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0508 Failed allocate fast-path NVME CQ (%d)\n", @@ -7970,8 +7994,8 @@ lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx) } phba->sli4_hba.nvme_cq[wqidx] = qdesc; - cnt = LPFC_NVME_WQSIZE; - qdesc = lpfc_sli4_queue_alloc(phba, LPFC_WQE128_SIZE, cnt); + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, + LPFC_WQE128_SIZE, LPFC_WQE_EXP_COUNT); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0509 Failed allocate fast-path NVME WQ (%d)\n", @@ -7987,11 +8011,18 @@ static int lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) { struct lpfc_queue *qdesc; - uint32_t wqesize; /* Create Fast Path FCP CQs */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); + if (phba->fcp_embed_io) + /* Increase the CQ size when WQEs contain an embedded cdb */ + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, + phba->sli4_hba.cq_esize, + LPFC_CQE_EXP_COUNT); + + else + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.cq_esize, + phba->sli4_hba.cq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0499 Failed allocate fast-path FCP CQ (%d)\n", wqidx); @@ -8000,9 +8031,15 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) phba->sli4_hba.fcp_cq[wqidx] = qdesc; /* Create Fast Path FCP WQs */ - wqesize = (phba->fcp_embed_io) ? - LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize; - qdesc = lpfc_sli4_queue_alloc(phba, wqesize, phba->sli4_hba.wq_ecount); + if (phba->fcp_embed_io) + /* Increase the WQ size when WQEs contain an embedded cdb */ + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, + LPFC_WQE128_SIZE, + LPFC_WQE_EXP_COUNT); + else + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.wq_esize, + phba->sli4_hba.wq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0503 Failed allocate fast-path FCP WQ (%d)\n", @@ -8173,7 +8210,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* Create HBA Event Queues (EQs) */ for (idx = 0; idx < io_channel; idx++) { /* Create EQs */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.eq_esize, phba->sli4_hba.eq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8196,8 +8234,9 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (phba->nvmet_support) { for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) { qdesc = lpfc_sli4_queue_alloc(phba, - phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); + LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.cq_esize, + phba->sli4_hba.cq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3142 Failed allocate NVME " @@ -8213,7 +8252,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) */ /* Create slow-path Mailbox Command Complete Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8223,7 +8263,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.mbx_cq = qdesc; /* Create slow-path ELS Complete Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8239,7 +8280,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* Create Mailbox Command Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.mq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.mq_esize, phba->sli4_hba.mq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8253,7 +8295,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) */ /* Create slow-path ELS Work Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.wq_esize, phba->sli4_hba.wq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8265,7 +8308,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { /* Create NVME LS Complete Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8275,7 +8319,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.nvmels_cq = qdesc; /* Create NVME LS Work Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.wq_esize, phba->sli4_hba.wq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8291,7 +8336,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) */ /* Create Receive Queue for header */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.rq_esize, phba->sli4_hba.rq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8301,7 +8347,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) phba->sli4_hba.hdr_rq = qdesc; /* Create Receive Queue for data */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.rq_esize, phba->sli4_hba.rq_ecount); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8314,6 +8361,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) { /* Create NVMET Receive Queue for header */ qdesc = lpfc_sli4_queue_alloc(phba, + LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.rq_esize, LPFC_NVMET_RQE_DEF_COUNT); if (!qdesc) { @@ -8339,6 +8387,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* Create NVMET Receive Queue for data */ qdesc = lpfc_sli4_queue_alloc(phba, + LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.rq_esize, LPFC_NVMET_RQE_DEF_COUNT); if (!qdesc) { @@ -8437,13 +8486,15 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) /* Release NVME CQ mapping array */ lpfc_sli4_release_queue_map(&phba->sli4_hba.nvme_cq_map); - lpfc_sli4_release_queues(&phba->sli4_hba.nvmet_cqset, - phba->cfg_nvmet_mrq); + if (phba->nvmet_support) { + lpfc_sli4_release_queues(&phba->sli4_hba.nvmet_cqset, + phba->cfg_nvmet_mrq); - lpfc_sli4_release_queues(&phba->sli4_hba.nvmet_mrq_hdr, - phba->cfg_nvmet_mrq); - lpfc_sli4_release_queues(&phba->sli4_hba.nvmet_mrq_data, - phba->cfg_nvmet_mrq); + lpfc_sli4_release_queues(&phba->sli4_hba.nvmet_mrq_hdr, + phba->cfg_nvmet_mrq); + lpfc_sli4_release_queues(&phba->sli4_hba.nvmet_mrq_data, + phba->cfg_nvmet_mrq); + } /* Release mailbox command work queue */ __lpfc_sli4_release_queue(&phba->sli4_hba.mbx_wq); @@ -8514,6 +8565,7 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, qidx, (uint32_t)rc); return rc; } + cq->chann = qidx; if (qtype != LPFC_MBOX) { /* Setup nvme_cq_map for fast lookup */ @@ -8533,6 +8585,7 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq, /* no need to tear down cq - caller will do so */ return rc; } + wq->chann = qidx; /* Bind this CQ/WQ to the NVME ring */ pring = wq->pring; @@ -8773,6 +8826,8 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) "rc = 0x%x\n", (uint32_t)rc); goto out_destroy; } + phba->sli4_hba.nvmet_cqset[0]->chann = 0; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "6090 NVMET CQ setup: cq-id=%d, " "parent eq-id=%d\n", @@ -8994,19 +9049,22 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba) for (qidx = 0; qidx < phba->cfg_nvme_io_channel; qidx++) lpfc_cq_destroy(phba, phba->sli4_hba.nvme_cq[qidx]); - /* Unset NVMET MRQ queue */ - if (phba->sli4_hba.nvmet_mrq_hdr) { - for (qidx = 0; qidx < phba->cfg_nvmet_mrq; qidx++) - lpfc_rq_destroy(phba, + if (phba->nvmet_support) { + /* Unset NVMET MRQ queue */ + if (phba->sli4_hba.nvmet_mrq_hdr) { + for (qidx = 0; qidx < phba->cfg_nvmet_mrq; qidx++) + lpfc_rq_destroy( + phba, phba->sli4_hba.nvmet_mrq_hdr[qidx], phba->sli4_hba.nvmet_mrq_data[qidx]); - } + } - /* Unset NVMET CQ Set complete queue */ - if (phba->sli4_hba.nvmet_cqset) { - for (qidx = 0; qidx < phba->cfg_nvmet_mrq; qidx++) - lpfc_cq_destroy(phba, - phba->sli4_hba.nvmet_cqset[qidx]); + /* Unset NVMET CQ Set complete queue */ + if (phba->sli4_hba.nvmet_cqset) { + for (qidx = 0; qidx < phba->cfg_nvmet_mrq; qidx++) + lpfc_cq_destroy( + phba, phba->sli4_hba.nvmet_cqset[qidx]); + } } /* Unset FCP response complete queue */ @@ -9175,11 +9233,6 @@ lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba) /* Pending ELS XRI abort events */ list_splice_init(&phba->sli4_hba.sp_els_xri_aborted_work_queue, &cqelist); - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - /* Pending NVME XRI abort events */ - list_splice_init(&phba->sli4_hba.sp_nvme_xri_aborted_work_queue, - &cqelist); - } /* Pending asynnc events */ list_splice_init(&phba->sli4_hba.sp_asynce_work_queue, &cqelist); @@ -9421,44 +9474,62 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) lpfc_sli4_bar0_register_memmap(phba, if_type); } - if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) && - (pci_resource_start(pdev, PCI_64BIT_BAR2))) { - /* - * Map SLI4 if type 0 HBA Control Register base to a kernel - * virtual address and setup the registers. - */ - phba->pci_bar1_map = pci_resource_start(pdev, PCI_64BIT_BAR2); - bar1map_len = pci_resource_len(pdev, PCI_64BIT_BAR2); - phba->sli4_hba.ctrl_regs_memmap_p = - ioremap(phba->pci_bar1_map, bar1map_len); - if (!phba->sli4_hba.ctrl_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for SLI4 HBA control registers.\n"); + if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { + if (pci_resource_start(pdev, PCI_64BIT_BAR2)) { + /* + * Map SLI4 if type 0 HBA Control Register base to a + * kernel virtual address and setup the registers. + */ + phba->pci_bar1_map = pci_resource_start(pdev, + PCI_64BIT_BAR2); + bar1map_len = pci_resource_len(pdev, PCI_64BIT_BAR2); + phba->sli4_hba.ctrl_regs_memmap_p = + ioremap(phba->pci_bar1_map, + bar1map_len); + if (!phba->sli4_hba.ctrl_regs_memmap_p) { + dev_err(&pdev->dev, + "ioremap failed for SLI4 HBA " + "control registers.\n"); + error = -ENOMEM; + goto out_iounmap_conf; + } + phba->pci_bar2_memmap_p = + phba->sli4_hba.ctrl_regs_memmap_p; + lpfc_sli4_bar1_register_memmap(phba); + } else { + error = -ENOMEM; goto out_iounmap_conf; } - phba->pci_bar2_memmap_p = phba->sli4_hba.ctrl_regs_memmap_p; - lpfc_sli4_bar1_register_memmap(phba); } - if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) && - (pci_resource_start(pdev, PCI_64BIT_BAR4))) { - /* - * Map SLI4 if type 0 HBA Doorbell Register base to a kernel - * virtual address and setup the registers. - */ - phba->pci_bar2_map = pci_resource_start(pdev, PCI_64BIT_BAR4); - bar2map_len = pci_resource_len(pdev, PCI_64BIT_BAR4); - phba->sli4_hba.drbl_regs_memmap_p = - ioremap(phba->pci_bar2_map, bar2map_len); - if (!phba->sli4_hba.drbl_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for SLI4 HBA doorbell registers.\n"); - goto out_iounmap_ctrl; - } - phba->pci_bar4_memmap_p = phba->sli4_hba.drbl_regs_memmap_p; - error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0); - if (error) + if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { + if (pci_resource_start(pdev, PCI_64BIT_BAR4)) { + /* + * Map SLI4 if type 0 HBA Doorbell Register base to + * a kernel virtual address and setup the registers. + */ + phba->pci_bar2_map = pci_resource_start(pdev, + PCI_64BIT_BAR4); + bar2map_len = pci_resource_len(pdev, PCI_64BIT_BAR4); + phba->sli4_hba.drbl_regs_memmap_p = + ioremap(phba->pci_bar2_map, + bar2map_len); + if (!phba->sli4_hba.drbl_regs_memmap_p) { + dev_err(&pdev->dev, + "ioremap failed for SLI4 HBA" + " doorbell registers.\n"); + error = -ENOMEM; + goto out_iounmap_ctrl; + } + phba->pci_bar4_memmap_p = + phba->sli4_hba.drbl_regs_memmap_p; + error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0); + if (error) + goto out_iounmap_all; + } else { + error = -ENOMEM; goto out_iounmap_all; + } } return 0; @@ -10093,6 +10164,16 @@ lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba) int fcp_xri_cmpl = 1; int els_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list); + /* Driver just aborted IOs during the hba_unset process. Pause + * here to give the HBA time to complete the IO and get entries + * into the abts lists. + */ + msleep(LPFC_XRI_EXCH_BUSY_WAIT_T1 * 5); + + /* Wait for NVME pending IO to flush back to transport. */ + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) + lpfc_nvme_wait_for_io_drain(phba); + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) fcp_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_scsi_buf_list); @@ -10369,7 +10450,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) !phba->nvme_support) { phba->nvme_support = 0; phba->nvmet_support = 0; - phba->cfg_nvmet_mrq = 0; + phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_OFF; phba->cfg_nvme_io_channel = 0; phba->io_channel_irqs = phba->cfg_fcp_io_channel; lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME, @@ -11616,6 +11697,10 @@ lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) /* Flush all driver's outstanding SCSI I/Os as we are to reset */ lpfc_sli_flush_fcp_rings(phba); + /* Flush the outstanding NVME IOs if fc4 type enabled. */ + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) + lpfc_sli_flush_nvme_rings(phba); + /* stop all timers */ lpfc_stop_hba_timers(phba); @@ -11647,6 +11732,10 @@ lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba) /* Clean up all driver's outstanding SCSI I/Os */ lpfc_sli_flush_fcp_rings(phba); + + /* Flush the outstanding NVME IOs if fc4 type enabled. */ + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) + lpfc_sli_flush_nvme_rings(phba); } /** @@ -12138,10 +12227,10 @@ int lpfc_fof_queue_create(struct lpfc_hba *phba) { struct lpfc_queue *qdesc; - uint32_t wqesize; /* Create FOF EQ */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.eq_esize, phba->sli4_hba.eq_ecount); if (!qdesc) goto out_error; @@ -12151,7 +12240,15 @@ lpfc_fof_queue_create(struct lpfc_hba *phba) if (phba->cfg_fof) { /* Create OAS CQ */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, + if (phba->fcp_embed_io) + qdesc = lpfc_sli4_queue_alloc(phba, + LPFC_EXPANDED_PAGE_SIZE, + phba->sli4_hba.cq_esize, + LPFC_CQE_EXP_COUNT); + else + qdesc = lpfc_sli4_queue_alloc(phba, + LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount); if (!qdesc) goto out_error; @@ -12159,11 +12256,16 @@ lpfc_fof_queue_create(struct lpfc_hba *phba) phba->sli4_hba.oas_cq = qdesc; /* Create OAS WQ */ - wqesize = (phba->fcp_embed_io) ? - LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize; - qdesc = lpfc_sli4_queue_alloc(phba, wqesize, - phba->sli4_hba.wq_ecount); - + if (phba->fcp_embed_io) + qdesc = lpfc_sli4_queue_alloc(phba, + LPFC_EXPANDED_PAGE_SIZE, + LPFC_WQE128_SIZE, + LPFC_WQE_EXP_COUNT); + else + qdesc = lpfc_sli4_queue_alloc(phba, + LPFC_DEFAULT_PAGE_SIZE, + phba->sli4_hba.wq_esize, + phba->sli4_hba.wq_ecount); if (!qdesc) goto out_error; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index b6957d944b9a..d841aa42f607 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -390,6 +390,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, break; } + ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); + ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + ndlp->nlp_flag &= ~NLP_FIRSTBURST; + /* Check for Nport to NPort pt2pt protocol */ if ((vport->fc_flag & FC_PT2PT) && !(vport->fc_flag & FC_PT2PT_PLOGI)) { @@ -727,6 +732,41 @@ out: return 0; } +static uint32_t +lpfc_rcv_prli_support_check(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, + struct lpfc_iocbq *cmdiocb) +{ + struct ls_rjt stat; + uint32_t *payload; + uint32_t cmd; + + payload = ((struct lpfc_dmabuf *)cmdiocb->context2)->virt; + cmd = *payload; + if (vport->phba->nvmet_support) { + /* Must be a NVME PRLI */ + if (cmd == ELS_CMD_PRLI) + goto out; + } else { + /* Initiator mode. */ + if (!vport->nvmei_support && (cmd == ELS_CMD_NVMEPRLI)) + goto out; + } + return 1; +out: + lpfc_printf_vlog(vport, KERN_WARNING, LOG_NVME_DISC, + "6115 Rcv PRLI (%x) check failed: ndlp rpi %d " + "state x%x flags x%x\n", + cmd, ndlp->nlp_rpi, ndlp->nlp_state, + ndlp->nlp_flag); + memset(&stat, 0, sizeof(struct ls_rjt)); + stat.un.b.lsRjtRsnCode = LSRJT_CMD_UNSUPPORTED; + stat.un.b.lsRjtRsnCodeExp = LSEXP_REQ_UNSUPPORTED; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, + ndlp, NULL); + return 0; +} + static void lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *cmdiocb) @@ -742,9 +782,6 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lp = (uint32_t *) pcmd->virt; npr = (PRLI *) ((uint8_t *) lp + sizeof (uint32_t)); - ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); - ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - ndlp->nlp_flag &= ~NLP_FIRSTBURST; if ((npr->prliType == PRLI_FCP_TYPE) || (npr->prliType == PRLI_NVME_TYPE)) { if (npr->initiatorFunc) { @@ -769,8 +806,12 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * type. Target mode does not issue gft_id so doesn't get * the fc4 type set until now. */ - if ((phba->nvmet_support) && (npr->prliType == PRLI_NVME_TYPE)) + if (phba->nvmet_support && (npr->prliType == PRLI_NVME_TYPE)) { ndlp->nlp_fc4_type |= NLP_FC4_NVME; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + } + if (npr->prliType == PRLI_FCP_TYPE) + ndlp->nlp_fc4_type |= NLP_FC4_FCP; } if (rport) { /* We need to update the rport role values */ @@ -1373,7 +1414,8 @@ lpfc_rcv_prli_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); + if (lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb)) + lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); return ndlp->nlp_state; } @@ -1544,6 +1586,9 @@ lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; struct ls_rjt stat; + if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb)) { + return ndlp->nlp_state; + } if (vport->phba->nvmet_support) { /* NVME Target mode. Handle and respond to the PRLI and * transition to UNMAPPED provided the RPI has completed @@ -1552,28 +1597,22 @@ lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport, if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { lpfc_rcv_prli(vport, ndlp, cmdiocb); lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); } else { /* RPI registration has not completed. Reject the PRLI * to prevent an illegal state transition when the * rpi registration does complete. */ - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NVME_DISC, - "6115 NVMET ndlp rpi %d state " - "unknown, state x%x flags x%08x\n", - ndlp->nlp_rpi, ndlp->nlp_state, - ndlp->nlp_flag); memset(&stat, 0, sizeof(struct ls_rjt)); - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS; + stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; + stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); + return ndlp->nlp_state; } } else { /* Initiator mode. */ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); } - return ndlp->nlp_state; } @@ -1819,6 +1858,8 @@ lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; + if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb)) + return ndlp->nlp_state; lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); return ndlp->nlp_state; } @@ -1922,13 +1963,6 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp->nlp_state; } - /* Check out PRLI rsp */ - ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); - ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - - /* NVME or FCP first burst must be negotiated for each PRLI. */ - ndlp->nlp_flag &= ~NLP_FIRSTBURST; - ndlp->nvme_fb_size = 0; if (npr && (npr->acceptRspCode == PRLI_REQ_EXECUTED) && (npr->prliType == PRLI_FCP_TYPE)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, @@ -1945,8 +1979,6 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (npr->Retry) ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; - /* PRLI completed. Decrement count. */ - ndlp->fc4_prli_sent--; } else if (nvpr && (bf_get_be32(prli_acc_rsp_code, nvpr) == PRLI_REQ_EXECUTED) && @@ -1991,8 +2023,6 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, be32_to_cpu(nvpr->word5), ndlp->nlp_flag, ndlp->nlp_fcp_info, ndlp->nlp_type); - /* PRLI completed. Decrement count. */ - ndlp->fc4_prli_sent--; } if (!(ndlp->nlp_type & NLP_FCP_TARGET) && (vport->port_type == LPFC_NPIV_PORT) && @@ -2016,7 +2046,8 @@ out_err: ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET)) lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); - else + else if (ndlp->nlp_type & + (NLP_FCP_INITIATOR | NLP_NVME_INITIATOR)) lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); } else lpfc_printf_vlog(vport, @@ -2241,6 +2272,9 @@ lpfc_rcv_prli_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; + if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb)) + return ndlp->nlp_state; + lpfc_rcv_prli(vport, ndlp, cmdiocb); lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); return ndlp->nlp_state; @@ -2310,6 +2344,8 @@ lpfc_rcv_prli_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; + if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb)) + return ndlp->nlp_state; lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); return ndlp->nlp_state; } diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 517ae570e507..81e3a4f10c3c 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -57,11 +57,13 @@ /* NVME initiator-based functions */ static struct lpfc_nvme_buf * -lpfc_get_nvme_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp); +lpfc_get_nvme_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, + int expedite); static void lpfc_release_nvme_buf(struct lpfc_hba *, struct lpfc_nvme_buf *); +static struct nvme_fc_port_template lpfc_nvme_template; /** * lpfc_nvme_create_queue - @@ -88,6 +90,9 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport, struct lpfc_nvme_qhandle *qhandle; char *str; + if (!pnvme_lport->private) + return -ENOMEM; + lport = (struct lpfc_nvme_lport *)pnvme_lport->private; vport = lport->vport; qhandle = kzalloc(sizeof(struct lpfc_nvme_qhandle), GFP_KERNEL); @@ -140,6 +145,9 @@ lpfc_nvme_delete_queue(struct nvme_fc_local_port *pnvme_lport, struct lpfc_nvme_lport *lport; struct lpfc_vport *vport; + if (!pnvme_lport->private) + return; + lport = (struct lpfc_nvme_lport *)pnvme_lport->private; vport = lport->vport; @@ -154,6 +162,10 @@ lpfc_nvme_localport_delete(struct nvme_fc_local_port *localport) { struct lpfc_nvme_lport *lport = localport->private; + lpfc_printf_vlog(lport->vport, KERN_INFO, LOG_NVME, + "6173 localport %p delete complete\n", + lport); + /* release any threads waiting for the unreg to complete */ complete(&lport->lport_unreg_done); } @@ -189,16 +201,19 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) * calling state machine to remove the node. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6146 remoteport delete complete %p\n", + "6146 remoteport delete of remoteport %p\n", remoteport); + spin_lock_irq(&vport->phba->hbalock); ndlp->nrport = NULL; + spin_unlock_irq(&vport->phba->hbalock); + + /* Remove original register reference. The host transport + * won't reference this rport/remoteport any further. + */ lpfc_nlp_put(ndlp); rport_err: - /* This call has to execute as long as the rport is valid. - * Release any threads waiting for the unreg to complete. - */ - complete(&rport->rport_unreg_done); + return; } static void @@ -206,6 +221,7 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, struct lpfc_wcqe_complete *wcqe) { struct lpfc_vport *vport = cmdwqe->vport; + struct lpfc_nvme_lport *lport; uint32_t status; struct nvmefc_ls_req *pnvme_lsreq; struct lpfc_dmabuf *buf_ptr; @@ -215,6 +231,13 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, pnvme_lsreq = (struct nvmefc_ls_req *)cmdwqe->context2; status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; + if (status) { + lport = (struct lpfc_nvme_lport *)vport->localport->private; + if (bf_get(lpfc_wcqe_c_xb, wcqe)) + atomic_inc(&lport->cmpl_ls_xb); + atomic_inc(&lport->cmpl_ls_err); + } + ndlp = (struct lpfc_nodelist *)cmdwqe->context1; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6047 nvme cmpl Enter " @@ -419,6 +442,9 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, if (vport->load_flag & FC_UNLOADING) return -ENODEV; + if (vport->load_flag & FC_UNLOADING) + return -ENODEV; + ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id); if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, @@ -490,6 +516,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, pnvme_lsreq, lpfc_nvme_cmpl_gen_req, ndlp, 2, 30, 0); if (ret != WQE_SUCCESS) { + atomic_inc(&lport->xmt_ls_err); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6052 EXIT. issue ls wqe failed lport %p, " "rport %p lsreq%p Status %x DID %x\n", @@ -534,6 +561,9 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, vport = lport->vport; phba = vport->phba; + if (vport->load_flag & FC_UNLOADING) + return; + ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id); if (!ndlp) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, @@ -571,6 +601,7 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, /* Abort the targeted IOs and remove them from the abort list. */ list_for_each_entry_safe(wqe, next_wqe, &abort_list, dlist) { + atomic_inc(&lport->xmt_ls_abort); spin_lock_irq(&phba->hbalock); list_del_init(&wqe->dlist); lpfc_sli_issue_abort_iotag(phba, pring, wqe); @@ -774,8 +805,9 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, struct lpfc_nvme_rport *rport; struct lpfc_nodelist *ndlp; struct lpfc_nvme_fcpreq_priv *freqpriv; + struct lpfc_nvme_lport *lport; unsigned long flags; - uint32_t code; + uint32_t code, status; uint16_t cid, sqhd, data; uint32_t *ptr; @@ -790,10 +822,17 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, nCmd = lpfc_ncmd->nvmeCmd; rport = lpfc_ncmd->nrport; + status = bf_get(lpfc_wcqe_c_status, wcqe); + if (status) { + lport = (struct lpfc_nvme_lport *)vport->localport->private; + if (bf_get(lpfc_wcqe_c_xb, wcqe)) + atomic_inc(&lport->cmpl_fcp_xb); + atomic_inc(&lport->cmpl_fcp_err); + } lpfc_nvmeio_data(phba, "NVME FCP CMPL: xri x%x stat x%x parm x%x\n", lpfc_ncmd->cur_iocbq.sli4_xritag, - bf_get(lpfc_wcqe_c_status, wcqe), wcqe->parameter); + status, wcqe->parameter); /* * Catch race where our node has transitioned, but the * transport is still transitioning. @@ -851,8 +890,7 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, nCmd->rcv_rsplen = LPFC_NVME_ERSP_LEN; nCmd->transferred_length = nCmd->payload_length; } else { - lpfc_ncmd->status = (bf_get(lpfc_wcqe_c_status, wcqe) & - LPFC_IOCB_STATUS_MASK); + lpfc_ncmd->status = (status & LPFC_IOCB_STATUS_MASK); lpfc_ncmd->result = (wcqe->parameter & IOERR_PARAM_MASK); /* For NVME, the only failure path that results in an @@ -946,10 +984,13 @@ out_err: freqpriv->nvme_buf = NULL; /* NVME targets need completion held off until the abort exchange - * completes. + * completes unless the NVME Rport is getting unregistered. */ - if (!(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) + + if (!(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) { nCmd->done(nCmd); + lpfc_ncmd->nvmeCmd = NULL; + } spin_lock_irqsave(&phba->hbalock, flags); lpfc_ncmd->nrport = NULL; @@ -1149,7 +1190,7 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, first_data_sgl = sgl; lpfc_ncmd->seg_cnt = nCmd->sg_cnt; - if (lpfc_ncmd->seg_cnt > phba->cfg_nvme_seg_cnt + 1) { + if (lpfc_ncmd->seg_cnt > lpfc_nvme_template.max_sgl_segments) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, "6058 Too many sg segments from " "NVME Transport. Max %d, " @@ -1239,6 +1280,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, struct nvmefc_fcp_req *pnvme_fcreq) { int ret = 0; + int expedite = 0; struct lpfc_nvme_lport *lport; struct lpfc_vport *vport; struct lpfc_hba *phba; @@ -1246,13 +1288,30 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, struct lpfc_nvme_buf *lpfc_ncmd; struct lpfc_nvme_rport *rport; struct lpfc_nvme_qhandle *lpfc_queue_info; - struct lpfc_nvme_fcpreq_priv *freqpriv = pnvme_fcreq->private; + struct lpfc_nvme_fcpreq_priv *freqpriv; + struct nvme_common_command *sqe; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint64_t start = 0; #endif + /* Validate pointers. LLDD fault handling with transport does + * have timing races. + */ lport = (struct lpfc_nvme_lport *)pnvme_lport->private; + if (unlikely(!lport)) { + ret = -EINVAL; + goto out_fail; + } + vport = lport->vport; + + if (unlikely(!hw_queue_handle)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, + "6129 Fail Abort, NULL hw_queue_handle\n"); + ret = -EINVAL; + goto out_fail; + } + phba = vport->phba; if (vport->load_flag & FC_UNLOADING) { @@ -1260,16 +1319,17 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, goto out_fail; } - /* Validate pointers. */ - if (!pnvme_lport || !pnvme_rport || !freqpriv) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR | LOG_NODE, - "6117 No Send:IO submit ptrs NULL, lport %p, " - "rport %p fcreq_priv %p\n", - pnvme_lport, pnvme_rport, freqpriv); + if (vport->load_flag & FC_UNLOADING) { ret = -ENODEV; goto out_fail; } + freqpriv = pnvme_fcreq->private; + if (unlikely(!freqpriv)) { + ret = -EINVAL; + goto out_fail; + } + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (phba->ktime_on) start = ktime_get_ns(); @@ -1293,6 +1353,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, "6066 Missing node for DID %x\n", pnvme_rport->port_id); + atomic_inc(&lport->xmt_fcp_bad_ndlp); ret = -ENODEV; goto out_fail; } @@ -1306,21 +1367,36 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, "IO. State x%x, Type x%x\n", rport, pnvme_rport->port_id, ndlp->nlp_state, ndlp->nlp_type); + atomic_inc(&lport->xmt_fcp_bad_ndlp); ret = -ENODEV; goto out_fail; } + /* Currently only NVME Keep alive commands should be expedited + * if the driver runs out of a resource. These should only be + * issued on the admin queue, qidx 0 + */ + if (!lpfc_queue_info->qidx && !pnvme_fcreq->sg_cnt) { + sqe = &((struct nvme_fc_cmd_iu *) + pnvme_fcreq->cmdaddr)->sqe.common; + if (sqe->opcode == nvme_admin_keep_alive) + expedite = 1; + } + /* The node is shared with FCP IO, make sure the IO pending count does * not exceed the programmed depth. */ - if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) { + if ((atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) && + !expedite) { + atomic_inc(&lport->xmt_fcp_qdepth); ret = -EBUSY; goto out_fail; } - lpfc_ncmd = lpfc_get_nvme_buf(phba, ndlp); + lpfc_ncmd = lpfc_get_nvme_buf(phba, ndlp, expedite); if (lpfc_ncmd == NULL) { + atomic_inc(&lport->xmt_fcp_noxri); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, "6065 driver's buffer pool is empty, " "IO failed\n"); @@ -1373,6 +1449,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, ret = lpfc_sli4_issue_wqe(phba, LPFC_FCP_RING, &lpfc_ncmd->cur_iocbq); if (ret) { + atomic_inc(&lport->xmt_fcp_wqerr); atomic_dec(&ndlp->cmd_pending); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, "6113 FCP could not issue WQE err %x " @@ -1473,19 +1550,36 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, struct lpfc_nvme_lport *lport; struct lpfc_vport *vport; struct lpfc_hba *phba; - struct lpfc_nvme_rport *rport; struct lpfc_nvme_buf *lpfc_nbuf; struct lpfc_iocbq *abts_buf; struct lpfc_iocbq *nvmereq_wqe; - struct lpfc_nvme_fcpreq_priv *freqpriv = pnvme_fcreq->private; + struct lpfc_nvme_fcpreq_priv *freqpriv; union lpfc_wqe *abts_wqe; unsigned long flags; int ret_val; + /* Validate pointers. LLDD fault handling with transport does + * have timing races. + */ lport = (struct lpfc_nvme_lport *)pnvme_lport->private; - rport = (struct lpfc_nvme_rport *)pnvme_rport->private; + if (unlikely(!lport)) + return; + vport = lport->vport; + + if (unlikely(!hw_queue_handle)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, + "6129 Fail Abort, HW Queue Handle NULL.\n"); + return; + } + phba = vport->phba; + freqpriv = pnvme_fcreq->private; + + if (unlikely(!freqpriv)) + return; + if (vport->load_flag & FC_UNLOADING) + return; /* Announce entry to new IO submit field. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, @@ -1552,6 +1646,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, return; } + atomic_inc(&lport->xmt_fcp_abort); lpfc_nvmeio_data(phba, "NVME FCP ABORT: xri x%x idx %d to %06x\n", nvmereq_wqe->sli4_xritag, nvmereq_wqe->hba_wqidx, pnvme_rport->port_id); @@ -1931,6 +2026,8 @@ lpfc_repost_nvme_sgl_list(struct lpfc_hba *phba) spin_lock(&phba->nvme_buf_list_put_lock); list_splice_init(&phba->lpfc_nvme_buf_list_get, &post_nblist); list_splice(&phba->lpfc_nvme_buf_list_put, &post_nblist); + phba->get_nvme_bufs = 0; + phba->put_nvme_bufs = 0; spin_unlock(&phba->nvme_buf_list_put_lock); spin_unlock_irq(&phba->nvme_buf_list_get_lock); @@ -2067,6 +2164,20 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc) return num_posted; } +static inline struct lpfc_nvme_buf * +lpfc_nvme_buf(struct lpfc_hba *phba) +{ + struct lpfc_nvme_buf *lpfc_ncmd, *lpfc_ncmd_next; + + list_for_each_entry_safe(lpfc_ncmd, lpfc_ncmd_next, + &phba->lpfc_nvme_buf_list_get, list) { + list_del_init(&lpfc_ncmd->list); + phba->get_nvme_bufs--; + return lpfc_ncmd; + } + return NULL; +} + /** * lpfc_get_nvme_buf - Get a nvme buffer from lpfc_nvme_buf_list of the HBA * @phba: The HBA for which this call is being executed. @@ -2079,35 +2190,27 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc) * Pointer to lpfc_nvme_buf - Success **/ static struct lpfc_nvme_buf * -lpfc_get_nvme_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +lpfc_get_nvme_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, + int expedite) { - struct lpfc_nvme_buf *lpfc_ncmd, *lpfc_ncmd_next; + struct lpfc_nvme_buf *lpfc_ncmd = NULL; unsigned long iflag = 0; - int found = 0; spin_lock_irqsave(&phba->nvme_buf_list_get_lock, iflag); - list_for_each_entry_safe(lpfc_ncmd, lpfc_ncmd_next, - &phba->lpfc_nvme_buf_list_get, list) { - list_del_init(&lpfc_ncmd->list); - found = 1; - break; - } - if (!found) { + if (phba->get_nvme_bufs > LPFC_NVME_EXPEDITE_XRICNT || expedite) + lpfc_ncmd = lpfc_nvme_buf(phba); + if (!lpfc_ncmd) { spin_lock(&phba->nvme_buf_list_put_lock); list_splice(&phba->lpfc_nvme_buf_list_put, &phba->lpfc_nvme_buf_list_get); + phba->get_nvme_bufs += phba->put_nvme_bufs; INIT_LIST_HEAD(&phba->lpfc_nvme_buf_list_put); + phba->put_nvme_bufs = 0; spin_unlock(&phba->nvme_buf_list_put_lock); - list_for_each_entry_safe(lpfc_ncmd, lpfc_ncmd_next, - &phba->lpfc_nvme_buf_list_get, list) { - list_del_init(&lpfc_ncmd->list); - found = 1; - break; - } + if (phba->get_nvme_bufs > LPFC_NVME_EXPEDITE_XRICNT || expedite) + lpfc_ncmd = lpfc_nvme_buf(phba); } spin_unlock_irqrestore(&phba->nvme_buf_list_get_lock, iflag); - if (!found) - return NULL; return lpfc_ncmd; } @@ -2145,6 +2248,7 @@ lpfc_release_nvme_buf(struct lpfc_hba *phba, struct lpfc_nvme_buf *lpfc_ncmd) lpfc_ncmd->cur_iocbq.iocb_flag = LPFC_IO_NVME; spin_lock_irqsave(&phba->nvme_buf_list_put_lock, iflag); list_add_tail(&lpfc_ncmd->list, &phba->lpfc_nvme_buf_list_put); + phba->put_nvme_bufs++; spin_unlock_irqrestore(&phba->nvme_buf_list_put_lock, iflag); } } @@ -2221,6 +2325,18 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) lport->vport = vport; vport->nvmei_support = 1; + atomic_set(&lport->xmt_fcp_noxri, 0); + atomic_set(&lport->xmt_fcp_bad_ndlp, 0); + atomic_set(&lport->xmt_fcp_qdepth, 0); + atomic_set(&lport->xmt_fcp_wqerr, 0); + atomic_set(&lport->xmt_fcp_abort, 0); + atomic_set(&lport->xmt_ls_abort, 0); + atomic_set(&lport->xmt_ls_err, 0); + atomic_set(&lport->cmpl_fcp_xb, 0); + atomic_set(&lport->cmpl_fcp_err, 0); + atomic_set(&lport->cmpl_ls_xb, 0); + atomic_set(&lport->cmpl_ls_err, 0); + /* Don't post more new bufs if repost already recovered * the nvme sgls. */ @@ -2234,6 +2350,47 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) return ret; } +/* lpfc_nvme_lport_unreg_wait - Wait for the host to complete an lport unreg. + * + * The driver has to wait for the host nvme transport to callback + * indicating the localport has successfully unregistered all + * resources. Since this is an uninterruptible wait, loop every ten + * seconds and print a message indicating no progress. + * + * An uninterruptible wait is used because of the risk of transport-to- + * driver state mismatch. + */ +void +lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, + struct lpfc_nvme_lport *lport) +{ +#if (IS_ENABLED(CONFIG_NVME_FC)) + u32 wait_tmo; + int ret; + + /* Host transport has to clean up and confirm requiring an indefinite + * wait. Print a message if a 10 second wait expires and renew the + * wait. This is unexpected. + */ + wait_tmo = msecs_to_jiffies(LPFC_NVME_WAIT_TMO * 1000); + while (true) { + ret = wait_for_completion_timeout(&lport->lport_unreg_done, + wait_tmo); + if (unlikely(!ret)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, + "6176 Lport %p Localport %p wait " + "timed out. Renewing.\n", + lport, vport->localport); + continue; + } + break; + } + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, + "6177 Lport %p Localport %p Complete Success\n", + lport, vport->localport); +#endif +} + /** * lpfc_nvme_destroy_localport - Destroy lpfc_nvme bound to nvme transport. * @pnvme: pointer to lpfc nvme data structure. @@ -2268,7 +2425,11 @@ lpfc_nvme_destroy_localport(struct lpfc_vport *vport) */ init_completion(&lport->lport_unreg_done); ret = nvme_fc_unregister_localport(localport); - wait_for_completion_timeout(&lport->lport_unreg_done, 5); + + /* Wait for completion. This either blocks + * indefinitely or succeeds + */ + lpfc_nvme_lport_unreg_wait(vport, lport); /* Regardless of the unregister upcall response, clear * nvmei_support. All rports are unregistered and the @@ -2365,6 +2526,9 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rpinfo.port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn); rpinfo.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn); + if (!ndlp->nrport) + lpfc_nlp_get(ndlp); + ret = nvme_fc_register_remoteport(localport, &rpinfo, &remote_port); if (!ret) { /* If the ndlp already has an nrport, this is just @@ -2373,23 +2537,33 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) */ rport = remote_port->private; if (ndlp->nrport) { - lpfc_printf_vlog(ndlp->vport, KERN_INFO, - LOG_NVME_DISC, - "6014 Rebinding lport to " - "rport wwpn 0x%llx, " - "Data: x%x x%x x%x x%06x\n", - remote_port->port_name, - remote_port->port_id, - remote_port->port_role, - ndlp->nlp_type, - ndlp->nlp_DID); + if (ndlp->nrport == remote_port->private) { + /* Same remoteport. Just reuse. */ + lpfc_printf_vlog(ndlp->vport, KERN_INFO, + LOG_NVME_DISC, + "6014 Rebinding lport to " + "remoteport %p wwpn 0x%llx, " + "Data: x%x x%x %p x%x x%06x\n", + remote_port, + remote_port->port_name, + remote_port->port_id, + remote_port->port_role, + ndlp, + ndlp->nlp_type, + ndlp->nlp_DID); + return 0; + } prev_ndlp = rport->ndlp; - /* Sever the ndlp<->rport connection before dropping - * the ndlp ref from register. + /* Sever the ndlp<->rport association + * before dropping the ndlp ref from + * register. */ + spin_lock_irq(&vport->phba->hbalock); ndlp->nrport = NULL; + spin_unlock_irq(&vport->phba->hbalock); rport->ndlp = NULL; + rport->remoteport = NULL; if (prev_ndlp) lpfc_nlp_put(ndlp); } @@ -2397,19 +2571,20 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* Clean bind the rport to the ndlp. */ rport->remoteport = remote_port; rport->lport = lport; - rport->ndlp = lpfc_nlp_get(ndlp); - if (!rport->ndlp) - return -1; + rport->ndlp = ndlp; + spin_lock_irq(&vport->phba->hbalock); ndlp->nrport = rport; + spin_unlock_irq(&vport->phba->hbalock); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_NODE, "6022 Binding new rport to " - "lport %p Rport WWNN 0x%llx, " + "lport %p Remoteport %p WWNN 0x%llx, " "Rport WWPN 0x%llx DID " - "x%06x Role x%x\n", - lport, + "x%06x Role x%x, ndlp %p\n", + lport, remote_port, rpinfo.node_name, rpinfo.port_name, - rpinfo.port_id, rpinfo.port_role); + rpinfo.port_id, rpinfo.port_role, + ndlp); } else { lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC | LOG_NODE, @@ -2473,20 +2648,20 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* Sanity check ndlp type. Only call for NVME ports. Don't * clear any rport state until the transport calls back. */ - if (ndlp->nlp_type & (NLP_NVME_TARGET | NLP_NVME_INITIATOR)) { - init_completion(&rport->rport_unreg_done); + if (ndlp->nlp_type & NLP_NVME_TARGET) { /* No concern about the role change on the nvme remoteport. * The transport will update it. */ + ndlp->upcall_flags |= NLP_WAIT_FOR_UNREG; ret = nvme_fc_unregister_remoteport(remoteport); if (ret != 0) { + lpfc_nlp_put(ndlp); lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, "6167 NVME unregister failed %d " "port_state x%x\n", ret, remoteport->port_state); } - } return; @@ -2545,8 +2720,11 @@ lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, * before the abort exchange command fully completes. * Once completed, it is available via the put list. */ - nvme_cmd = lpfc_ncmd->nvmeCmd; - nvme_cmd->done(nvme_cmd); + if (lpfc_ncmd->nvmeCmd) { + nvme_cmd = lpfc_ncmd->nvmeCmd; + nvme_cmd->done(nvme_cmd); + lpfc_ncmd->nvmeCmd = NULL; + } lpfc_release_nvme_buf(phba, lpfc_ncmd); return; } @@ -2558,3 +2736,45 @@ lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, "6312 XRI Aborted xri x%x not found\n", xri); } + +/** + * lpfc_nvme_wait_for_io_drain - Wait for all NVME wqes to complete + * @phba: Pointer to HBA context object. + * + * This function flushes all wqes in the nvme rings and frees all resources + * in the txcmplq. This function does not issue abort wqes for the IO + * commands in txcmplq, they will just be returned with + * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI + * slot has been permanently disabled. + **/ +void +lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba) +{ + struct lpfc_sli_ring *pring; + u32 i, wait_cnt = 0; + + if (phba->sli_rev < LPFC_SLI_REV4) + return; + + /* Cycle through all NVME rings and make sure all outstanding + * WQEs have been removed from the txcmplqs. + */ + for (i = 0; i < phba->cfg_nvme_io_channel; i++) { + pring = phba->sli4_hba.nvme_wq[i]->pring; + + /* Retrieve everything on the txcmplq */ + while (!list_empty(&pring->txcmplq)) { + msleep(LPFC_XRI_EXCH_BUSY_WAIT_T1); + wait_cnt++; + + /* The sleep is 10mS. Every ten seconds, + * dump a message. Something is wrong. + */ + if ((wait_cnt % 1000) == 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6178 NVME IO not empty, " + "cnt %d\n", wait_cnt); + } + } + } +} diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h index d192bb268f99..e79f8f75758c 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.h +++ b/drivers/scsi/lpfc/lpfc_nvme.h @@ -22,10 +22,12 @@ ********************************************************************/ #define LPFC_NVME_DEFAULT_SEGS (64 + 1) /* 256K IOs */ -#define LPFC_NVME_WQSIZE 256 #define LPFC_NVME_ERSP_LEN 0x20 +#define LPFC_NVME_WAIT_TMO 10 +#define LPFC_NVME_EXPEDITE_XRICNT 8 + struct lpfc_nvme_qhandle { uint32_t index; /* WQ index to use */ uint32_t qidx; /* queue index passed to create */ @@ -36,7 +38,18 @@ struct lpfc_nvme_qhandle { struct lpfc_nvme_lport { struct lpfc_vport *vport; struct completion lport_unreg_done; - /* Add sttats counters here */ + /* Add stats counters here */ + atomic_t xmt_fcp_noxri; + atomic_t xmt_fcp_bad_ndlp; + atomic_t xmt_fcp_qdepth; + atomic_t xmt_fcp_wqerr; + atomic_t xmt_fcp_abort; + atomic_t xmt_ls_abort; + atomic_t xmt_ls_err; + atomic_t cmpl_fcp_xb; + atomic_t cmpl_fcp_err; + atomic_t cmpl_ls_xb; + atomic_t cmpl_ls_err; }; struct lpfc_nvme_rport { diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 84cf1b9079f7..8dbf5c9d51aa 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -38,6 +38,7 @@ #include <../drivers/nvme/host/nvme.h> #include <linux/nvme-fc-driver.h> +#include <linux/nvme-fc.h> #include "lpfc_version.h" #include "lpfc_hw4.h" @@ -126,10 +127,17 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; - if (status) - atomic_inc(&tgtp->xmt_ls_rsp_error); - else - atomic_inc(&tgtp->xmt_ls_rsp_cmpl); + if (tgtp) { + if (status) { + atomic_inc(&tgtp->xmt_ls_rsp_error); + if (status == IOERR_ABORT_REQUESTED) + atomic_inc(&tgtp->xmt_ls_rsp_aborted); + if (bf_get(lpfc_wcqe_c_xb, wcqe)) + atomic_inc(&tgtp->xmt_ls_rsp_xb_set); + } else { + atomic_inc(&tgtp->xmt_ls_rsp_cmpl); + } + } out: rsp = &ctxp->ctx.ls_req; @@ -218,6 +226,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) ctxp->entry_cnt = 1; ctxp->flag = 0; ctxp->ctxbuf = ctx_buf; + ctxp->rqb_buffer = (void *)nvmebuf; spin_lock_init(&ctxp->ctxlock); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -253,6 +262,17 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) return; } + /* Processing of FCP command is deferred */ + if (rc == -EOVERFLOW) { + lpfc_nvmeio_data(phba, + "NVMET RCV BUSY: xri x%x sz %d " + "from %06x\n", + oxid, size, sid); + /* defer repost rcv buffer till .defer_rcv callback */ + ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST; + atomic_inc(&tgtp->rcv_fcp_cmd_out); + return; + } atomic_inc(&tgtp->rcv_fcp_cmd_drop); lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, "2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n", @@ -519,8 +539,11 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, if (status) { rsp->fcp_error = NVME_SC_DATA_XFER_ERROR; rsp->transferred_length = 0; - if (tgtp) + if (tgtp) { atomic_inc(&tgtp->xmt_fcp_rsp_error); + if (status == IOERR_ABORT_REQUESTED) + atomic_inc(&tgtp->xmt_fcp_rsp_aborted); + } logerr = LOG_NVME_IOERR; @@ -528,6 +551,8 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, if (bf_get(lpfc_wcqe_c_xb, wcqe)) { ctxp->flag |= LPFC_NVMET_XBUSY; logerr |= LOG_NVME_ABTS; + if (tgtp) + atomic_inc(&tgtp->xmt_fcp_rsp_xb_set); } else { ctxp->flag &= ~LPFC_NVMET_XBUSY; @@ -635,6 +660,9 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, if (phba->pport->load_flag & FC_UNLOADING) return -ENODEV; + if (phba->pport->load_flag & FC_UNLOADING) + return -ENODEV; + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, "6023 NVMET LS rsp oxid x%x\n", ctxp->oxid); @@ -721,6 +749,11 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, goto aerr; } + if (phba->pport->load_flag & FC_UNLOADING) { + rc = -ENODEV; + goto aerr; + } + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (ctxp->ts_cmd_nvme) { if (rsp->op == NVMET_FCOP_RSP) @@ -823,6 +856,9 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, if (phba->pport->load_flag & FC_UNLOADING) return; + if (phba->pport->load_flag & FC_UNLOADING) + return; + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, "6103 NVMET Abort op: oxri x%x flg x%x ste %d\n", ctxp->oxid, ctxp->flag, ctxp->state); @@ -910,7 +946,11 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, tgtp = phba->targetport->private; atomic_inc(&tgtp->rcv_fcp_cmd_defer); - lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ + if (ctxp->flag & LPFC_NVMET_DEFER_RCV_REPOST) + lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ + else + nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); + ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST; } static struct nvmet_fc_target_template lpfc_tgttemplate = { @@ -1216,6 +1256,8 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) atomic_set(&tgtp->xmt_ls_rsp, 0); atomic_set(&tgtp->xmt_ls_drop, 0); atomic_set(&tgtp->xmt_ls_rsp_error, 0); + atomic_set(&tgtp->xmt_ls_rsp_xb_set, 0); + atomic_set(&tgtp->xmt_ls_rsp_aborted, 0); atomic_set(&tgtp->xmt_ls_rsp_cmpl, 0); atomic_set(&tgtp->rcv_fcp_cmd_in, 0); atomic_set(&tgtp->rcv_fcp_cmd_out, 0); @@ -1228,7 +1270,10 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) atomic_set(&tgtp->xmt_fcp_release, 0); atomic_set(&tgtp->xmt_fcp_rsp_cmpl, 0); atomic_set(&tgtp->xmt_fcp_rsp_error, 0); + atomic_set(&tgtp->xmt_fcp_rsp_xb_set, 0); + atomic_set(&tgtp->xmt_fcp_rsp_aborted, 0); atomic_set(&tgtp->xmt_fcp_rsp_drop, 0); + atomic_set(&tgtp->xmt_fcp_xri_abort_cqe, 0); atomic_set(&tgtp->xmt_fcp_abort, 0); atomic_set(&tgtp->xmt_fcp_abort_cmpl, 0); atomic_set(&tgtp->xmt_abort_unsol, 0); @@ -1270,6 +1315,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; + struct lpfc_nvmet_tgtport *tgtp; struct lpfc_nodelist *ndlp; unsigned long iflag = 0; int rrq_empty = 0; @@ -1280,6 +1326,12 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) return; + + if (phba->targetport) { + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + atomic_inc(&tgtp->xmt_fcp_xri_abort_cqe); + } + spin_lock_irqsave(&phba->hbalock, iflag); spin_lock(&phba->sli4_hba.abts_nvme_buf_list_lock); list_for_each_entry_safe(ctxp, next_ctxp, @@ -1682,6 +1734,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, ctxp->entry_cnt = 1; ctxp->flag = 0; ctxp->ctxbuf = ctx_buf; + ctxp->rqb_buffer = (void *)nvmebuf; spin_lock_init(&ctxp->ctxlock); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -1715,6 +1768,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, /* Process FCP command */ if (rc == 0) { + ctxp->rqb_buffer = NULL; atomic_inc(&tgtp->rcv_fcp_cmd_out); lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ return; @@ -1726,10 +1780,11 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, "NVMET RCV BUSY: xri x%x sz %d from %06x\n", oxid, size, sid); /* defer reposting rcv buffer till .defer_rcv callback */ - ctxp->rqb_buffer = nvmebuf; + ctxp->flag |= LPFC_NVMET_DEFER_RCV_REPOST; atomic_inc(&tgtp->rcv_fcp_cmd_out); return; } + ctxp->rqb_buffer = nvmebuf; atomic_inc(&tgtp->rcv_fcp_cmd_drop); lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, @@ -1992,7 +2047,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, return NULL; } - if (rsp->sg_cnt > phba->cfg_nvme_seg_cnt) { + if (rsp->sg_cnt > lpfc_tgttemplate.max_sgl_segments) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, "6109 NVMET prep FCP wqe: seg cnt err: " "NPORT x%x oxid x%x ste %d cnt %d\n", diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h index 25a65b0bb7f3..5b32c9e4d4ef 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.h +++ b/drivers/scsi/lpfc/lpfc_nvmet.h @@ -25,6 +25,10 @@ #define LPFC_NVMET_RQE_DEF_COUNT 512 #define LPFC_NVMET_SUCCESS_LEN 12 +#define LPFC_NVMET_MRQ_OFF 0xffff +#define LPFC_NVMET_MRQ_AUTO 0 +#define LPFC_NVMET_MRQ_MAX 16 + /* Used for NVME Target */ struct lpfc_nvmet_tgtport { struct lpfc_hba *phba; @@ -43,6 +47,8 @@ struct lpfc_nvmet_tgtport { /* Stats counters - lpfc_nvmet_xmt_ls_rsp_cmp */ atomic_t xmt_ls_rsp_error; + atomic_t xmt_ls_rsp_aborted; + atomic_t xmt_ls_rsp_xb_set; atomic_t xmt_ls_rsp_cmpl; /* Stats counters - lpfc_nvmet_unsol_fcp_buffer */ @@ -60,12 +66,15 @@ struct lpfc_nvmet_tgtport { atomic_t xmt_fcp_rsp; /* Stats counters - lpfc_nvmet_xmt_fcp_op_cmp */ + atomic_t xmt_fcp_rsp_xb_set; atomic_t xmt_fcp_rsp_cmpl; atomic_t xmt_fcp_rsp_error; + atomic_t xmt_fcp_rsp_aborted; atomic_t xmt_fcp_rsp_drop; /* Stats counters - lpfc_nvmet_xmt_fcp_abort */ + atomic_t xmt_fcp_xri_abort_cqe; atomic_t xmt_fcp_abort; atomic_t xmt_fcp_abort_cmpl; atomic_t xmt_abort_sol; @@ -122,6 +131,7 @@ struct lpfc_nvmet_rcv_ctx { #define LPFC_NVMET_XBUSY 0x4 /* XB bit set on IO cmpl */ #define LPFC_NVMET_CTX_RLS 0x8 /* ctx free requested */ #define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */ +#define LPFC_NVMET_DEFER_RCV_REPOST 0x20 /* repost to RQ on defer rcv */ struct rqb_dmabuf *rqb_buffer; struct lpfc_nvmet_ctxbuf *ctxbuf; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index aecd2399005d..5f5528a12308 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -475,28 +475,30 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, struct lpfc_rqe *temp_hrqe; struct lpfc_rqe *temp_drqe; struct lpfc_register doorbell; - int put_index; + int hq_put_index; + int dq_put_index; /* sanity check on queue memory */ if (unlikely(!hq) || unlikely(!dq)) return -ENOMEM; - put_index = hq->host_index; - temp_hrqe = hq->qe[put_index].rqe; - temp_drqe = dq->qe[dq->host_index].rqe; + hq_put_index = hq->host_index; + dq_put_index = dq->host_index; + temp_hrqe = hq->qe[hq_put_index].rqe; + temp_drqe = dq->qe[dq_put_index].rqe; if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ) return -EINVAL; - if (put_index != dq->host_index) + if (hq_put_index != dq_put_index) return -EINVAL; /* If the host has not yet processed the next entry then we are done */ - if (((put_index + 1) % hq->entry_count) == hq->hba_index) + if (((hq_put_index + 1) % hq->entry_count) == hq->hba_index) return -EBUSY; lpfc_sli_pcimem_bcopy(hrqe, temp_hrqe, hq->entry_size); lpfc_sli_pcimem_bcopy(drqe, temp_drqe, dq->entry_size); /* Update the host index to point to the next slot */ - hq->host_index = ((put_index + 1) % hq->entry_count); - dq->host_index = ((dq->host_index + 1) % dq->entry_count); + hq->host_index = ((hq_put_index + 1) % hq->entry_count); + dq->host_index = ((dq_put_index + 1) % dq->entry_count); hq->RQ_buf_posted++; /* Ring The Header Receive Queue Doorbell */ @@ -517,7 +519,7 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, } writel(doorbell.word0, hq->db_regaddr); } - return put_index; + return hq_put_index; } /** @@ -12318,41 +12320,6 @@ void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *phba) } /** - * lpfc_sli4_nvme_xri_abort_event_proc - Process nvme xri abort event - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked by the worker thread to process all the pending - * SLI4 NVME abort XRI events. - **/ -void lpfc_sli4_nvme_xri_abort_event_proc(struct lpfc_hba *phba) -{ - struct lpfc_cq_event *cq_event; - - /* First, declare the fcp xri abort event has been handled */ - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~NVME_XRI_ABORT_EVENT; - spin_unlock_irq(&phba->hbalock); - /* Now, handle all the fcp xri abort events */ - while (!list_empty(&phba->sli4_hba.sp_nvme_xri_aborted_work_queue)) { - /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); - list_remove_head(&phba->sli4_hba.sp_nvme_xri_aborted_work_queue, - cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); - /* Notify aborted XRI for NVME work queue */ - if (phba->nvmet_support) { - lpfc_sli4_nvmet_xri_aborted(phba, - &cq_event->cqe.wcqe_axri); - } else { - lpfc_sli4_nvme_xri_aborted(phba, - &cq_event->cqe.wcqe_axri); - } - /* Free the event processed back to the free pool */ - lpfc_sli4_cq_event_release(phba, cq_event); - } -} - -/** * lpfc_sli4_els_xri_abort_event_proc - Process els xri abort event * @phba: pointer to lpfc hba data structure. * @@ -12548,6 +12515,24 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, return irspiocbq; } +inline struct lpfc_cq_event * +lpfc_cq_event_setup(struct lpfc_hba *phba, void *entry, int size) +{ + struct lpfc_cq_event *cq_event; + + /* Allocate a new internal CQ_EVENT entry */ + cq_event = lpfc_sli4_cq_event_alloc(phba); + if (!cq_event) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0602 Failed to alloc CQ_EVENT entry\n"); + return NULL; + } + + /* Move the CQE into the event */ + memcpy(&cq_event->cqe, entry, size); + return cq_event; +} + /** * lpfc_sli4_sp_handle_async_event - Handle an asynchroous event * @phba: Pointer to HBA context object. @@ -12569,16 +12554,9 @@ lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) "word2:x%x, word3:x%x\n", mcqe->word0, mcqe->mcqe_tag0, mcqe->mcqe_tag1, mcqe->trailer); - /* Allocate a new internal CQ_EVENT entry */ - cq_event = lpfc_sli4_cq_event_alloc(phba); - if (!cq_event) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0394 Failed to allocate CQ_EVENT entry\n"); + cq_event = lpfc_cq_event_setup(phba, mcqe, sizeof(struct lpfc_mcqe)); + if (!cq_event) return false; - } - - /* Move the CQE into an asynchronous event entry */ - memcpy(&cq_event->cqe, mcqe, sizeof(struct lpfc_mcqe)); spin_lock_irqsave(&phba->hbalock, iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue); /* Set the async event flag */ @@ -12824,18 +12802,12 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, struct lpfc_cq_event *cq_event; unsigned long iflags; - /* Allocate a new internal CQ_EVENT entry */ - cq_event = lpfc_sli4_cq_event_alloc(phba); - if (!cq_event) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0602 Failed to allocate CQ_EVENT entry\n"); - return false; - } - - /* Move the CQE into the proper xri abort event list */ - memcpy(&cq_event->cqe, wcqe, sizeof(struct sli4_wcqe_xri_aborted)); switch (cq->subtype) { case LPFC_FCP: + cq_event = lpfc_cq_event_setup( + phba, wcqe, sizeof(struct sli4_wcqe_xri_aborted)); + if (!cq_event) + return false; spin_lock_irqsave(&phba->hbalock, iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_fcp_xri_aborted_work_queue); @@ -12844,7 +12816,12 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, spin_unlock_irqrestore(&phba->hbalock, iflags); workposted = true; break; + case LPFC_NVME_LS: /* NVME LS uses ELS resources */ case LPFC_ELS: + cq_event = lpfc_cq_event_setup( + phba, wcqe, sizeof(struct sli4_wcqe_xri_aborted)); + if (!cq_event) + return false; spin_lock_irqsave(&phba->hbalock, iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_els_xri_aborted_work_queue); @@ -12854,13 +12831,13 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, workposted = true; break; case LPFC_NVME: - spin_lock_irqsave(&phba->hbalock, iflags); - list_add_tail(&cq_event->list, - &phba->sli4_hba.sp_nvme_xri_aborted_work_queue); - /* Set the nvme xri abort event flag */ - phba->hba_flag |= NVME_XRI_ABORT_EVENT; - spin_unlock_irqrestore(&phba->hbalock, iflags); - workposted = true; + /* Notify aborted XRI for NVME work queue */ + if (phba->nvmet_support) + lpfc_sli4_nvmet_xri_aborted(phba, wcqe); + else + lpfc_sli4_nvme_xri_aborted(phba, wcqe); + + workposted = false; break; default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -12868,7 +12845,6 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, "%08x %08x %08x %08x\n", cq->subtype, wcqe->word0, wcqe->parameter, wcqe->word2, wcqe->word3); - lpfc_sli4_cq_event_release(phba, cq_event); workposted = false; break; } @@ -12913,8 +12889,8 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2537 Receive Frame Truncated!!\n"); case FC_STATUS_RQ_SUCCESS: - lpfc_sli4_rq_release(hrq, drq); spin_lock_irqsave(&phba->hbalock, iflags); + lpfc_sli4_rq_release(hrq, drq); dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list); if (!dma_buf) { hrq->RQ_no_buf_found++; @@ -13316,8 +13292,8 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, "6126 Receive Frame Truncated!!\n"); /* Drop thru */ case FC_STATUS_RQ_SUCCESS: - lpfc_sli4_rq_release(hrq, drq); spin_lock_irqsave(&phba->hbalock, iflags); + lpfc_sli4_rq_release(hrq, drq); dma_buf = lpfc_sli_rqbuf_get(phba, hrq); if (!dma_buf) { hrq->RQ_no_buf_found++; @@ -13919,7 +13895,7 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue) while (!list_empty(&queue->page_list)) { list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf, list); - dma_free_coherent(&queue->phba->pcidev->dev, SLI4_PAGE_SIZE, + dma_free_coherent(&queue->phba->pcidev->dev, queue->page_size, dmabuf->virt, dmabuf->phys); kfree(dmabuf); } @@ -13938,6 +13914,7 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue) /** * lpfc_sli4_queue_alloc - Allocate and initialize a queue structure * @phba: The HBA that this queue is being created on. + * @page_size: The size of a queue page * @entry_size: The size of each queue entry for this queue. * @entry count: The number of entries that this queue will handle. * @@ -13946,8 +13923,8 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue) * queue on the HBA. **/ struct lpfc_queue * -lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size, - uint32_t entry_count) +lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size, + uint32_t entry_size, uint32_t entry_count) { struct lpfc_queue *queue; struct lpfc_dmabuf *dmabuf; @@ -13956,7 +13933,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size, uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; + hw_page_size = page_size; queue = kzalloc(sizeof(struct lpfc_queue) + (sizeof(union sli4_qe) * entry_count), GFP_KERNEL); @@ -13973,6 +13950,15 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size, INIT_LIST_HEAD(&queue->wq_list); INIT_LIST_HEAD(&queue->page_list); INIT_LIST_HEAD(&queue->child_list); + + /* Set queue parameters now. If the system cannot provide memory + * resources, the free routine needs to know what was allocated. + */ + queue->entry_size = entry_size; + queue->entry_count = entry_count; + queue->page_size = hw_page_size; + queue->phba = phba; + for (x = 0, total_qe_count = 0; x < queue->page_count; x++) { dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (!dmabuf) @@ -13994,9 +13980,6 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size, queue->qe[total_qe_count].address = dma_pointer; } } - queue->entry_size = entry_size; - queue->entry_count = entry_count; - queue->phba = phba; INIT_WORK(&queue->irqwork, lpfc_sli4_hba_process_cq); INIT_WORK(&queue->spwork, lpfc_sli4_sp_process_cq); @@ -14299,7 +14282,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, if (!cq || !eq) return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; + hw_page_size = cq->page_size; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) @@ -14318,8 +14301,8 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, bf_set(lpfc_mbox_hdr_version, &shdr->request, phba->sli4_hba.pc_sli4_params.cqv); if (phba->sli4_hba.pc_sli4_params.cqv == LPFC_Q_CREATE_VERSION_2) { - /* FW only supports 1. Should be PAGE_SIZE/SLI4_PAGE_SIZE */ - bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request, 1); + bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request, + (cq->page_size / SLI4_PAGE_SIZE)); bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context, eq->queue_id); } else { @@ -14327,6 +14310,18 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, eq->queue_id); } switch (cq->entry_count) { + case 2048: + case 4096: + if (phba->sli4_hba.pc_sli4_params.cqv == + LPFC_Q_CREATE_VERSION_2) { + cq_create->u.request.context.lpfc_cq_context_count = + cq->entry_count; + bf_set(lpfc_cq_context_count, + &cq_create->u.request.context, + LPFC_CQ_CNT_WORD7); + break; + } + /* Fall Thru */ default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0361 Unsupported CQ count: " @@ -14352,7 +14347,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, break; } list_for_each_entry(dmabuf, &cq->page_list, list) { - memset(dmabuf->virt, 0, hw_page_size); + memset(dmabuf->virt, 0, cq->page_size); cq_create->u.request.page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys); cq_create->u.request.page[dmabuf->buffer_tag].addr_hi = @@ -14433,8 +14428,6 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, numcq = phba->cfg_nvmet_mrq; if (!cqp || !eqp || !numcq) return -ENODEV; - if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) @@ -14465,6 +14458,8 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, status = -ENOMEM; goto out; } + if (!phba->sli4_hba.pc_sli4_params.supported) + hw_page_size = cq->page_size; switch (idx) { case 0: @@ -14482,6 +14477,19 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, bf_set(lpfc_mbx_cq_create_set_num_cq, &cq_set->u.request, numcq); switch (cq->entry_count) { + case 2048: + case 4096: + if (phba->sli4_hba.pc_sli4_params.cqv == + LPFC_Q_CREATE_VERSION_2) { + bf_set(lpfc_mbx_cq_create_set_cqe_cnt, + &cq_set->u.request, + cq->entry_count); + bf_set(lpfc_mbx_cq_create_set_cqe_cnt, + &cq_set->u.request, + LPFC_CQ_CNT_WORD7); + break; + } + /* Fall Thru */ default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3118 Bad CQ count. (%d)\n", @@ -14578,6 +14586,7 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, cq->host_index = 0; cq->hba_index = 0; cq->entry_repost = LPFC_CQ_REPOST; + cq->chann = idx; rc = 0; list_for_each_entry(dmabuf, &cq->page_list, list) { @@ -14872,12 +14881,13 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, void __iomem *bar_memmap_p; uint32_t db_offset; uint16_t pci_barset; + uint8_t wq_create_version; /* sanity check on queue memory */ if (!wq || !cq) return -ENODEV; if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; + hw_page_size = wq->page_size; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) @@ -14898,7 +14908,12 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, bf_set(lpfc_mbox_hdr_version, &shdr->request, phba->sli4_hba.pc_sli4_params.wqv); - switch (phba->sli4_hba.pc_sli4_params.wqv) { + if (phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) + wq_create_version = LPFC_Q_CREATE_VERSION_1; + else + wq_create_version = LPFC_Q_CREATE_VERSION_0; + + switch (wq_create_version) { case LPFC_Q_CREATE_VERSION_0: switch (wq->entry_size) { default: @@ -14956,7 +14971,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, } bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1, - LPFC_WQ_PAGE_SIZE_4096); + (wq->page_size / SLI4_PAGE_SIZE)); page = wq_create->u.request_1.page; break; default: diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 13b8f4d4da34..81fb58e59e60 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -161,7 +161,6 @@ struct lpfc_queue { #define LPFC_RELEASE_NOTIFICATION_INTERVAL 32 /* For WQs */ uint32_t queue_id; /* Queue ID assigned by the hardware */ uint32_t assoc_qid; /* Queue ID associated with, for CQ/WQ/MQ */ - uint32_t page_count; /* Number of pages allocated for this queue */ uint32_t host_index; /* The host's index for putting or getting */ uint32_t hba_index; /* The last known hba index for get or put */ @@ -169,6 +168,11 @@ struct lpfc_queue { struct lpfc_rqb *rqbp; /* ptr to RQ buffers */ uint32_t q_mode; + uint16_t page_count; /* Number of pages allocated for this queue */ + uint16_t page_size; /* size of page allocated for this queue */ +#define LPFC_EXPANDED_PAGE_SIZE 16384 +#define LPFC_DEFAULT_PAGE_SIZE 4096 + uint16_t chann; /* IO channel this queue is associated with */ uint16_t db_format; #define LPFC_DB_RING_FORMAT 0x01 #define LPFC_DB_LIST_FORMAT 0x02 @@ -366,9 +370,9 @@ struct lpfc_bmbx { #define LPFC_EQE_DEF_COUNT 1024 #define LPFC_CQE_DEF_COUNT 1024 +#define LPFC_CQE_EXP_COUNT 4096 #define LPFC_WQE_DEF_COUNT 256 -#define LPFC_WQE128_DEF_COUNT 128 -#define LPFC_WQE128_MAX_COUNT 256 +#define LPFC_WQE_EXP_COUNT 1024 #define LPFC_MQE_DEF_COUNT 16 #define LPFC_RQE_DEF_COUNT 512 @@ -668,7 +672,6 @@ struct lpfc_sli4_hba { struct list_head sp_asynce_work_queue; struct list_head sp_fcp_xri_aborted_work_queue; struct list_head sp_els_xri_aborted_work_queue; - struct list_head sp_nvme_xri_aborted_work_queue; struct list_head sp_unsol_work_queue; struct lpfc_sli4_link link_state; struct lpfc_sli4_lnk_info lnk_info; @@ -769,7 +772,7 @@ int lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *, struct lpfcMboxq *, void lpfc_sli4_hba_reset(struct lpfc_hba *); struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t, - uint32_t); + uint32_t, uint32_t); void lpfc_sli4_queue_free(struct lpfc_queue *); int lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint32_t); int lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, @@ -820,7 +823,6 @@ void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *); int lpfc_sli4_resume_rpi(struct lpfc_nodelist *, void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *); void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *); -void lpfc_sli4_nvme_xri_abort_event_proc(struct lpfc_hba *phba); void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *); void lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *, struct sli4_wcqe_xri_aborted *); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index e0181371af09..c232bf0e8998 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "11.4.0.4" +#define LPFC_DRIVER_VERSION "11.4.0.6" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ |