mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
[SCSI] lpfc 8.3.37: Fixed no-context ABTS failed with BA_RJT
Fixed no-context ABTS received on unsolicited receive queue failed with BA_RJT Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
7b15db32d3
commit
6dd9e31ccb
5 changed files with 168 additions and 83 deletions
|
@ -466,11 +466,13 @@ enum intr_type_t {
|
||||||
MSIX,
|
MSIX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define LPFC_CT_CTX_MAX 64
|
||||||
struct unsol_rcv_ct_ctx {
|
struct unsol_rcv_ct_ctx {
|
||||||
uint32_t ctxt_id;
|
uint32_t ctxt_id;
|
||||||
uint32_t SID;
|
uint32_t SID;
|
||||||
uint32_t flags;
|
uint32_t valid;
|
||||||
#define UNSOL_VALID 0x00000001
|
#define UNSOL_INVALID 0
|
||||||
|
#define UNSOL_VALID 1
|
||||||
uint16_t oxid;
|
uint16_t oxid;
|
||||||
uint16_t rxid;
|
uint16_t rxid;
|
||||||
};
|
};
|
||||||
|
@ -938,7 +940,7 @@ struct lpfc_hba {
|
||||||
|
|
||||||
spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */
|
spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */
|
||||||
struct list_head ct_ev_waiters;
|
struct list_head ct_ev_waiters;
|
||||||
struct unsol_rcv_ct_ctx ct_ctx[64];
|
struct unsol_rcv_ct_ctx ct_ctx[LPFC_CT_CTX_MAX];
|
||||||
uint32_t ctx_idx;
|
uint32_t ctx_idx;
|
||||||
|
|
||||||
uint8_t menlo_flag; /* menlo generic flags */
|
uint8_t menlo_flag; /* menlo generic flags */
|
||||||
|
|
|
@ -955,9 +955,9 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||||
spin_lock_irqsave(&phba->ct_ev_lock, flags);
|
spin_lock_irqsave(&phba->ct_ev_lock, flags);
|
||||||
if (phba->sli_rev == LPFC_SLI_REV4) {
|
if (phba->sli_rev == LPFC_SLI_REV4) {
|
||||||
evt_dat->immed_dat = phba->ctx_idx;
|
evt_dat->immed_dat = phba->ctx_idx;
|
||||||
phba->ctx_idx = (phba->ctx_idx + 1) % 64;
|
phba->ctx_idx = (phba->ctx_idx + 1) % LPFC_CT_CTX_MAX;
|
||||||
/* Provide warning for over-run of the ct_ctx array */
|
/* Provide warning for over-run of the ct_ctx array */
|
||||||
if (phba->ct_ctx[evt_dat->immed_dat].flags &
|
if (phba->ct_ctx[evt_dat->immed_dat].valid ==
|
||||||
UNSOL_VALID)
|
UNSOL_VALID)
|
||||||
lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
|
lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
|
||||||
"2717 CT context array entry "
|
"2717 CT context array entry "
|
||||||
|
@ -973,7 +973,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||||
piocbq->iocb.unsli3.rcvsli3.ox_id;
|
piocbq->iocb.unsli3.rcvsli3.ox_id;
|
||||||
phba->ct_ctx[evt_dat->immed_dat].SID =
|
phba->ct_ctx[evt_dat->immed_dat].SID =
|
||||||
piocbq->iocb.un.rcvels.remoteID;
|
piocbq->iocb.un.rcvels.remoteID;
|
||||||
phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID;
|
phba->ct_ctx[evt_dat->immed_dat].valid = UNSOL_VALID;
|
||||||
} else
|
} else
|
||||||
evt_dat->immed_dat = piocbq->iocb.ulpContext;
|
evt_dat->immed_dat = piocbq->iocb.ulpContext;
|
||||||
|
|
||||||
|
@ -1012,6 +1012,47 @@ error_ct_unsol_exit:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lpfc_bsg_ct_unsol_abort - handler ct abort to management plane
|
||||||
|
* @phba: Pointer to HBA context object.
|
||||||
|
* @dmabuf: pointer to a dmabuf that describes the FC sequence
|
||||||
|
*
|
||||||
|
* This function handles abort to the CT command toward management plane
|
||||||
|
* for SLI4 port.
|
||||||
|
*
|
||||||
|
* If the pending context of a CT command to management plane present, clears
|
||||||
|
* such context and returns 1 for handled; otherwise, it returns 0 indicating
|
||||||
|
* no context exists.
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
lpfc_bsg_ct_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf)
|
||||||
|
{
|
||||||
|
struct fc_frame_header fc_hdr;
|
||||||
|
struct fc_frame_header *fc_hdr_ptr = &fc_hdr;
|
||||||
|
int ctx_idx, handled = 0;
|
||||||
|
uint16_t oxid, rxid;
|
||||||
|
uint32_t sid;
|
||||||
|
|
||||||
|
memcpy(fc_hdr_ptr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header));
|
||||||
|
sid = sli4_sid_from_fc_hdr(fc_hdr_ptr);
|
||||||
|
oxid = be16_to_cpu(fc_hdr_ptr->fh_ox_id);
|
||||||
|
rxid = be16_to_cpu(fc_hdr_ptr->fh_rx_id);
|
||||||
|
|
||||||
|
for (ctx_idx = 0; ctx_idx < LPFC_CT_CTX_MAX; ctx_idx++) {
|
||||||
|
if (phba->ct_ctx[ctx_idx].valid != UNSOL_VALID)
|
||||||
|
continue;
|
||||||
|
if (phba->ct_ctx[ctx_idx].rxid != rxid)
|
||||||
|
continue;
|
||||||
|
if (phba->ct_ctx[ctx_idx].oxid != oxid)
|
||||||
|
continue;
|
||||||
|
if (phba->ct_ctx[ctx_idx].SID != sid)
|
||||||
|
continue;
|
||||||
|
phba->ct_ctx[ctx_idx].valid = UNSOL_INVALID;
|
||||||
|
handled = 1;
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command
|
* lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command
|
||||||
* @job: SET_EVENT fc_bsg_job
|
* @job: SET_EVENT fc_bsg_job
|
||||||
|
@ -1318,7 +1359,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
|
||||||
icmd->ulpClass = CLASS3;
|
icmd->ulpClass = CLASS3;
|
||||||
if (phba->sli_rev == LPFC_SLI_REV4) {
|
if (phba->sli_rev == LPFC_SLI_REV4) {
|
||||||
/* Do not issue unsol response if oxid not marked as valid */
|
/* Do not issue unsol response if oxid not marked as valid */
|
||||||
if (!(phba->ct_ctx[tag].flags & UNSOL_VALID)) {
|
if (phba->ct_ctx[tag].valid != UNSOL_VALID) {
|
||||||
rc = IOCB_ERROR;
|
rc = IOCB_ERROR;
|
||||||
goto issue_ct_rsp_exit;
|
goto issue_ct_rsp_exit;
|
||||||
}
|
}
|
||||||
|
@ -1352,7 +1393,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
|
||||||
phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
|
phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
|
||||||
|
|
||||||
/* The exchange is done, mark the entry as invalid */
|
/* The exchange is done, mark the entry as invalid */
|
||||||
phba->ct_ctx[tag].flags &= ~UNSOL_VALID;
|
phba->ct_ctx[tag].valid = UNSOL_INVALID;
|
||||||
} else
|
} else
|
||||||
icmd->ulpContext = (ushort) tag;
|
icmd->ulpContext = (ushort) tag;
|
||||||
|
|
||||||
|
|
|
@ -164,8 +164,7 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *);
|
||||||
|
|
||||||
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
|
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
|
||||||
struct lpfc_iocbq *);
|
struct lpfc_iocbq *);
|
||||||
void lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
|
int lpfc_ct_handle_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *);
|
||||||
struct lpfc_iocbq *);
|
|
||||||
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
|
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
|
||||||
int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
|
int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
|
||||||
void lpfc_fdmi_tmo(unsigned long);
|
void lpfc_fdmi_tmo(unsigned long);
|
||||||
|
@ -427,6 +426,7 @@ int lpfc_bsg_request(struct fc_bsg_job *);
|
||||||
int lpfc_bsg_timeout(struct fc_bsg_job *);
|
int lpfc_bsg_timeout(struct fc_bsg_job *);
|
||||||
int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
|
int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
|
||||||
struct lpfc_iocbq *);
|
struct lpfc_iocbq *);
|
||||||
|
int lpfc_bsg_ct_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *);
|
||||||
void __lpfc_sli_ringtx_put(struct lpfc_hba *, struct lpfc_sli_ring *,
|
void __lpfc_sli_ringtx_put(struct lpfc_hba *, struct lpfc_sli_ring *,
|
||||||
struct lpfc_iocbq *);
|
struct lpfc_iocbq *);
|
||||||
struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *,
|
struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *,
|
||||||
|
|
|
@ -164,37 +164,24 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lpfc_sli4_ct_abort_unsol_event - Default handle for sli4 unsol abort
|
* lpfc_ct_handle_unsol_abort - ct upper level protocol abort handler
|
||||||
* @phba: Pointer to HBA context object.
|
* @phba: Pointer to HBA context object.
|
||||||
* @pring: Pointer to the driver internal I/O ring.
|
* @dmabuf: pointer to a dmabuf that describes the FC sequence
|
||||||
* @piocbq: Pointer to the IOCBQ.
|
|
||||||
*
|
*
|
||||||
* This function serves as the default handler for the sli4 unsolicited
|
* This function serves as the upper level protocol abort handler for CT
|
||||||
* abort event. It shall be invoked when there is no application interface
|
* protocol.
|
||||||
* registered unsolicited abort handler. This handler does nothing but
|
*
|
||||||
* just simply releases the dma buffer used by the unsol abort event.
|
* Return 1 if abort has been handled, 0 otherwise.
|
||||||
**/
|
**/
|
||||||
void
|
int
|
||||||
lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba,
|
lpfc_ct_handle_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf)
|
||||||
struct lpfc_sli_ring *pring,
|
|
||||||
struct lpfc_iocbq *piocbq)
|
|
||||||
{
|
{
|
||||||
IOCB_t *icmd = &piocbq->iocb;
|
int handled;
|
||||||
struct lpfc_dmabuf *bdeBuf;
|
|
||||||
uint32_t size;
|
|
||||||
|
|
||||||
/* Forward abort event to any process registered to receive ct event */
|
/* CT upper level goes through BSG */
|
||||||
if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0)
|
handled = lpfc_bsg_ct_unsol_abort(phba, dmabuf);
|
||||||
return;
|
|
||||||
|
|
||||||
/* If there is no BDE associated with IOCB, there is nothing to do */
|
return handled;
|
||||||
if (icmd->ulpBdeCount == 0)
|
|
||||||
return;
|
|
||||||
bdeBuf = piocbq->context2;
|
|
||||||
piocbq->context2 = NULL;
|
|
||||||
size = icmd->un.cont64[0].tus.f.bdeSize;
|
|
||||||
lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
|
|
||||||
lpfc_in_buf_free(phba, bdeBuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -8855,12 +8855,6 @@ lpfc_sli_setup(struct lpfc_hba *phba)
|
||||||
pring->prt[3].type = FC_TYPE_CT;
|
pring->prt[3].type = FC_TYPE_CT;
|
||||||
pring->prt[3].lpfc_sli_rcv_unsol_event =
|
pring->prt[3].lpfc_sli_rcv_unsol_event =
|
||||||
lpfc_ct_unsol_event;
|
lpfc_ct_unsol_event;
|
||||||
/* abort unsolicited sequence */
|
|
||||||
pring->prt[4].profile = 0; /* Mask 4 */
|
|
||||||
pring->prt[4].rctl = FC_RCTL_BA_ABTS;
|
|
||||||
pring->prt[4].type = FC_TYPE_BLS;
|
|
||||||
pring->prt[4].lpfc_sli_rcv_unsol_event =
|
|
||||||
lpfc_sli4_ct_abort_unsol_event;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
totiocbsize += (pring->sli.sli3.numCiocb *
|
totiocbsize += (pring->sli.sli3.numCiocb *
|
||||||
|
@ -14062,6 +14056,40 @@ lpfc_sli4_abort_partial_seq(struct lpfc_vport *vport,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lpfc_sli4_abort_ulp_seq - Abort assembled unsol sequence from ulp
|
||||||
|
* @vport: pointer to a vitural port
|
||||||
|
* @dmabuf: pointer to a dmabuf that describes the FC sequence
|
||||||
|
*
|
||||||
|
* This function tries to abort from the assembed sequence from upper level
|
||||||
|
* protocol, described by the information from basic abbort @dmabuf. It
|
||||||
|
* checks to see whether such pending context exists at upper level protocol.
|
||||||
|
* If so, it shall clean up the pending context.
|
||||||
|
*
|
||||||
|
* Return
|
||||||
|
* true -- if there is matching pending context of the sequence cleaned
|
||||||
|
* at ulp;
|
||||||
|
* false -- if there is no matching pending context of the sequence present
|
||||||
|
* at ulp.
|
||||||
|
**/
|
||||||
|
static bool
|
||||||
|
lpfc_sli4_abort_ulp_seq(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
|
||||||
|
{
|
||||||
|
struct lpfc_hba *phba = vport->phba;
|
||||||
|
int handled;
|
||||||
|
|
||||||
|
/* Accepting abort at ulp with SLI4 only */
|
||||||
|
if (phba->sli_rev < LPFC_SLI_REV4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Register all caring upper level protocols to attend abort */
|
||||||
|
handled = lpfc_ct_handle_unsol_abort(phba, dmabuf);
|
||||||
|
if (handled)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lpfc_sli4_seq_abort_rsp_cmpl - BLS ABORT RSP seq abort iocb complete handler
|
* lpfc_sli4_seq_abort_rsp_cmpl - BLS ABORT RSP seq abort iocb complete handler
|
||||||
* @phba: Pointer to HBA context object.
|
* @phba: Pointer to HBA context object.
|
||||||
|
@ -14077,8 +14105,14 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba,
|
||||||
struct lpfc_iocbq *cmd_iocbq,
|
struct lpfc_iocbq *cmd_iocbq,
|
||||||
struct lpfc_iocbq *rsp_iocbq)
|
struct lpfc_iocbq *rsp_iocbq)
|
||||||
{
|
{
|
||||||
if (cmd_iocbq)
|
struct lpfc_nodelist *ndlp;
|
||||||
|
|
||||||
|
if (cmd_iocbq) {
|
||||||
|
ndlp = (struct lpfc_nodelist *)cmd_iocbq->context1;
|
||||||
|
lpfc_nlp_put(ndlp);
|
||||||
|
lpfc_nlp_not_used(ndlp);
|
||||||
lpfc_sli_release_iocbq(phba, cmd_iocbq);
|
lpfc_sli_release_iocbq(phba, cmd_iocbq);
|
||||||
|
}
|
||||||
|
|
||||||
/* Failure means BLS ABORT RSP did not get delivered to remote node*/
|
/* Failure means BLS ABORT RSP did not get delivered to remote node*/
|
||||||
if (rsp_iocbq && rsp_iocbq->iocb.ulpStatus)
|
if (rsp_iocbq && rsp_iocbq->iocb.ulpStatus)
|
||||||
|
@ -14118,9 +14152,10 @@ lpfc_sli4_xri_inrange(struct lpfc_hba *phba,
|
||||||
* event after aborting the sequence handling.
|
* event after aborting the sequence handling.
|
||||||
**/
|
**/
|
||||||
static void
|
static void
|
||||||
lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
|
lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport,
|
||||||
struct fc_frame_header *fc_hdr)
|
struct fc_frame_header *fc_hdr, bool aborted)
|
||||||
{
|
{
|
||||||
|
struct lpfc_hba *phba = vport->phba;
|
||||||
struct lpfc_iocbq *ctiocb = NULL;
|
struct lpfc_iocbq *ctiocb = NULL;
|
||||||
struct lpfc_nodelist *ndlp;
|
struct lpfc_nodelist *ndlp;
|
||||||
uint16_t oxid, rxid, xri, lxri;
|
uint16_t oxid, rxid, xri, lxri;
|
||||||
|
@ -14135,12 +14170,27 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
|
||||||
oxid = be16_to_cpu(fc_hdr->fh_ox_id);
|
oxid = be16_to_cpu(fc_hdr->fh_ox_id);
|
||||||
rxid = be16_to_cpu(fc_hdr->fh_rx_id);
|
rxid = be16_to_cpu(fc_hdr->fh_rx_id);
|
||||||
|
|
||||||
ndlp = lpfc_findnode_did(phba->pport, sid);
|
ndlp = lpfc_findnode_did(vport, sid);
|
||||||
if (!ndlp) {
|
if (!ndlp) {
|
||||||
lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
|
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
|
||||||
"1268 Find ndlp returned NULL for oxid:x%x "
|
if (!ndlp) {
|
||||||
"SID:x%x\n", oxid, sid);
|
lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS,
|
||||||
return;
|
"1268 Failed to allocate ndlp for "
|
||||||
|
"oxid:x%x SID:x%x\n", oxid, sid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lpfc_nlp_init(vport, ndlp, sid);
|
||||||
|
/* 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 */
|
/* Allocate buffer for rsp iocb */
|
||||||
|
@ -14164,7 +14214,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
|
||||||
icmd->ulpLe = 1;
|
icmd->ulpLe = 1;
|
||||||
icmd->ulpClass = CLASS3;
|
icmd->ulpClass = CLASS3;
|
||||||
icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
|
icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
|
||||||
ctiocb->context1 = ndlp;
|
ctiocb->context1 = lpfc_nlp_get(ndlp);
|
||||||
|
|
||||||
ctiocb->iocb_cmpl = NULL;
|
ctiocb->iocb_cmpl = NULL;
|
||||||
ctiocb->vport = phba->pport;
|
ctiocb->vport = phba->pport;
|
||||||
|
@ -14183,14 +14233,24 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
|
||||||
if (lxri != NO_XRI)
|
if (lxri != NO_XRI)
|
||||||
lpfc_set_rrq_active(phba, ndlp, lxri,
|
lpfc_set_rrq_active(phba, ndlp, lxri,
|
||||||
(xri == oxid) ? rxid : oxid, 0);
|
(xri == oxid) ? rxid : oxid, 0);
|
||||||
/* If the oxid maps to the FCP XRI range or if it is out of range,
|
/* For BA_ABTS from exchange responder, if the logical xri with
|
||||||
* send a BLS_RJT. The driver no longer has that exchange.
|
* the oxid maps to the FCP XRI range, the port no longer has
|
||||||
* Override the IOCB for a BA_RJT.
|
* that exchange context, send a BLS_RJT. Override the IOCB for
|
||||||
|
* a BA_RJT.
|
||||||
*/
|
*/
|
||||||
if (xri > (phba->sli4_hba.max_cfg_param.max_xri +
|
if ((fctl & FC_FC_EX_CTX) &&
|
||||||
phba->sli4_hba.max_cfg_param.xri_base) ||
|
(lxri > lpfc_sli4_get_els_iocb_cnt(phba))) {
|
||||||
xri > (lpfc_sli4_get_els_iocb_cnt(phba) +
|
icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT;
|
||||||
phba->sli4_hba.max_cfg_param.xri_base)) {
|
bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0);
|
||||||
|
bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID);
|
||||||
|
bf_set(lpfc_rsn_code, &icmd->un.bls_rsp, FC_BA_RJT_UNABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If BA_ABTS failed to abort a partially assembled receive sequence,
|
||||||
|
* the driver no longer has that exchange, send a BLS_RJT. Override
|
||||||
|
* the IOCB for a BA_RJT.
|
||||||
|
*/
|
||||||
|
if (aborted == false) {
|
||||||
icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT;
|
icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT;
|
||||||
bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0);
|
bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0);
|
||||||
bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID);
|
bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID);
|
||||||
|
@ -14214,17 +14274,19 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba,
|
||||||
bf_set(lpfc_abts_oxid, &icmd->un.bls_rsp, oxid);
|
bf_set(lpfc_abts_oxid, &icmd->un.bls_rsp, oxid);
|
||||||
|
|
||||||
/* Xmit CT abts response on exchange <xid> */
|
/* Xmit CT abts response on exchange <xid> */
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
||||||
"1200 Send BLS cmd x%x on oxid x%x Data: x%x\n",
|
"1200 Send BLS cmd x%x on oxid x%x Data: x%x\n",
|
||||||
icmd->un.xseq64.w5.hcsw.Rctl, oxid, phba->link_state);
|
icmd->un.xseq64.w5.hcsw.Rctl, oxid, phba->link_state);
|
||||||
|
|
||||||
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0);
|
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0);
|
||||||
if (rc == IOCB_ERROR) {
|
if (rc == IOCB_ERROR) {
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
|
||||||
"2925 Failed to issue CT ABTS RSP x%x on "
|
"2925 Failed to issue CT ABTS RSP x%x on "
|
||||||
"xri x%x, Data x%x\n",
|
"xri x%x, Data x%x\n",
|
||||||
icmd->un.xseq64.w5.hcsw.Rctl, oxid,
|
icmd->un.xseq64.w5.hcsw.Rctl, oxid,
|
||||||
phba->link_state);
|
phba->link_state);
|
||||||
|
lpfc_nlp_put(ndlp);
|
||||||
|
ctiocb->context1 = NULL;
|
||||||
lpfc_sli_release_iocbq(phba, ctiocb);
|
lpfc_sli_release_iocbq(phba, ctiocb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14249,32 +14311,25 @@ lpfc_sli4_handle_unsol_abort(struct lpfc_vport *vport,
|
||||||
struct lpfc_hba *phba = vport->phba;
|
struct lpfc_hba *phba = vport->phba;
|
||||||
struct fc_frame_header fc_hdr;
|
struct fc_frame_header fc_hdr;
|
||||||
uint32_t fctl;
|
uint32_t fctl;
|
||||||
bool abts_par;
|
bool aborted;
|
||||||
|
|
||||||
/* Make a copy of fc_hdr before the dmabuf being released */
|
/* Make a copy of fc_hdr before the dmabuf being released */
|
||||||
memcpy(&fc_hdr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header));
|
memcpy(&fc_hdr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header));
|
||||||
fctl = sli4_fctl_from_fc_hdr(&fc_hdr);
|
fctl = sli4_fctl_from_fc_hdr(&fc_hdr);
|
||||||
|
|
||||||
if (fctl & FC_FC_EX_CTX) {
|
if (fctl & FC_FC_EX_CTX) {
|
||||||
/*
|
/* ABTS by responder to exchange, no cleanup needed */
|
||||||
* ABTS sent by responder to exchange, just free the buffer
|
aborted = true;
|
||||||
*/
|
|
||||||
lpfc_in_buf_free(phba, &dmabuf->dbuf);
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/* ABTS by initiator to exchange, need to do cleanup */
|
||||||
* ABTS sent by initiator to exchange, need to do cleanup
|
aborted = lpfc_sli4_abort_partial_seq(vport, dmabuf);
|
||||||
*/
|
if (aborted == false)
|
||||||
/* Try to abort partially assembled seq */
|
aborted = lpfc_sli4_abort_ulp_seq(vport, dmabuf);
|
||||||
abts_par = lpfc_sli4_abort_partial_seq(vport, dmabuf);
|
|
||||||
|
|
||||||
/* Send abort to ULP if partially seq abort failed */
|
|
||||||
if (abts_par == false)
|
|
||||||
lpfc_sli4_send_seq_to_ulp(vport, dmabuf);
|
|
||||||
else
|
|
||||||
lpfc_in_buf_free(phba, &dmabuf->dbuf);
|
|
||||||
}
|
}
|
||||||
/* Send basic accept (BA_ACC) to the abort requester */
|
lpfc_in_buf_free(phba, &dmabuf->dbuf);
|
||||||
lpfc_sli4_seq_abort_rsp(phba, &fc_hdr);
|
|
||||||
|
/* Respond with BA_ACC or BA_RJT accordingly */
|
||||||
|
lpfc_sli4_seq_abort_rsp(vport, &fc_hdr, aborted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue