diff options
author | James Smart | 2019-03-12 16:30:27 -0700 |
---|---|---|
committer | Martin K. Petersen | 2019-03-19 13:15:09 -0400 |
commit | 9a66d990c7429d61c1cdc6feb22e559da587a0db (patch) | |
tree | 35833f3bface8efc0fb729e8f874a3001165105c | |
parent | f3339800f98c30bcca1b70e4201f38b41d4926b1 (diff) |
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: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 121 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 25 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 17 |
4 files changed, 128 insertions, 37 deletions
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index f2494d3b365c..7e9791aaad00 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1968,14 +1968,17 @@ link_diag_state_set_out: } /** - * 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 @@ loopback_mode_exit: } 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 */ diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index 9151824beea4..cd2c4382fced 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -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 { diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index ff875b833192..3b5988669b54 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -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; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index f90ade037cfe..325069abc087 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -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 { |