Commit 9a66d990 authored by James Smart's avatar James Smart Committed by Martin K. Petersen

scsi: lpfc: Add loopback testing to trunking mode

When in trunking mode, the adapter can be placed into diagnostic mode and
each link in the trunk tested via loopback.

Add support to the driver to perform per-link loopback testing when in
trunking mode.
Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent f3339800
......@@ -1968,14 +1968,17 @@ lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag)
}
/**
* lpfc_sli4_bsg_set_internal_loopback - set sli4 internal loopback diagnostic
* lpfc_sli4_bsg_set_loopback_mode - set sli4 internal loopback diagnostic
* @phba: Pointer to HBA context object.
* @mode: loopback mode to set
* @link_no: link number for loopback mode to set
*
* This function is responsible for issuing a sli4 mailbox command for setting
* up internal loopback diagnostic.
* up loopback diagnostic for a link.
*/
static int
lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba)
lpfc_sli4_bsg_set_loopback_mode(struct lpfc_hba *phba, int mode,
uint32_t link_no)
{
LPFC_MBOXQ_t *pmboxq;
uint32_t req_len, alloc_len;
......@@ -1996,11 +1999,19 @@ lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba)
}
link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback;
bf_set(lpfc_mbx_set_diag_state_link_num,
&link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_no);
bf_set(lpfc_mbx_set_diag_state_link_type,
&link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp);
&link_diag_loopback->u.req, link_no);
if (phba->sli4_hba.conf_trunk & (1 << link_no)) {
bf_set(lpfc_mbx_set_diag_state_link_type,
&link_diag_loopback->u.req, LPFC_LNK_FC_TRUNKED);
} else {
bf_set(lpfc_mbx_set_diag_state_link_type,
&link_diag_loopback->u.req,
phba->sli4_hba.lnk_info.lnk_tp);
}
bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req,
LPFC_DIAG_LOOPBACK_TYPE_INTERNAL);
mode);
mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) {
......@@ -2054,7 +2065,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
struct fc_bsg_request *bsg_request = job->request;
struct fc_bsg_reply *bsg_reply = job->reply;
struct diag_mode_set *loopback_mode;
uint32_t link_flags, timeout;
uint32_t link_flags, timeout, link_no;
int i, rc = 0;
/* no data to return just the return code */
......@@ -2069,12 +2080,39 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
(int)(sizeof(struct fc_bsg_request) +
sizeof(struct diag_mode_set)));
rc = -EINVAL;
goto job_error;
goto job_done;
}
loopback_mode = (struct diag_mode_set *)
bsg_request->rqst_data.h_vendor.vendor_cmd;
link_flags = loopback_mode->type;
timeout = loopback_mode->timeout * 100;
if (loopback_mode->physical_link == -1)
link_no = phba->sli4_hba.lnk_info.lnk_no;
else
link_no = loopback_mode->physical_link;
if (link_flags == DISABLE_LOOP_BACK) {
rc = lpfc_sli4_bsg_set_loopback_mode(phba,
LPFC_DIAG_LOOPBACK_TYPE_DISABLE,
link_no);
if (!rc) {
/* Unset the need disable bit */
phba->sli4_hba.conf_trunk &= ~((1 << link_no) << 4);
}
goto job_done;
} else {
/* Check if we need to disable the loopback state */
if (phba->sli4_hba.conf_trunk & ((1 << link_no) << 4)) {
rc = -EPERM;
goto job_done;
}
}
rc = lpfc_bsg_diag_mode_enter(phba);
if (rc)
goto job_error;
goto job_done;
/* indicate we are in loobpack diagnostic mode */
spin_lock_irq(&phba->hbalock);
......@@ -2084,15 +2122,11 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
/* reset port to start frome scratch */
rc = lpfc_selective_reset(phba);
if (rc)
goto job_error;
goto job_done;
/* bring the link to diagnostic mode */
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"3129 Bring link to diagnostic state.\n");
loopback_mode = (struct diag_mode_set *)
bsg_request->rqst_data.h_vendor.vendor_cmd;
link_flags = loopback_mode->type;
timeout = loopback_mode->timeout * 100;
rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1);
if (rc) {
......@@ -2120,13 +2154,54 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"3132 Set up loopback mode:x%x\n", link_flags);
if (link_flags == INTERNAL_LOOP_BACK)
rc = lpfc_sli4_bsg_set_internal_loopback(phba);
else if (link_flags == EXTERNAL_LOOP_BACK)
rc = lpfc_hba_init_link_fc_topology(phba,
FLAGS_TOPOLOGY_MODE_PT_PT,
MBX_NOWAIT);
else {
switch (link_flags) {
case INTERNAL_LOOP_BACK:
if (phba->sli4_hba.conf_trunk & (1 << link_no)) {
rc = lpfc_sli4_bsg_set_loopback_mode(phba,
LPFC_DIAG_LOOPBACK_TYPE_INTERNAL,
link_no);
} else {
/* Trunk is configured, but link is not in this trunk */
if (phba->sli4_hba.conf_trunk) {
rc = -ELNRNG;
goto loopback_mode_exit;
}
rc = lpfc_sli4_bsg_set_loopback_mode(phba,
LPFC_DIAG_LOOPBACK_TYPE_INTERNAL,
link_no);
}
if (!rc) {
/* Set the need disable bit */
phba->sli4_hba.conf_trunk |= (1 << link_no) << 4;
}
break;
case EXTERNAL_LOOP_BACK:
if (phba->sli4_hba.conf_trunk & (1 << link_no)) {
rc = lpfc_sli4_bsg_set_loopback_mode(phba,
LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL_TRUNKED,
link_no);
} else {
/* Trunk is configured, but link is not in this trunk */
if (phba->sli4_hba.conf_trunk) {
rc = -ELNRNG;
goto loopback_mode_exit;
}
rc = lpfc_sli4_bsg_set_loopback_mode(phba,
LPFC_DIAG_LOOPBACK_TYPE_SERDES,
link_no);
}
if (!rc) {
/* Set the need disable bit */
phba->sli4_hba.conf_trunk |= (1 << link_no) << 4;
}
break;
default:
rc = -EINVAL;
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
"3141 Loopback mode:x%x not supported\n",
......@@ -2185,7 +2260,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
}
lpfc_bsg_diag_mode_exit(phba);
job_error:
job_done:
/* make error code available to userspace */
bsg_reply->result = rc;
/* complete the job back to userspace if no error */
......
......@@ -68,6 +68,7 @@ struct send_mgmt_resp {
};
#define DISABLE_LOOP_BACK 0x0 /* disables loop back */
#define INTERNAL_LOOP_BACK 0x1 /* adapter short cuts the loop internally */
#define EXTERNAL_LOOP_BACK 0x2 /* requires an external loopback plug */
......@@ -75,6 +76,7 @@ struct diag_mode_set {
uint32_t command;
uint32_t type;
uint32_t timeout;
uint32_t physical_link;
};
struct sli4_link_diag {
......
......@@ -1894,18 +1894,19 @@ struct lpfc_mbx_set_link_diag_loopback {
union {
struct {
uint32_t word0;
#define lpfc_mbx_set_diag_lpbk_type_SHIFT 0
#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000003
#define lpfc_mbx_set_diag_lpbk_type_WORD word0
#define LPFC_DIAG_LOOPBACK_TYPE_DISABLE 0x0
#define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL 0x1
#define LPFC_DIAG_LOOPBACK_TYPE_SERDES 0x2
#define lpfc_mbx_set_diag_lpbk_link_num_SHIFT 16
#define lpfc_mbx_set_diag_lpbk_link_num_MASK 0x0000003F
#define lpfc_mbx_set_diag_lpbk_link_num_WORD word0
#define lpfc_mbx_set_diag_lpbk_link_type_SHIFT 22
#define lpfc_mbx_set_diag_lpbk_link_type_MASK 0x00000003
#define lpfc_mbx_set_diag_lpbk_link_type_WORD word0
#define lpfc_mbx_set_diag_lpbk_type_SHIFT 0
#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000003
#define lpfc_mbx_set_diag_lpbk_type_WORD word0
#define LPFC_DIAG_LOOPBACK_TYPE_DISABLE 0x0
#define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL 0x1
#define LPFC_DIAG_LOOPBACK_TYPE_SERDES 0x2
#define LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL_TRUNKED 0x3
#define lpfc_mbx_set_diag_lpbk_link_num_SHIFT 16
#define lpfc_mbx_set_diag_lpbk_link_num_MASK 0x0000003F
#define lpfc_mbx_set_diag_lpbk_link_num_WORD word0
#define lpfc_mbx_set_diag_lpbk_link_type_SHIFT 22
#define lpfc_mbx_set_diag_lpbk_link_type_MASK 0x00000003
#define lpfc_mbx_set_diag_lpbk_link_type_WORD word0
} req;
struct {
uint32_t word0;
......
......@@ -543,8 +543,9 @@ struct lpfc_sli4_lnk_info {
#define LPFC_LNK_DAT_INVAL 0
#define LPFC_LNK_DAT_VAL 1
uint8_t lnk_tp;
#define LPFC_LNK_GE 0x0 /* FCoE */
#define LPFC_LNK_FC 0x1 /* FC */
#define LPFC_LNK_GE 0x0 /* FCoE */
#define LPFC_LNK_FC 0x1 /* FC */
#define LPFC_LNK_FC_TRUNKED 0x2 /* FC_Trunked */
uint8_t lnk_no;
uint8_t optic_state;
};
......@@ -907,6 +908,18 @@ struct lpfc_sli4_hba {
#define lpfc_conf_trunk_port3_WORD conf_trunk
#define lpfc_conf_trunk_port3_SHIFT 3
#define lpfc_conf_trunk_port3_MASK 0x1
#define lpfc_conf_trunk_port0_nd_WORD conf_trunk
#define lpfc_conf_trunk_port0_nd_SHIFT 4
#define lpfc_conf_trunk_port0_nd_MASK 0x1
#define lpfc_conf_trunk_port1_nd_WORD conf_trunk
#define lpfc_conf_trunk_port1_nd_SHIFT 5
#define lpfc_conf_trunk_port1_nd_MASK 0x1
#define lpfc_conf_trunk_port2_nd_WORD conf_trunk
#define lpfc_conf_trunk_port2_nd_SHIFT 6
#define lpfc_conf_trunk_port2_nd_MASK 0x1
#define lpfc_conf_trunk_port3_nd_WORD conf_trunk
#define lpfc_conf_trunk_port3_nd_SHIFT 7
#define lpfc_conf_trunk_port3_nd_MASK 0x1
};
enum lpfc_sge_type {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment