summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c121
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h25
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h17
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 {