diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 744 |
1 files changed, 526 insertions, 218 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e158cd77d387..95caad764fb7 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -90,12 +90,138 @@ static void __lpfc_sli4_consume_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_cqe *cqe); +union lpfc_wqe128 lpfc_iread_cmd_template; +union lpfc_wqe128 lpfc_iwrite_cmd_template; +union lpfc_wqe128 lpfc_icmnd_cmd_template; + static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) { return &iocbq->iocb; } +/* Setup WQE templates for IOs */ +void lpfc_wqe_cmd_template(void) +{ + union lpfc_wqe128 *wqe; + + /* IREAD template */ + wqe = &lpfc_iread_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - cmd_buff_len, payload_offset_len is zero */ + + /* Word 4 - total_xfer_len is variable */ + + /* Word 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_iread.wqe_com, CMD_FCP_IREAD64_WQE); + bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, PARM_READ_CHECK); + bf_set(wqe_class, &wqe->fcp_iread.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_iread.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0); + bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); + bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4); + bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1); + + /* Word 11 - pbde is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, COMMAND_DATA_IN); + bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 0); + + /* Word 12 - is zero */ + + /* Word 13, 14, 15 - PBDE is variable */ + + /* IWRITE template */ + wqe = &lpfc_iwrite_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - cmd_buff_len, payload_offset_len is zero */ + + /* Word 4 - total_xfer_len is variable */ + + /* Word 5 - initial_xfer_len is variable */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_iwrite.wqe_com, CMD_FCP_IWRITE64_WQE); + bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, PARM_READ_CHECK); + bf_set(wqe_class, &wqe->fcp_iwrite.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_iwrite.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0); + bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); + bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4); + bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); + + /* Word 11 - pbde is variable */ + bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, COMMAND_DATA_OUT); + bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0); + + /* Word 12 - is zero */ + + /* Word 13, 14, 15 - PBDE is variable */ + + /* ICMND template */ + wqe = &lpfc_icmnd_cmd_template; + memset(wqe, 0, sizeof(union lpfc_wqe128)); + + /* Word 0, 1, 2 - BDE is variable */ + + /* Word 3 - payload_offset_len is variable */ + + /* Word 4, 5 - is zero */ + + /* Word 6 - ctxt_tag, xri_tag is variable */ + + /* Word 7 */ + bf_set(wqe_cmnd, &wqe->fcp_icmd.wqe_com, CMD_FCP_ICMND64_WQE); + bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, CLASS3); + bf_set(wqe_ct, &wqe->fcp_icmd.wqe_com, SLI4_CT_RPI); + + /* Word 8 - abort_tag is variable */ + + /* Word 9 - reqtag is variable */ + + /* Word 10 - dbde, wqes is variable */ + bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1); + bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_NONE); + bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE); + bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0); + bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1); + + /* Word 11 */ + bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, COMMAND_DATA_IN); + bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0); + + /* Word 12, 13, 14, 15 - is zero */ +} + #if defined(CONFIG_64BIT) && defined(__LITTLE_ENDIAN) /** * lpfc_sli4_pcimem_bcopy - SLI4 memory copy function @@ -150,6 +276,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe) /* sanity check on queue memory */ if (unlikely(!q)) return -ENOMEM; + temp_wqe = lpfc_sli4_qe(q, q->host_index); /* If the host has not yet processed the next entry then we are done */ @@ -860,7 +987,7 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba, { struct lpfc_nodelist *ndlp = NULL; - if ((rrq->vport) && NLP_CHK_NODE_ACT(rrq->ndlp)) + if (rrq->vport) ndlp = lpfc_findnode_did(rrq->vport, rrq->nlp_DID); /* The target DID could have been swapped (cable swap) @@ -1061,12 +1188,6 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, goto out; } - /* - * set the active bit even if there is no mem available. - */ - if (NLP_CHK_FREE_REQ(ndlp)) - goto out; - if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING)) goto out; @@ -1289,6 +1410,11 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) (sglq->state != SGL_XRI_ABORTED)) { spin_lock_irqsave(&phba->sli4_hba.sgl_list_lock, iflag); + + /* Check if we can get a reference on ndlp */ + if (sglq->ndlp && !lpfc_nlp_get(sglq->ndlp)) + sglq->ndlp = NULL; + list_add(&sglq->list, &phba->sli4_hba.lpfc_abts_els_sgl_list); spin_unlock_irqrestore( @@ -2449,10 +2575,10 @@ __lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->nlp_flag & NLP_RELEASE_RPI) { lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); - spin_lock_irqsave(&vport->phba->ndlp_lock, iflags); + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->nlp_flag &= ~NLP_RELEASE_RPI; ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - spin_unlock_irqrestore(&vport->phba->ndlp_lock, iflags); + spin_unlock_irqrestore(&ndlp->lock, iflags); } ndlp->nlp_flag &= ~NLP_UNREG_INP; } @@ -2529,9 +2655,10 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport, KERN_INFO, LOG_MBOX | LOG_DISCOVERY, "1438 UNREG cmpl deferred mbox x%x " - "on NPort x%x Data: x%x x%x %px\n", + "on NPort x%x Data: x%x x%x %px x%x x%x\n", ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, ndlp->nlp_defer_did, ndlp); + ndlp->nlp_flag, ndlp->nlp_defer_did, + ndlp, vport->load_flag, kref_read(&ndlp->kref)); if ((ndlp->nlp_flag & NLP_UNREG_INP) && (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) { @@ -2541,8 +2668,12 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { __lpfc_sli_rpi_release(vport, ndlp); } - if (vport->load_flag & FC_UNLOADING) - lpfc_nlp_put(ndlp); + + /* The unreg_login mailbox is complete and had a + * reference that has to be released. The PLOGI + * got its own ref. + */ + lpfc_nlp_put(ndlp); pmb->ctx_ndlp = NULL; } } @@ -2566,7 +2697,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * * This function is the unreg rpi mailbox completion handler. It * frees the memory resources associated with the completed mailbox - * command. An additional refrenece is put on the ndlp to prevent + * command. An additional reference is put on the ndlp to prevent * lpfc_nlp_release from freeing the rpi bit in the bitmask before * the unreg mailbox command completes, this routine puts the * reference back. @@ -2586,16 +2717,15 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) LPFC_SLI_INTF_IF_TYPE_2)) { if (ndlp) { lpfc_printf_vlog( - vport, KERN_INFO, LOG_MBOX | LOG_SLI, + vport, KERN_INFO, LOG_MBOX | LOG_SLI, "0010 UNREG_LOGIN vpi:%x " "rpi:%x DID:%x defer x%x flg x%x " - "map:%x %px\n", + "%px\n", vport->vpi, ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp->nlp_flag, - ndlp->nlp_usg_map, ndlp); + ndlp); ndlp->nlp_flag &= ~NLP_LOGO_ACC; - lpfc_nlp_put(ndlp); /* Check to see if there are any deferred * events to process @@ -2618,6 +2748,8 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { __lpfc_sli_rpi_release(vport, ndlp); } + + lpfc_nlp_put(ndlp); } } } @@ -2852,7 +2984,7 @@ lpfc_nvme_unsol_ls_handler(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) /* validate the source of the LS is logged in */ ndlp = lpfc_findnode_did(phba->pport, sid); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + if (!ndlp || ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, @@ -4077,7 +4209,7 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) spin_lock_irq(&phba->hbalock); /* Next issue ABTS for everything on the txcmplq */ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); spin_unlock_irq(&phba->hbalock); } else { spin_lock_irq(&phba->hbalock); @@ -4086,7 +4218,7 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) /* Next issue ABTS for everything on the txcmplq */ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); spin_unlock_irq(&phba->hbalock); } @@ -7248,12 +7380,16 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, struct rqb_dmabuf *rqb_buffer; LIST_HEAD(rqb_buf_list); - spin_lock_irqsave(&phba->hbalock, flags); rqbp = hrq->rqbp; for (i = 0; i < count; i++) { + spin_lock_irqsave(&phba->hbalock, flags); /* IF RQ is already full, don't bother */ - if (rqbp->buffer_count + i >= rqbp->entry_count - 1) + if (rqbp->buffer_count + i >= rqbp->entry_count - 1) { + spin_unlock_irqrestore(&phba->hbalock, flags); break; + } + spin_unlock_irqrestore(&phba->hbalock, flags); + rqb_buffer = rqbp->rqb_alloc_buffer(phba); if (!rqb_buffer) break; @@ -7262,6 +7398,8 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, rqb_buffer->idx = idx; list_add_tail(&rqb_buffer->hbuf.list, &rqb_buf_list); } + + spin_lock_irqsave(&phba->hbalock, flags); while (!list_empty(&rqb_buf_list)) { list_remove_head(&rqb_buf_list, rqb_buffer, struct rqb_dmabuf, hbuf.list); @@ -9189,7 +9327,6 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) "1420 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } return 0; } @@ -10072,7 +10209,6 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, "2014 Invalid command 0x%x\n", iocbq->iocb.ulpCommand); return IOCB_ERROR; - break; } if (iocbq->iocb_flag & LPFC_IO_DIF_PASS) @@ -10094,6 +10230,96 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, } /** + * __lpfc_sli_issue_fcp_io_s3 - SLI3 device for sending fcp io iocb + * @phba: Pointer to HBA context object. + * @ring_number: SLI ring number to issue wqe on. + * @piocb: Pointer to command iocb. + * @flag: Flag indicating if this command can be put into txq. + * + * __lpfc_sli_issue_fcp_io_s3 is wrapper function to invoke lockless func to + * send an iocb command to an HBA with SLI-4 interface spec. + * + * This function takes the hbalock before invoking the lockless version. + * The function will return success after it successfully submit the wqe to + * firmware or after adding to the txq. + **/ +static int +__lpfc_sli_issue_fcp_io_s3(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + unsigned long iflags; + int rc; + + spin_lock_irqsave(&phba->hbalock, iflags); + rc = __lpfc_sli_issue_iocb_s3(phba, ring_number, piocb, flag); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + return rc; +} + +/** + * __lpfc_sli_issue_fcp_io_s4 - SLI4 device for sending fcp io wqe + * @phba: Pointer to HBA context object. + * @ring_number: SLI ring number to issue wqe on. + * @piocb: Pointer to command iocb. + * @flag: Flag indicating if this command can be put into txq. + * + * __lpfc_sli_issue_fcp_io_s4 is used by other functions in the driver to issue + * an wqe command to an HBA with SLI-4 interface spec. + * + * This function is a lockless version. The function will return success + * after it successfully submit the wqe to firmware or after adding to the + * txq. + **/ +static int +__lpfc_sli_issue_fcp_io_s4(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + int rc; + struct lpfc_io_buf *lpfc_cmd = + (struct lpfc_io_buf *)piocb->context1; + union lpfc_wqe128 *wqe = &piocb->wqe; + struct sli4_sge *sgl; + + /* 128 byte wqe support here */ + sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; + + if (phba->fcp_embed_io) { + struct fcp_cmnd *fcp_cmnd; + u32 *ptr; + + fcp_cmnd = lpfc_cmd->fcp_cmnd; + + /* Word 0-2 - FCP_CMND */ + wqe->generic.bde.tus.f.bdeFlags = + BUFF_TYPE_BDE_IMMED; + wqe->generic.bde.tus.f.bdeSize = sgl->sge_len; + wqe->generic.bde.addrHigh = 0; + wqe->generic.bde.addrLow = 88; /* Word 22 */ + + bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1); + bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0); + + /* Word 22-29 FCP CMND Payload */ + ptr = &wqe->words[22]; + memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd)); + } else { + /* Word 0-2 - Inline BDE */ + wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; + wqe->generic.bde.tus.f.bdeSize = sizeof(struct fcp_cmnd); + wqe->generic.bde.addrHigh = sgl->addr_hi; + wqe->generic.bde.addrLow = sgl->addr_lo; + + /* Word 10 */ + bf_set(wqe_dbde, &wqe->generic.wqe_com, 1); + bf_set(wqe_wqes, &wqe->generic.wqe_com, 0); + } + + rc = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, piocb); + return rc; +} + +/** * __lpfc_sli_issue_iocb_s4 - SLI4 device lockless ver of lpfc_sli_issue_iocb * @phba: Pointer to HBA context object. * @ring_number: SLI ring number to issue iocb on. @@ -10159,9 +10385,10 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, } } } - } else if (piocb->iocb_flag & LPFC_IO_FCP) + } else if (piocb->iocb_flag & LPFC_IO_FCP) { /* These IO's already have an XRI and a mapped sgl. */ sglq = NULL; + } else { /* * This is a continuation of a commandi,(CX) so this @@ -10189,6 +10416,25 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, return 0; } +/** + * lpfc_sli_issue_fcp_io - Wrapper func for issuing fcp i/o + * + * This routine wraps the actual fcp i/o function for issusing WQE for sli-4 + * or IOCB for sli-3 function. + * pointer from the lpfc_hba struct. + * + * Return codes: + * IOCB_ERROR - Error + * IOCB_SUCCESS - Success + * IOCB_BUSY - Busy + **/ +int +lpfc_sli_issue_fcp_io(struct lpfc_hba *phba, uint32_t ring_number, + struct lpfc_iocbq *piocb, uint32_t flag) +{ + return phba->__lpfc_sli_issue_fcp_io(phba, ring_number, piocb, flag); +} + /* * __lpfc_sli_issue_iocb - Wrapper func of lockless version for issuing iocb * @@ -10224,17 +10470,18 @@ lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) case LPFC_PCI_DEV_LP: phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s3; phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s3; + phba->__lpfc_sli_issue_fcp_io = __lpfc_sli_issue_fcp_io_s3; break; case LPFC_PCI_DEV_OC: phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s4; phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s4; + phba->__lpfc_sli_issue_fcp_io = __lpfc_sli_issue_fcp_io_s4; break; default: lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "1419 Invalid HBA PCI-device group: 0x%x\n", dev_grp); return -ENODEV; - break; } phba->lpfc_get_iocb_from_iocbq = lpfc_get_iocb_from_iocbq; return 0; @@ -10364,6 +10611,32 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) return 0; } +static void +lpfc_sli_post_recovery_event(struct lpfc_hba *phba, + struct lpfc_nodelist *ndlp) +{ + unsigned long iflags; + struct lpfc_work_evt *evtp = &ndlp->recovery_evt; + + spin_lock_irqsave(&phba->hbalock, iflags); + if (!list_empty(&evtp->evt_listp)) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return; + } + + /* Incrementing the reference count until the queued work is done. */ + evtp->evt_arg1 = lpfc_nlp_get(ndlp); + if (!evtp->evt_arg1) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + return; + } + evtp->evt = LPFC_EVT_RECOVER_PORT; + list_add_tail(&evtp->evt_listp, &phba->work_list); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + lpfc_worker_wake_up(phba); +} + /* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. * @phba: Pointer to HBA context object. * @iocbq: Pointer to iocb object. @@ -10397,7 +10670,7 @@ lpfc_sli_abts_err_handler(struct lpfc_hba *phba, if (!vport) goto err_exit; ndlp = lpfc_findnode_rpi(vport, rpi); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + if (!ndlp) goto err_exit; if (iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) @@ -10427,17 +10700,15 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct sli4_wcqe_xri_aborted *axri) { - struct lpfc_vport *vport; uint32_t ext_status = 0; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + if (!ndlp) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3115 Node Context not found, driver " "ignoring abts err event\n"); return; } - vport = ndlp->vport; lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "3116 Port generated FCP XRI ABORT event on " "vpi %d rpi %d xri x%x status 0x%x parameter x%x\n", @@ -10454,7 +10725,7 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, ext_status = axri->parameter & IOERR_PARAM_MASK; if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) && ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0))) - lpfc_sli_abts_recover_port(vport, ndlp); + lpfc_sli_post_recovery_event(phba, ndlp); } /** @@ -10908,7 +11179,8 @@ lpfc_sli_host_down(struct lpfc_vport *vport) &pring->txcmplq, list) { if (iocb->vport != vport) continue; - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, + NULL); } pring->flag = prev_pring_flag; } @@ -10935,7 +11207,8 @@ lpfc_sli_host_down(struct lpfc_vport *vport) &pring->txcmplq, list) { if (iocb->vport != vport) continue; - lpfc_sli_issue_abort_iotag(phba, pring, iocb); + lpfc_sli_issue_abort_iotag(phba, pring, iocb, + NULL); } pring->flag = prev_pring_flag; } @@ -11324,35 +11597,37 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "x%x x%x x%x\n", irsp->ulpIoTag, irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout); + lpfc_nlp_put((struct lpfc_nodelist *)cmdiocb->context1); if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) lpfc_ct_free_iocb(phba, cmdiocb); else lpfc_els_free_iocb(phba, cmdiocb); - return; } /** - * lpfc_sli_abort_iotag_issue - Issue abort for a command iocb + * lpfc_sli_issue_abort_iotag - Abort function for a command iocb * @phba: Pointer to HBA context object. * @pring: Pointer to driver SLI ring object. * @cmdiocb: Pointer to driver command iocb object. + * @cmpl: completion function. + * + * This function issues an abort iocb for the provided command iocb. In case + * of unloading, the abort iocb will not be issued to commands on the ELS + * ring. Instead, the callback function shall be changed to those commands + * so that nothing happens when them finishes. This function is called with + * hbalock held andno ring_lock held (SLI4). The function returns IOCB_SUCCESS + * when the command iocb is an abort request. * - * This function issues an abort iocb for the provided command iocb down to - * the port. Other than the case the outstanding command iocb is an abort - * request, this function issues abort out unconditionally. This function is - * called with hbalock held. The function returns 0 when it fails due to - * memory allocation failure or when the command iocb is an abort request. - * The hbalock is asserted held in the code path calling this routine. **/ -static int -lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb) +int +lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *cmdiocb, void *cmpl) { struct lpfc_vport *vport = cmdiocb->vport; struct lpfc_iocbq *abtsiocbp; IOCB_t *icmd = NULL; IOCB_t *iabt = NULL; - int retval; + int retval = IOCB_ERROR; unsigned long iflags; struct lpfc_nodelist *ndlp; @@ -11365,12 +11640,33 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (icmd->ulpCommand == CMD_ABORT_XRI_CN || icmd->ulpCommand == CMD_CLOSE_XRI_CN || (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) - return 0; + return IOCB_ABORTING; + + if (!pring) { + if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) + cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; + else + cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; + return retval; + } + + /* + * If we're unloading, don't abort iocb on the ELS ring, but change + * the callback so that nothing happens when it finishes. + */ + if ((vport->load_flag & FC_UNLOADING) && + pring->ringno == LPFC_ELS_RING) { + if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) + cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; + else + cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; + return retval; + } /* issue ABTS for this IOCB based on iotag */ abtsiocbp = __lpfc_sli_get_iocbq(phba); if (abtsiocbp == NULL) - return 0; + return IOCB_NORESOURCE; /* This signals the response to set the correct status * before calling the completion handler @@ -11382,7 +11678,8 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt->un.acxri.abortContextTag = icmd->ulpContext; if (phba->sli_rev == LPFC_SLI_REV4) { iabt->un.acxri.abortIoTag = cmdiocb->sli4_xritag; - iabt->un.acxri.abortContextTag = cmdiocb->iotag; + if (pring->ringno == LPFC_ELS_RING) + iabt->un.acxri.abortContextTag = cmdiocb->iotag; } else { iabt->un.acxri.abortIoTag = icmd->ulpIoTag; if (pring->ringno == LPFC_ELS_RING) { @@ -11395,8 +11692,10 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abtsiocbp->hba_wqidx = cmdiocb->hba_wqidx; - if (cmdiocb->iocb_flag & LPFC_IO_FCP) + if (cmdiocb->iocb_flag & LPFC_IO_FCP) { + abtsiocbp->iocb_flag |= LPFC_IO_FCP; abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX; + } if (cmdiocb->iocb_flag & LPFC_IO_FOF) abtsiocbp->iocb_flag |= LPFC_IO_FOF; @@ -11405,20 +11704,16 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, else iabt->ulpCommand = CMD_CLOSE_XRI_CN; - abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; + if (cmpl) + abtsiocbp->iocb_cmpl = cmpl; + else + abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; abtsiocbp->vport = vport; - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "0339 Abort xri x%x, original iotag x%x, " - "abort cmd iotag x%x\n", - iabt->un.acxri.abortIoTag, - iabt->un.acxri.abortContextTag, - abtsiocbp->iotag); - if (phba->sli_rev == LPFC_SLI_REV4) { pring = lpfc_sli4_calc_ring(phba, abtsiocbp); if (unlikely(pring == NULL)) - return 0; + goto abort_iotag_exit; /* Note: both hbalock and ring_lock need to be set here */ spin_lock_irqsave(&pring->ring_lock, iflags); retval = __lpfc_sli_issue_iocb(phba, pring->ringno, @@ -11429,76 +11724,20 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, abtsiocbp, 0); } - if (retval) - __lpfc_sli_release_iocbq(phba, abtsiocbp); - - /* - * Caller to this routine should check for IOCB_ERROR - * and handle it properly. This routine no longer removes - * iocb off txcmplq and call compl in case of IOCB_ERROR. - */ - return retval; -} - -/** - * lpfc_sli_issue_abort_iotag - Abort function for a command iocb - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @cmdiocb: Pointer to driver command iocb object. - * - * This function issues an abort iocb for the provided command iocb. In case - * of unloading, the abort iocb will not be issued to commands on the ELS - * ring. Instead, the callback function shall be changed to those commands - * so that nothing happens when them finishes. This function is called with - * hbalock held. The function returns 0 when the command iocb is an abort - * request. - **/ -int -lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - int retval = IOCB_ERROR; - IOCB_t *icmd = NULL; - - lockdep_assert_held(&phba->hbalock); - - /* - * There are certain command types we don't want to abort. And we - * don't want to abort commands that are already in the process of - * being aborted. - */ - icmd = &cmdiocb->iocb; - if (icmd->ulpCommand == CMD_ABORT_XRI_CN || - icmd->ulpCommand == CMD_CLOSE_XRI_CN || - (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) - return 0; +abort_iotag_exit: - if (!pring) { - if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) - cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; - else - cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; - goto abort_iotag_exit; - } + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "0339 Abort xri x%x, original iotag x%x, " + "abort cmd iotag x%x retval x%x\n", + iabt->un.acxri.abortIoTag, + iabt->un.acxri.abortContextTag, + abtsiocbp->iotag, retval); - /* - * If we're unloading, don't abort iocb on the ELS ring, but change - * the callback so that nothing happens when it finishes. - */ - if ((vport->load_flag & FC_UNLOADING) && - (pring->ringno == LPFC_ELS_RING)) { - if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) - cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; - else - cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; - goto abort_iotag_exit; + if (retval) { + cmdiocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; + __lpfc_sli_release_iocbq(phba, abtsiocbp); } - /* Now, we try to issue the abort to the cmdiocb out */ - retval = lpfc_sli_abort_iotag_issue(phba, pring, cmdiocb); - -abort_iotag_exit: /* * Caller to this routine should check for IOCB_ERROR * and handle it properly. This routine no longer removes @@ -11643,6 +11882,33 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id, } /** + * lpfc_sli4_abort_fcp_cmpl - Completion handler function for aborted FCP IOCBs + * @phba: Pointer to HBA context object + * @cmdiocb: Pointer to command iocb object. + * @wcqe: pointer to the complete wcqe + * + * This function is called when an aborted FCP iocb completes. This + * function is called by the ring event handler with no lock held. + * This function frees the iocb. It is called for sli-4 adapters. + **/ +void +lpfc_sli4_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_wcqe_complete *wcqe) +{ + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3017 ABORT_XRI_CN completing on rpi x%x " + "original iotag x%x, abort cmd iotag x%x " + "status 0x%x, reason 0x%x\n", + cmdiocb->iocb.un.acxri.abortContextTag, + cmdiocb->iocb.un.acxri.abortIoTag, + cmdiocb->iotag, + (bf_get(lpfc_wcqe_c_status, wcqe) + & LPFC_IOCB_STATUS_MASK), + wcqe->parameter); + lpfc_sli_release_iocbq(phba, cmdiocb); +} + +/** * lpfc_sli_abort_fcp_cmpl - Completion handler function for aborted FCP IOCBs * @phba: Pointer to HBA context object * @cmdiocb: Pointer to command iocb object. @@ -11695,10 +11961,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, { struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *iocbq; - struct lpfc_iocbq *abtsiocb; - struct lpfc_sli_ring *pring_s4; - IOCB_t *cmd = NULL; int errcnt = 0, ret_val = 0; + unsigned long iflags; int i; /* all I/Os are in process of being flushed */ @@ -11712,62 +11976,12 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, abort_cmd) != 0) continue; - /* - * If the iocbq is already being aborted, don't take a second - * action, but do count it. - */ - if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED) - continue; - - /* issue ABTS for this IOCB based on iotag */ - abtsiocb = lpfc_sli_get_iocbq(phba); - if (abtsiocb == NULL) { - errcnt++; - continue; - } - - /* indicate the IO is being aborted by the driver. */ - iocbq->iocb_flag |= LPFC_DRIVER_ABORTED; - - cmd = &iocbq->iocb; - abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; - abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) - abtsiocb->iocb.un.acxri.abortIoTag = iocbq->sli4_xritag; - else - abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag; - abtsiocb->iocb.ulpLe = 1; - abtsiocb->iocb.ulpClass = cmd->ulpClass; - abtsiocb->vport = vport; - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocb->hba_wqidx = iocbq->hba_wqidx; - if (iocbq->iocb_flag & LPFC_IO_FCP) - abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; - if (iocbq->iocb_flag & LPFC_IO_FOF) - abtsiocb->iocb_flag |= LPFC_IO_FOF; - - if (lpfc_is_link_up(phba)) - abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; - else - abtsiocb->iocb.ulpCommand = CMD_CLOSE_XRI_CN; - - /* Setup callback routine and issue the command. */ - abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - if (phba->sli_rev == LPFC_SLI_REV4) { - pring_s4 = lpfc_sli4_calc_ring(phba, iocbq); - if (!pring_s4) - continue; - ret_val = lpfc_sli_issue_iocb(phba, pring_s4->ringno, - abtsiocb, 0); - } else - ret_val = lpfc_sli_issue_iocb(phba, pring->ringno, - abtsiocb, 0); - if (ret_val == IOCB_ERROR) { - lpfc_sli_release_iocbq(phba, abtsiocb); + spin_lock_irqsave(&phba->hbalock, iflags); + ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocbq, + lpfc_sli_abort_fcp_cmpl); + spin_unlock_irqrestore(&phba->hbalock, iflags); + if (ret_val != IOCB_SUCCESS) errcnt++; - continue; - } } return errcnt; @@ -13062,23 +13276,30 @@ lpfc_sli_intr_handler(int irq, void *dev_id) void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) { struct lpfc_cq_event *cq_event; + unsigned long iflags; /* First, declare the els xri abort event has been handled */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag &= ~ELS_XRI_ABORT_EVENT; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); + /* Now, handle all the els xri abort events */ + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); while (!list_empty(&phba->sli4_hba.sp_els_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_els_xri_aborted_work_queue, cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); /* Notify aborted XRI for ELS work queue */ lpfc_sli4_els_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); + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); } + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, iflags); } /** @@ -13289,9 +13510,13 @@ lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) cq_event = lpfc_cq_event_setup(phba, mcqe, sizeof(struct lpfc_mcqe)); if (!cq_event) return false; - spin_lock_irqsave(&phba->hbalock, iflags); + + spin_lock_irqsave(&phba->sli4_hba.asynce_list_lock, iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue); + spin_unlock_irqrestore(&phba->sli4_hba.asynce_list_lock, iflags); + /* Set the async event flag */ + spin_lock_irqsave(&phba->hbalock, iflags); phba->hba_flag |= ASYNC_EVENT; spin_unlock_irqrestore(&phba->hbalock, iflags); @@ -13375,6 +13600,12 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) pmbox->un.varWords[0], pmb); pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; pmb->ctx_buf = mp; + + /* No reference taken here. This is a default + * RPI reg/immediate unreg cycle. The reference was + * taken in the reg rpi path and is released when + * this mailbox completes. + */ pmb->ctx_ndlp = ndlp; pmb->vport = vport; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); @@ -13566,17 +13797,20 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, 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; + cq_event = lpfc_cq_event_setup(phba, wcqe, sizeof(*wcqe)); + if (!cq_event) { + workposted = false; + break; + } cq_event->hdwq = cq->hdwq; - spin_lock_irqsave(&phba->hbalock, iflags); + spin_lock_irqsave(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); list_add_tail(&cq_event->list, &phba->sli4_hba.sp_els_xri_aborted_work_queue); /* Set the els xri abort event flag */ phba->hba_flag |= ELS_XRI_ABORT_EVENT; - spin_unlock_irqrestore(&phba->hbalock, iflags); + spin_unlock_irqrestore(&phba->sli4_hba.els_xri_abrt_list_lock, + iflags); workposted = true; break; default: @@ -14046,7 +14280,9 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, #endif if (cmdiocbq->iocb_cmpl == NULL) { if (cmdiocbq->wqe_cmpl) { - if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) { + /* For FCP the flag is cleared in wqe_cmpl */ + if (!(cmdiocbq->iocb_flag & LPFC_IO_FCP) && + cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) { spin_lock_irqsave(&phba->hbalock, iflags); cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED; spin_unlock_irqrestore(&phba->hbalock, iflags); @@ -14063,6 +14299,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, return; } + /* Only SLI4 non-IO commands stil use IOCB */ /* Fake the irspiocb and copy necessary response information */ lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe); @@ -15850,12 +16087,6 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, else wq_create_version = LPFC_Q_CREATE_VERSION_0; - - 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_1: bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, @@ -17864,15 +18095,6 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, } /* Put ndlp onto pport node list */ lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, - "3275 Failed to active ndlp found " - "for oxid:x%x SID:x%x\n", oxid, sid); - return; - } } /* Allocate buffer for rsp iocb */ @@ -17897,6 +18119,10 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, icmd->ulpClass = CLASS3; icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; ctiocb->context1 = lpfc_nlp_get(ndlp); + if (!ctiocb->context1) { + lpfc_sli_release_iocbq(phba, ctiocb); + return; + } ctiocb->vport = phba->pport; ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; @@ -19840,7 +20066,6 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) struct lpfc_dmabuf *mp; struct lpfc_nodelist *ndlp; struct lpfc_nodelist *act_mbx_ndlp = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); LIST_HEAD(mbox_cmd_list); uint8_t restart_loop; @@ -19894,9 +20119,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) mb->mbox_flag |= LPFC_MBX_IMED_UNREG; restart_loop = 1; spin_unlock_irq(&phba->hbalock); - spin_lock(shost->host_lock); + spin_lock(&ndlp->lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); + spin_unlock(&ndlp->lock); spin_lock_irq(&phba->hbalock); break; } @@ -19918,9 +20143,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp; mb->ctx_ndlp = NULL; if (ndlp) { - spin_lock(shost->host_lock); + spin_lock(&ndlp->lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); + spin_unlock(&ndlp->lock); lpfc_nlp_put(ndlp); } } @@ -19929,9 +20154,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) /* Release the ndlp with the cleaned-up active mailbox command */ if (act_mbx_ndlp) { - spin_lock(shost->host_lock); + spin_lock(&act_mbx_ndlp->lock); act_mbx_ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); + spin_unlock(&act_mbx_ndlp->lock); lpfc_nlp_put(act_mbx_ndlp); } } @@ -20213,7 +20438,8 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, } /* NVME_FCREQ and NVME_ABTS requests */ - if (pwqe->iocb_flag & LPFC_IO_NVME) { + if (pwqe->iocb_flag & LPFC_IO_NVME || + pwqe->iocb_flag & LPFC_IO_FCP) { /* Get the IO distribution (hba_wqidx) for WQ assignment. */ wq = qp->io_wq; pring = wq->pring; @@ -20266,6 +20492,88 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, return WQE_ERROR; } +/** + * lpfc_sli4_issue_abort_iotag - SLI-4 WQE init & issue for the Abort + * @phba: Pointer to HBA context object. + * @cmdiocb: Pointer to driver command iocb object. + * @cmpl: completion function. + * + * Fill the appropriate fields for the abort WQE and call + * internal routine lpfc_sli4_issue_wqe to send the WQE + * This function is called with hbalock held and no ring_lock held. + * + * RETURNS 0 - SUCCESS + **/ + +int +lpfc_sli4_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + void *cmpl) +{ + struct lpfc_vport *vport = cmdiocb->vport; + struct lpfc_iocbq *abtsiocb = NULL; + union lpfc_wqe128 *abtswqe; + struct lpfc_io_buf *lpfc_cmd; + int retval = IOCB_ERROR; + u16 xritag = cmdiocb->sli4_xritag; + + /* + * The scsi command can not be in txq and it is in flight because the + * pCmd is still pointing at the SCSI command we have to abort. There + * is no need to search the txcmplq. Just send an abort to the FW. + */ + + abtsiocb = __lpfc_sli_get_iocbq(phba); + if (!abtsiocb) + return WQE_NORESOURCE; + + /* Indicate the IO is being aborted by the driver. */ + cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; + + abtswqe = &abtsiocb->wqe; + memset(abtswqe, 0, sizeof(*abtswqe)); + + if (lpfc_is_link_up(phba)) + bf_set(abort_cmd_ia, &abtswqe->abort_cmd, 1); + else + bf_set(abort_cmd_ia, &abtswqe->abort_cmd, 0); + bf_set(abort_cmd_criteria, &abtswqe->abort_cmd, T_XRI_TAG); + abtswqe->abort_cmd.rsrvd5 = 0; + abtswqe->abort_cmd.wqe_com.abort_tag = xritag; + bf_set(wqe_reqtag, &abtswqe->abort_cmd.wqe_com, abtsiocb->iotag); + bf_set(wqe_cmnd, &abtswqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); + bf_set(wqe_xri_tag, &abtswqe->generic.wqe_com, 0); + bf_set(wqe_qosd, &abtswqe->abort_cmd.wqe_com, 1); + bf_set(wqe_lenloc, &abtswqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); + bf_set(wqe_cmd_type, &abtswqe->abort_cmd.wqe_com, OTHER_COMMAND); + + /* ABTS WQE must go to the same WQ as the WQE to be aborted */ + abtsiocb->hba_wqidx = cmdiocb->hba_wqidx; + abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; + if (cmdiocb->iocb_flag & LPFC_IO_FCP) + abtsiocb->iocb_flag |= LPFC_IO_FCP; + if (cmdiocb->iocb_flag & LPFC_IO_NVME) + abtsiocb->iocb_flag |= LPFC_IO_NVME; + if (cmdiocb->iocb_flag & LPFC_IO_FOF) + abtsiocb->iocb_flag |= LPFC_IO_FOF; + abtsiocb->vport = vport; + abtsiocb->wqe_cmpl = cmpl; + + lpfc_cmd = container_of(cmdiocb, struct lpfc_io_buf, cur_iocbq); + retval = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, abtsiocb); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI | LOG_NVME_ABTS | LOG_FCP, + "0359 Abort xri x%x, original iotag x%x, " + "abort cmd iotag x%x retval x%x\n", + xritag, cmdiocb->iotag, abtsiocb->iotag, retval); + + if (retval) { + cmdiocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; + __lpfc_sli_release_iocbq(phba, abtsiocb); + } + + return retval; +} + #ifdef LPFC_MXP_STAT /** * lpfc_snapshot_mxp - Snapshot pbl, pvt and busy count |