Skip to content

Commit

Permalink
[SCSI] lpfc 8.3.37: Fixed no-context ABTS failed with BA_RJT
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
James Smart authored and James Bottomley committed Jan 30, 2013
1 parent 7b15db3 commit 6dd9e31
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 83 deletions.
8 changes: 5 additions & 3 deletions drivers/scsi/lpfc/lpfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,11 +466,13 @@ enum intr_type_t {
MSIX,
};

#define LPFC_CT_CTX_MAX 64
struct unsol_rcv_ct_ctx {
uint32_t ctxt_id;
uint32_t SID;
uint32_t flags;
#define UNSOL_VALID 0x00000001
uint32_t valid;
#define UNSOL_INVALID 0
#define UNSOL_VALID 1
uint16_t oxid;
uint16_t rxid;
};
Expand Down Expand Up @@ -938,7 +940,7 @@ struct lpfc_hba {

spinlock_t ct_ev_lock; /* synchronize access to 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;

uint8_t menlo_flag; /* menlo generic flags */
Expand Down
51 changes: 46 additions & 5 deletions drivers/scsi/lpfc/lpfc_bsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
if (phba->sli_rev == LPFC_SLI_REV4) {
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 */
if (phba->ct_ctx[evt_dat->immed_dat].flags &
if (phba->ct_ctx[evt_dat->immed_dat].valid ==
UNSOL_VALID)
lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
"2717 CT context array entry "
Expand All @@ -973,7 +973,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
piocbq->iocb.unsli3.rcvsli3.ox_id;
phba->ct_ctx[evt_dat->immed_dat].SID =
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
evt_dat->immed_dat = piocbq->iocb.ulpContext;

Expand Down Expand Up @@ -1012,6 +1012,47 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
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
* @job: SET_EVENT fc_bsg_job
Expand Down Expand Up @@ -1318,7 +1359,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
icmd->ulpClass = CLASS3;
if (phba->sli_rev == LPFC_SLI_REV4) {
/* 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;
goto issue_ct_rsp_exit;
}
Expand Down Expand Up @@ -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];

/* The exchange is done, mark the entry as invalid */
phba->ct_ctx[tag].flags &= ~UNSOL_VALID;
phba->ct_ctx[tag].valid = UNSOL_INVALID;
} else
icmd->ulpContext = (ushort) tag;

Expand Down
4 changes: 2 additions & 2 deletions drivers/scsi/lpfc/lpfc_crtn.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *);

void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
void lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
int lpfc_ct_handle_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *);
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
void lpfc_fdmi_tmo(unsigned long);
Expand Down Expand Up @@ -427,6 +426,7 @@ int lpfc_bsg_request(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 *,
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 *,
struct lpfc_iocbq *);
struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *,
Expand Down
37 changes: 12 additions & 25 deletions drivers/scsi/lpfc/lpfc_ct.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
* @pring: Pointer to the driver internal I/O ring.
* @piocbq: Pointer to the IOCBQ.
* @dmabuf: pointer to a dmabuf that describes the FC sequence
*
* This function serves as the default handler for the sli4 unsolicited
* abort event. It shall be invoked when there is no application interface
* registered unsolicited abort handler. This handler does nothing but
* just simply releases the dma buffer used by the unsol abort event.
* This function serves as the upper level protocol abort handler for CT
* protocol.
*
* Return 1 if abort has been handled, 0 otherwise.
**/
void
lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba,
struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocbq)
int
lpfc_ct_handle_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf)
{
IOCB_t *icmd = &piocbq->iocb;
struct lpfc_dmabuf *bdeBuf;
uint32_t size;
int handled;

/* Forward abort event to any process registered to receive ct event */
if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0)
return;
/* CT upper level goes through BSG */
handled = lpfc_bsg_ct_unsol_abort(phba, dmabuf);

/* If there is no BDE associated with IOCB, there is nothing to do */
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);
return handled;
}

static void
Expand Down
Loading

0 comments on commit 6dd9e31

Please sign in to comment.