Skip to content

Commit ae9e28f

Browse files
jsmart-ghmartinkpetersen
authored andcommitted
scsi: lpfc: Add MDS Diagnostic support.
Added code to support Cisco MDS loopback diagnostic. The diagnostics run various loopbacks including one which loops-back frame through the driver. Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com> Signed-off-by: James Smart <james.smart@broadcom.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent dc53a61 commit ae9e28f

File tree

6 files changed

+161
-10
lines changed

6 files changed

+161
-10
lines changed

drivers/scsi/lpfc/lpfc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,8 @@ struct lpfc_hba {
675675
/* INIT_LINK mailbox command */
676676
#define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */
677677
#define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */
678+
#define LS_MDS_LINK_DOWN 0x8 /* MDS Diagnostics Link Down */
679+
#define LS_MDS_LOOPBACK 0x16 /* MDS Diagnostics Link Up (Loopback) */
678680

679681
uint32_t hba_flag; /* hba generic flags */
680682
#define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */

drivers/scsi/lpfc/lpfc_els.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,13 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
10471047
irsp->ulpStatus, irsp->un.ulpWord[4],
10481048
irsp->ulpTimeout);
10491049

1050+
1051+
/* If this is not a loop open failure, bail out */
1052+
if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT &&
1053+
((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) ==
1054+
IOERR_LOOP_OPEN_FAILURE)))
1055+
goto flogifail;
1056+
10501057
/* FLOGI failed, so there is no fabric */
10511058
spin_lock_irq(shost->host_lock);
10521059
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);

drivers/scsi/lpfc/lpfc_hbadisc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,8 @@ lpfc_work_done(struct lpfc_hba *phba)
701701
/* Set the lpfc data pending flag */
702702
set_bit(LPFC_DATA_READY, &phba->data_flags);
703703
} else {
704-
if (phba->link_state >= LPFC_LINK_UP) {
704+
if (phba->link_state >= LPFC_LINK_UP ||
705+
phba->link_flag & LS_MDS_LOOPBACK) {
705706
pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
706707
lpfc_sli_handle_slow_ring_event(phba, pring,
707708
(status &

drivers/scsi/lpfc/lpfc_hw4.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4421,6 +4421,19 @@ struct fcp_treceive64_wqe {
44214421
};
44224422
#define TXRDY_PAYLOAD_LEN 12
44234423

4424+
#define CMD_SEND_FRAME 0xE1
4425+
4426+
struct send_frame_wqe {
4427+
struct ulp_bde64 bde; /* words 0-2 */
4428+
uint32_t frame_len; /* word 3 */
4429+
uint32_t fc_hdr_wd0; /* word 4 */
4430+
uint32_t fc_hdr_wd1; /* word 5 */
4431+
struct wqe_common wqe_com; /* words 6-11 */
4432+
uint32_t fc_hdr_wd2; /* word 12 */
4433+
uint32_t fc_hdr_wd3; /* word 13 */
4434+
uint32_t fc_hdr_wd4; /* word 14 */
4435+
uint32_t fc_hdr_wd5; /* word 15 */
4436+
};
44244437

44254438
union lpfc_wqe {
44264439
uint32_t words[16];
@@ -4439,7 +4452,7 @@ union lpfc_wqe {
44394452
struct fcp_trsp64_wqe fcp_trsp;
44404453
struct fcp_tsend64_wqe fcp_tsend;
44414454
struct fcp_treceive64_wqe fcp_treceive;
4442-
4455+
struct send_frame_wqe send_frame;
44434456
};
44444457

44454458
union lpfc_wqe128 {

drivers/scsi/lpfc/lpfc_init.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4540,6 +4540,19 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
45404540
pmb->vport = phba->pport;
45414541

45424542
if (phba->sli4_hba.link_state.status != LPFC_FC_LA_TYPE_LINK_UP) {
4543+
phba->link_flag &= ~(LS_MDS_LINK_DOWN | LS_MDS_LOOPBACK);
4544+
4545+
switch (phba->sli4_hba.link_state.status) {
4546+
case LPFC_FC_LA_TYPE_MDS_LINK_DOWN:
4547+
phba->link_flag |= LS_MDS_LINK_DOWN;
4548+
break;
4549+
case LPFC_FC_LA_TYPE_MDS_LOOPBACK:
4550+
phba->link_flag |= LS_MDS_LOOPBACK;
4551+
break;
4552+
default:
4553+
break;
4554+
}
4555+
45434556
/* Parse and translate status field */
45444557
mb = &pmb->u.mb;
45454558
mb->mbxStatus = lpfc_sli4_parse_latt_fault(phba,

drivers/scsi/lpfc/lpfc_sli.c

Lines changed: 123 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ static struct lpfc_iocbq *lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *,
7474
struct lpfc_iocbq *);
7575
static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *,
7676
struct hbq_dmabuf *);
77+
static void lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport,
78+
struct hbq_dmabuf *dmabuf);
7779
static int lpfc_sli4_fp_handle_cqe(struct lpfc_hba *, struct lpfc_queue *,
7880
struct lpfc_cqe *);
7981
static int lpfc_sli4_post_sgl_list(struct lpfc_hba *, struct list_head *,
@@ -5907,7 +5909,7 @@ lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox,
59075909
bf_set(lpfc_mbx_set_feature_mds,
59085910
&mbox->u.mqe.un.set_feature, 1);
59095911
bf_set(lpfc_mbx_set_feature_mds_deep_loopbk,
5910-
&mbox->u.mqe.un.set_feature, 0);
5912+
&mbox->u.mqe.un.set_feature, 1);
59115913
mbox->u.mqe.un.set_feature.feature = LPFC_SET_MDS_DIAGS;
59125914
mbox->u.mqe.un.set_feature.param_len = 8;
59135915
break;
@@ -8688,8 +8690,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
86888690
memset(wqe, 0, sizeof(union lpfc_wqe128));
86898691
/* Some of the fields are in the right position already */
86908692
memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe));
8691-
wqe->generic.wqe_com.word7 = 0; /* The ct field has moved so reset */
8692-
wqe->generic.wqe_com.word10 = 0;
8693+
if (iocbq->iocb.ulpCommand != CMD_SEND_FRAME) {
8694+
/* The ct field has moved so reset */
8695+
wqe->generic.wqe_com.word7 = 0;
8696+
wqe->generic.wqe_com.word10 = 0;
8697+
}
86938698

86948699
abort_tag = (uint32_t) iocbq->iotag;
86958700
xritag = iocbq->sli4_xritag;
@@ -9183,6 +9188,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
91839188
}
91849189

91859190
break;
9191+
case CMD_SEND_FRAME:
9192+
bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag);
9193+
bf_set(wqe_reqtag, &wqe->generic.wqe_com, iocbq->iotag);
9194+
return 0;
91869195
case CMD_XRI_ABORTED_CX:
91879196
case CMD_CREATE_XRI_CR: /* Do we expect to use this? */
91889197
case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */
@@ -16137,6 +16146,8 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
1613716146
struct fc_vft_header *fc_vft_hdr;
1613816147
uint32_t *header = (uint32_t *) fc_hdr;
1613916148

16149+
#define FC_RCTL_MDS_DIAGS 0xF4
16150+
1614016151
switch (fc_hdr->fh_r_ctl) {
1614116152
case FC_RCTL_DD_UNCAT: /* uncategorized information */
1614216153
case FC_RCTL_DD_SOL_DATA: /* solicited data */
@@ -16164,6 +16175,7 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
1616416175
case FC_RCTL_F_BSY: /* fabric busy to data frame */
1616516176
case FC_RCTL_F_BSYL: /* fabric busy to link control frame */
1616616177
case FC_RCTL_LCR: /* link credit reset */
16178+
case FC_RCTL_MDS_DIAGS: /* MDS Diagnostics */
1616716179
case FC_RCTL_END: /* end */
1616816180
break;
1616916181
case FC_RCTL_VFTH: /* Virtual Fabric tagging Header */
@@ -16173,12 +16185,16 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
1617316185
default:
1617416186
goto drop;
1617516187
}
16188+
16189+
#define FC_TYPE_VENDOR_UNIQUE 0xFF
16190+
1617616191
switch (fc_hdr->fh_type) {
1617716192
case FC_TYPE_BLS:
1617816193
case FC_TYPE_ELS:
1617916194
case FC_TYPE_FCP:
1618016195
case FC_TYPE_CT:
1618116196
case FC_TYPE_NVME:
16197+
case FC_TYPE_VENDOR_UNIQUE:
1618216198
break;
1618316199
case FC_TYPE_IP:
1618416200
case FC_TYPE_ILS:
@@ -16189,12 +16205,14 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
1618916205
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1619016206
"2538 Received frame rctl:%s (x%x), type:%s (x%x), "
1619116207
"frame Data:%08x %08x %08x %08x %08x %08x %08x\n",
16208+
(fc_hdr->fh_r_ctl == FC_RCTL_MDS_DIAGS) ? "MDS Diags" :
1619216209
lpfc_rctl_names[fc_hdr->fh_r_ctl], fc_hdr->fh_r_ctl,
16193-
lpfc_type_names[fc_hdr->fh_type], fc_hdr->fh_type,
16194-
be32_to_cpu(header[0]), be32_to_cpu(header[1]),
16195-
be32_to_cpu(header[2]), be32_to_cpu(header[3]),
16196-
be32_to_cpu(header[4]), be32_to_cpu(header[5]),
16197-
be32_to_cpu(header[6]));
16210+
(fc_hdr->fh_type == FC_TYPE_VENDOR_UNIQUE) ?
16211+
"Vendor Unique" : lpfc_type_names[fc_hdr->fh_type],
16212+
fc_hdr->fh_type, be32_to_cpu(header[0]),
16213+
be32_to_cpu(header[1]), be32_to_cpu(header[2]),
16214+
be32_to_cpu(header[3]), be32_to_cpu(header[4]),
16215+
be32_to_cpu(header[5]), be32_to_cpu(header[6]));
1619816216
return 0;
1619916217
drop:
1620016218
lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
@@ -17000,6 +17018,96 @@ lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport,
1700017018
lpfc_sli_release_iocbq(phba, iocbq);
1700117019
}
1700217020

17021+
static void
17022+
lpfc_sli4_mds_loopback_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
17023+
struct lpfc_iocbq *rspiocb)
17024+
{
17025+
struct lpfc_dmabuf *pcmd = cmdiocb->context2;
17026+
17027+
if (pcmd && pcmd->virt)
17028+
pci_pool_free(phba->lpfc_drb_pool, pcmd->virt, pcmd->phys);
17029+
kfree(pcmd);
17030+
lpfc_sli_release_iocbq(phba, cmdiocb);
17031+
}
17032+
17033+
static void
17034+
lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport,
17035+
struct hbq_dmabuf *dmabuf)
17036+
{
17037+
struct fc_frame_header *fc_hdr;
17038+
struct lpfc_hba *phba = vport->phba;
17039+
struct lpfc_iocbq *iocbq = NULL;
17040+
union lpfc_wqe *wqe;
17041+
struct lpfc_dmabuf *pcmd = NULL;
17042+
uint32_t frame_len;
17043+
int rc;
17044+
17045+
fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
17046+
frame_len = bf_get(lpfc_rcqe_length, &dmabuf->cq_event.cqe.rcqe_cmpl);
17047+
17048+
/* Send the received frame back */
17049+
iocbq = lpfc_sli_get_iocbq(phba);
17050+
if (!iocbq)
17051+
goto exit;
17052+
17053+
/* Allocate buffer for command payload */
17054+
pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
17055+
if (pcmd)
17056+
pcmd->virt = pci_pool_alloc(phba->lpfc_drb_pool, GFP_KERNEL,
17057+
&pcmd->phys);
17058+
if (!pcmd || !pcmd->virt)
17059+
goto exit;
17060+
17061+
INIT_LIST_HEAD(&pcmd->list);
17062+
17063+
/* copyin the payload */
17064+
memcpy(pcmd->virt, dmabuf->dbuf.virt, frame_len);
17065+
17066+
/* fill in BDE's for command */
17067+
iocbq->iocb.un.xseq64.bdl.addrHigh = putPaddrHigh(pcmd->phys);
17068+
iocbq->iocb.un.xseq64.bdl.addrLow = putPaddrLow(pcmd->phys);
17069+
iocbq->iocb.un.xseq64.bdl.bdeFlags = BUFF_TYPE_BDE_64;
17070+
iocbq->iocb.un.xseq64.bdl.bdeSize = frame_len;
17071+
17072+
iocbq->context2 = pcmd;
17073+
iocbq->vport = vport;
17074+
iocbq->iocb_flag &= ~LPFC_FIP_ELS_ID_MASK;
17075+
iocbq->iocb_flag |= LPFC_USE_FCPWQIDX;
17076+
17077+
/*
17078+
* Setup rest of the iocb as though it were a WQE
17079+
* Build the SEND_FRAME WQE
17080+
*/
17081+
wqe = (union lpfc_wqe *)&iocbq->iocb;
17082+
17083+
wqe->send_frame.frame_len = frame_len;
17084+
wqe->send_frame.fc_hdr_wd0 = be32_to_cpu(*((uint32_t *)fc_hdr));
17085+
wqe->send_frame.fc_hdr_wd1 = be32_to_cpu(*((uint32_t *)fc_hdr + 1));
17086+
wqe->send_frame.fc_hdr_wd2 = be32_to_cpu(*((uint32_t *)fc_hdr + 2));
17087+
wqe->send_frame.fc_hdr_wd3 = be32_to_cpu(*((uint32_t *)fc_hdr + 3));
17088+
wqe->send_frame.fc_hdr_wd4 = be32_to_cpu(*((uint32_t *)fc_hdr + 4));
17089+
wqe->send_frame.fc_hdr_wd5 = be32_to_cpu(*((uint32_t *)fc_hdr + 5));
17090+
17091+
iocbq->iocb.ulpCommand = CMD_SEND_FRAME;
17092+
iocbq->iocb.ulpLe = 1;
17093+
iocbq->iocb_cmpl = lpfc_sli4_mds_loopback_cmpl;
17094+
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocbq, 0);
17095+
if (rc == IOCB_ERROR)
17096+
goto exit;
17097+
17098+
lpfc_in_buf_free(phba, &dmabuf->dbuf);
17099+
return;
17100+
17101+
exit:
17102+
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
17103+
"2023 Unable to process MDS loopback frame\n");
17104+
if (pcmd && pcmd->virt)
17105+
pci_pool_free(phba->lpfc_drb_pool, pcmd->virt, pcmd->phys);
17106+
kfree(pcmd);
17107+
lpfc_sli_release_iocbq(phba, iocbq);
17108+
lpfc_in_buf_free(phba, &dmabuf->dbuf);
17109+
}
17110+
1700317111
/**
1700417112
* lpfc_sli4_handle_received_buffer - Handle received buffers from firmware
1700517113
* @phba: Pointer to HBA context object.
@@ -17038,6 +17146,13 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
1703817146
fcfi = bf_get(lpfc_rcqe_fcf_id,
1703917147
&dmabuf->cq_event.cqe.rcqe_cmpl);
1704017148

17149+
if (fc_hdr->fh_r_ctl == 0xF4 && fc_hdr->fh_type == 0xFF) {
17150+
vport = phba->pport;
17151+
/* Handle MDS Loopback frames */
17152+
lpfc_sli4_handle_mds_loopback(vport, dmabuf);
17153+
return;
17154+
}
17155+
1704117156
/* d_id this frame is directed to */
1704217157
did = sli4_did_from_fc_hdr(fc_hdr);
1704317158

0 commit comments

Comments
 (0)