|
@@ -916,9 +916,11 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
|
|
} else {
|
|
|
switch (cmd) {
|
|
|
case ELX_LOOPBACK_DATA:
|
|
|
- diag_cmd_data_free(phba,
|
|
|
- (struct lpfc_dmabufext *)
|
|
|
- dmabuf);
|
|
|
+ if (phba->sli_rev <
|
|
|
+ LPFC_SLI_REV4)
|
|
|
+ diag_cmd_data_free(phba,
|
|
|
+ (struct lpfc_dmabufext
|
|
|
+ *)dmabuf);
|
|
|
break;
|
|
|
case ELX_LOOPBACK_XRI_SETUP:
|
|
|
if ((phba->sli_rev ==
|
|
@@ -1000,7 +1002,8 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
|
|
error_ct_unsol_exit:
|
|
|
if (!list_empty(&head))
|
|
|
list_del(&head);
|
|
|
- if (evt_req_id == SLI_CT_ELX_LOOPBACK)
|
|
|
+ if ((phba->sli_rev < LPFC_SLI_REV4) &&
|
|
|
+ (evt_req_id == SLI_CT_ELX_LOOPBACK))
|
|
|
return 0;
|
|
|
return 1;
|
|
|
}
|
|
@@ -1566,7 +1569,7 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
|
|
|
struct diag_mode_set *loopback_mode;
|
|
|
uint32_t link_flags;
|
|
|
uint32_t timeout;
|
|
|
- LPFC_MBOXQ_t *pmboxq;
|
|
|
+ LPFC_MBOXQ_t *pmboxq = NULL;
|
|
|
int mbxstatus = MBX_SUCCESS;
|
|
|
int i = 0;
|
|
|
int rc = 0;
|
|
@@ -1615,7 +1618,6 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
|
|
|
rc = -ETIMEDOUT;
|
|
|
goto loopback_mode_exit;
|
|
|
}
|
|
|
-
|
|
|
msleep(10);
|
|
|
}
|
|
|
|
|
@@ -1635,7 +1637,9 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
|
|
|
if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus))
|
|
|
rc = -ENODEV;
|
|
|
else {
|
|
|
+ spin_lock_irq(&phba->hbalock);
|
|
|
phba->link_flag |= LS_LOOPBACK_MODE;
|
|
|
+ spin_unlock_irq(&phba->hbalock);
|
|
|
/* wait for the link attention interrupt */
|
|
|
msleep(100);
|
|
|
|
|
@@ -1659,7 +1663,7 @@ loopback_mode_exit:
|
|
|
/*
|
|
|
* Let SLI layer release mboxq if mbox command completed after timeout.
|
|
|
*/
|
|
|
- if (mbxstatus != MBX_TIMEOUT)
|
|
|
+ if (pmboxq && mbxstatus != MBX_TIMEOUT)
|
|
|
mempool_free(pmboxq, phba->mbox_mem_pool);
|
|
|
|
|
|
job_error:
|
|
@@ -1700,11 +1704,16 @@ lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag)
|
|
|
rc = -ENOMEM;
|
|
|
goto link_diag_state_set_out;
|
|
|
}
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
+ "3128 Set link to diagnostic state:x%x (x%x/x%x)\n",
|
|
|
+ diag, phba->sli4_hba.lnk_info.lnk_tp,
|
|
|
+ phba->sli4_hba.lnk_info.lnk_no);
|
|
|
+
|
|
|
link_diag_state = &pmboxq->u.mqe.un.link_diag_state;
|
|
|
bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req,
|
|
|
- phba->sli4_hba.link_state.number);
|
|
|
+ phba->sli4_hba.lnk_info.lnk_no);
|
|
|
bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req,
|
|
|
- phba->sli4_hba.link_state.type);
|
|
|
+ phba->sli4_hba.lnk_info.lnk_tp);
|
|
|
if (diag)
|
|
|
bf_set(lpfc_mbx_set_diag_state_diag,
|
|
|
&link_diag_state->u.req, 1);
|
|
@@ -1726,6 +1735,79 @@ link_diag_state_set_out:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * lpfc_sli4_bsg_set_internal_loopback - set sli4 internal loopback diagnostic
|
|
|
+ * @phba: Pointer to HBA context object.
|
|
|
+ *
|
|
|
+ * This function is responsible for issuing a sli4 mailbox command for setting
|
|
|
+ * up internal loopback diagnostic.
|
|
|
+ */
|
|
|
+static int
|
|
|
+lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba)
|
|
|
+{
|
|
|
+ LPFC_MBOXQ_t *pmboxq;
|
|
|
+ uint32_t req_len, alloc_len;
|
|
|
+ struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback;
|
|
|
+ int mbxstatus = MBX_SUCCESS, rc = 0;
|
|
|
+
|
|
|
+ pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
|
|
+ if (!pmboxq)
|
|
|
+ return -ENOMEM;
|
|
|
+ req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) -
|
|
|
+ sizeof(struct lpfc_sli4_cfg_mhdr));
|
|
|
+ alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
|
|
|
+ LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK,
|
|
|
+ req_len, LPFC_SLI4_MBX_EMBED);
|
|
|
+ if (alloc_len != req_len) {
|
|
|
+ mempool_free(pmboxq, phba->mbox_mem_pool);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ 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);
|
|
|
+ bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req,
|
|
|
+ LPFC_DIAG_LOOPBACK_TYPE_SERDES);
|
|
|
+
|
|
|
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
|
|
|
+ if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) {
|
|
|
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
|
|
|
+ "3127 Failed setup loopback mode mailbox "
|
|
|
+ "command, rc:x%x, status:x%x\n", mbxstatus,
|
|
|
+ pmboxq->u.mb.mbxStatus);
|
|
|
+ rc = -ENODEV;
|
|
|
+ }
|
|
|
+ if (pmboxq && (mbxstatus != MBX_TIMEOUT))
|
|
|
+ mempool_free(pmboxq, phba->mbox_mem_pool);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * lpfc_sli4_diag_fcport_reg_setup - setup port registrations for diagnostic
|
|
|
+ * @phba: Pointer to HBA context object.
|
|
|
+ *
|
|
|
+ * This function set up SLI4 FC port registrations for diagnostic run, which
|
|
|
+ * includes all the rpis, vfi, and also vpi.
|
|
|
+ */
|
|
|
+static int
|
|
|
+lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ if (phba->pport->fc_flag & FC_VFI_REGISTERED) {
|
|
|
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
|
|
|
+ "3136 Port still had vfi registered: "
|
|
|
+ "mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n",
|
|
|
+ phba->pport->fc_myDID, phba->fcf.fcfi,
|
|
|
+ phba->sli4_hba.vfi_ids[phba->pport->vfi],
|
|
|
+ phba->vpi_ids[phba->pport->vpi]);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ rc = lpfc_issue_reg_vfi(phba->pport);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command
|
|
|
* @phba: Pointer to HBA context object.
|
|
@@ -1738,10 +1820,8 @@ static int
|
|
|
lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
|
|
|
{
|
|
|
struct diag_mode_set *loopback_mode;
|
|
|
- uint32_t link_flags, timeout, req_len, alloc_len;
|
|
|
- struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback;
|
|
|
- LPFC_MBOXQ_t *pmboxq = NULL;
|
|
|
- int mbxstatus = MBX_SUCCESS, i, rc = 0;
|
|
|
+ uint32_t link_flags, timeout;
|
|
|
+ int i, rc = 0;
|
|
|
|
|
|
/* no data to return just the return code */
|
|
|
job->reply->reply_payload_rcv_len = 0;
|
|
@@ -1762,65 +1842,100 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
|
|
|
if (rc)
|
|
|
goto job_error;
|
|
|
|
|
|
+ /* indicate we are in loobpack diagnostic mode */
|
|
|
+ spin_lock_irq(&phba->hbalock);
|
|
|
+ phba->link_flag |= LS_LOOPBACK_MODE;
|
|
|
+ spin_unlock_irq(&phba->hbalock);
|
|
|
+
|
|
|
+ /* reset port to start frome scratch */
|
|
|
+ rc = lpfc_selective_reset(phba);
|
|
|
+ if (rc)
|
|
|
+ goto job_error;
|
|
|
+
|
|
|
/* 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 *)
|
|
|
job->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)
|
|
|
+ if (rc) {
|
|
|
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
|
|
|
+ "3130 Failed to bring link to diagnostic "
|
|
|
+ "state, rc:x%x\n", rc);
|
|
|
goto loopback_mode_exit;
|
|
|
+ }
|
|
|
|
|
|
/* wait for link down before proceeding */
|
|
|
i = 0;
|
|
|
while (phba->link_state != LPFC_LINK_DOWN) {
|
|
|
if (i++ > timeout) {
|
|
|
rc = -ETIMEDOUT;
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
+ "3131 Timeout waiting for link to "
|
|
|
+ "diagnostic mode, timeout:%d ms\n",
|
|
|
+ timeout * 10);
|
|
|
goto loopback_mode_exit;
|
|
|
}
|
|
|
msleep(10);
|
|
|
}
|
|
|
+
|
|
|
/* set up loopback mode */
|
|
|
- pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
|
|
- if (!pmboxq) {
|
|
|
- rc = -ENOMEM;
|
|
|
- goto loopback_mode_exit;
|
|
|
- }
|
|
|
- req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) -
|
|
|
- sizeof(struct lpfc_sli4_cfg_mhdr));
|
|
|
- alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
|
|
|
- LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK,
|
|
|
- req_len, LPFC_SLI4_MBX_EMBED);
|
|
|
- if (alloc_len != req_len) {
|
|
|
- rc = -ENOMEM;
|
|
|
+ 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 {
|
|
|
+ rc = -EINVAL;
|
|
|
+ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
|
|
|
+ "3141 Loopback mode:x%x not supported\n",
|
|
|
+ link_flags);
|
|
|
goto loopback_mode_exit;
|
|
|
}
|
|
|
- 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.link_state.number);
|
|
|
- bf_set(lpfc_mbx_set_diag_state_link_type,
|
|
|
- &link_diag_loopback->u.req, phba->sli4_hba.link_state.type);
|
|
|
- if (link_flags == INTERNAL_LOOP_BACK)
|
|
|
- bf_set(lpfc_mbx_set_diag_lpbk_type,
|
|
|
- &link_diag_loopback->u.req,
|
|
|
- LPFC_DIAG_LOOPBACK_TYPE_INTERNAL);
|
|
|
- else
|
|
|
- bf_set(lpfc_mbx_set_diag_lpbk_type,
|
|
|
- &link_diag_loopback->u.req,
|
|
|
- LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL);
|
|
|
|
|
|
- mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
|
|
|
- if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus))
|
|
|
- rc = -ENODEV;
|
|
|
- else {
|
|
|
- phba->link_flag |= LS_LOOPBACK_MODE;
|
|
|
+ if (!rc) {
|
|
|
/* wait for the link attention interrupt */
|
|
|
msleep(100);
|
|
|
i = 0;
|
|
|
+ while (phba->link_state < LPFC_LINK_UP) {
|
|
|
+ if (i++ > timeout) {
|
|
|
+ rc = -ETIMEDOUT;
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
+ "3137 Timeout waiting for link up "
|
|
|
+ "in loopback mode, timeout:%d ms\n",
|
|
|
+ timeout * 10);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ msleep(10);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* port resource registration setup for loopback diagnostic */
|
|
|
+ if (!rc) {
|
|
|
+ /* set up a none zero myDID for loopback test */
|
|
|
+ phba->pport->fc_myDID = 1;
|
|
|
+ rc = lpfc_sli4_diag_fcport_reg_setup(phba);
|
|
|
+ } else
|
|
|
+ goto loopback_mode_exit;
|
|
|
+
|
|
|
+ if (!rc) {
|
|
|
+ /* wait for the port ready */
|
|
|
+ msleep(100);
|
|
|
+ i = 0;
|
|
|
while (phba->link_state != LPFC_HBA_READY) {
|
|
|
if (i++ > timeout) {
|
|
|
rc = -ETIMEDOUT;
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
+ "3133 Timeout waiting for port "
|
|
|
+ "loopback mode ready, timeout:%d ms\n",
|
|
|
+ timeout * 10);
|
|
|
break;
|
|
|
}
|
|
|
msleep(10);
|
|
@@ -1828,14 +1943,14 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
|
|
|
}
|
|
|
|
|
|
loopback_mode_exit:
|
|
|
+ /* clear loopback diagnostic mode */
|
|
|
+ if (rc) {
|
|
|
+ spin_lock_irq(&phba->hbalock);
|
|
|
+ phba->link_flag &= ~LS_LOOPBACK_MODE;
|
|
|
+ spin_unlock_irq(&phba->hbalock);
|
|
|
+ }
|
|
|
lpfc_bsg_diag_mode_exit(phba);
|
|
|
|
|
|
- /*
|
|
|
- * Let SLI layer release mboxq if mbox command completed after timeout.
|
|
|
- */
|
|
|
- if (pmboxq && (mbxstatus != MBX_TIMEOUT))
|
|
|
- mempool_free(pmboxq, phba->mbox_mem_pool);
|
|
|
-
|
|
|
job_error:
|
|
|
/* make error code available to userspace */
|
|
|
job->reply->result = rc;
|
|
@@ -1879,7 +1994,6 @@ lpfc_bsg_diag_loopback_mode(struct fc_bsg_job *job)
|
|
|
rc = -ENODEV;
|
|
|
|
|
|
return rc;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1895,7 +2009,9 @@ lpfc_sli4_bsg_diag_mode_end(struct fc_bsg_job *job)
|
|
|
struct Scsi_Host *shost;
|
|
|
struct lpfc_vport *vport;
|
|
|
struct lpfc_hba *phba;
|
|
|
- int rc;
|
|
|
+ struct diag_mode_set *loopback_mode_end_cmd;
|
|
|
+ uint32_t timeout;
|
|
|
+ int rc, i;
|
|
|
|
|
|
shost = job->shost;
|
|
|
if (!shost)
|
|
@@ -1913,11 +2029,47 @@ lpfc_sli4_bsg_diag_mode_end(struct fc_bsg_job *job)
|
|
|
LPFC_SLI_INTF_IF_TYPE_2)
|
|
|
return -ENODEV;
|
|
|
|
|
|
+ /* clear loopback diagnostic mode */
|
|
|
+ spin_lock_irq(&phba->hbalock);
|
|
|
+ phba->link_flag &= ~LS_LOOPBACK_MODE;
|
|
|
+ spin_unlock_irq(&phba->hbalock);
|
|
|
+ loopback_mode_end_cmd = (struct diag_mode_set *)
|
|
|
+ job->request->rqst_data.h_vendor.vendor_cmd;
|
|
|
+ timeout = loopback_mode_end_cmd->timeout * 100;
|
|
|
+
|
|
|
rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0);
|
|
|
+ if (rc) {
|
|
|
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
|
|
|
+ "3139 Failed to bring link to diagnostic "
|
|
|
+ "state, rc:x%x\n", rc);
|
|
|
+ goto loopback_mode_end_exit;
|
|
|
+ }
|
|
|
|
|
|
- if (!rc)
|
|
|
- rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
|
|
|
+ /* wait for link down before proceeding */
|
|
|
+ i = 0;
|
|
|
+ while (phba->link_state != LPFC_LINK_DOWN) {
|
|
|
+ if (i++ > timeout) {
|
|
|
+ rc = -ETIMEDOUT;
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
+ "3140 Timeout waiting for link to "
|
|
|
+ "diagnostic mode_end, timeout:%d ms\n",
|
|
|
+ timeout * 10);
|
|
|
+ /* there is nothing much we can do here */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ msleep(10);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* reset port resource registrations */
|
|
|
+ rc = lpfc_selective_reset(phba);
|
|
|
+ phba->pport->fc_myDID = 0;
|
|
|
|
|
|
+loopback_mode_end_exit:
|
|
|
+ /* make return code available to userspace */
|
|
|
+ job->reply->result = rc;
|
|
|
+ /* complete the job back to userspace if no error */
|
|
|
+ if (rc == 0)
|
|
|
+ job->job_done(job);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -2012,9 +2164,9 @@ lpfc_sli4_bsg_link_diag_test(struct fc_bsg_job *job)
|
|
|
}
|
|
|
run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test;
|
|
|
bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req,
|
|
|
- phba->sli4_hba.link_state.number);
|
|
|
+ phba->sli4_hba.lnk_info.lnk_no);
|
|
|
bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req,
|
|
|
- phba->sli4_hba.link_state.type);
|
|
|
+ phba->sli4_hba.lnk_info.lnk_tp);
|
|
|
bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req,
|
|
|
link_diag_test_cmd->test_id);
|
|
|
bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req,
|
|
@@ -2091,10 +2243,18 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi)
|
|
|
if (!mbox)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- if (phba->sli_rev == LPFC_SLI_REV4)
|
|
|
+ if (phba->sli_rev < LPFC_SLI_REV4)
|
|
|
+ status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID,
|
|
|
+ (uint8_t *)&phba->pport->fc_sparam,
|
|
|
+ mbox, *rpi);
|
|
|
+ else {
|
|
|
*rpi = lpfc_sli4_alloc_rpi(phba);
|
|
|
- status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID,
|
|
|
- (uint8_t *)&phba->pport->fc_sparam, mbox, *rpi);
|
|
|
+ status = lpfc_reg_rpi(phba, phba->pport->vpi,
|
|
|
+ phba->pport->fc_myDID,
|
|
|
+ (uint8_t *)&phba->pport->fc_sparam,
|
|
|
+ mbox, *rpi);
|
|
|
+ }
|
|
|
+
|
|
|
if (status) {
|
|
|
mempool_free(mbox, phba->mbox_mem_pool);
|
|
|
if (phba->sli_rev == LPFC_SLI_REV4)
|
|
@@ -2117,7 +2277,8 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi)
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
- *rpi = mbox->u.mb.un.varWords[0];
|
|
|
+ if (phba->sli_rev < LPFC_SLI_REV4)
|
|
|
+ *rpi = mbox->u.mb.un.varWords[0];
|
|
|
|
|
|
lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
|
|
|
kfree(dmabuff);
|
|
@@ -2142,7 +2303,12 @@ static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi)
|
|
|
if (mbox == NULL)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- lpfc_unreg_login(phba, 0, rpi, mbox);
|
|
|
+ if (phba->sli_rev < LPFC_SLI_REV4)
|
|
|
+ lpfc_unreg_login(phba, 0, rpi, mbox);
|
|
|
+ else
|
|
|
+ lpfc_unreg_login(phba, phba->pport->vpi,
|
|
|
+ phba->sli4_hba.rpi_ids[rpi], mbox);
|
|
|
+
|
|
|
status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
|
|
|
|
|
|
if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) {
|
|
@@ -2630,15 +2796,15 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
|
|
uint32_t full_size;
|
|
|
size_t segment_len = 0, segment_offset = 0, current_offset = 0;
|
|
|
uint16_t rpi = 0;
|
|
|
- struct lpfc_iocbq *cmdiocbq, *rspiocbq;
|
|
|
- IOCB_t *cmd, *rsp;
|
|
|
+ struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL;
|
|
|
+ IOCB_t *cmd, *rsp = NULL;
|
|
|
struct lpfc_sli_ct_request *ctreq;
|
|
|
struct lpfc_dmabuf *txbmp;
|
|
|
struct ulp_bde64 *txbpl = NULL;
|
|
|
struct lpfc_dmabufext *txbuffer = NULL;
|
|
|
struct list_head head;
|
|
|
struct lpfc_dmabuf *curr;
|
|
|
- uint16_t txxri, rxxri;
|
|
|
+ uint16_t txxri = 0, rxxri;
|
|
|
uint32_t num_bde;
|
|
|
uint8_t *ptr = NULL, *rx_databuf = NULL;
|
|
|
int rc = 0;
|
|
@@ -2665,7 +2831,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
|
|
rc = -EINVAL;
|
|
|
goto loopback_test_exit;
|
|
|
}
|
|
|
-
|
|
|
diag_mode = (struct diag_mode_test *)
|
|
|
job->request->rqst_data.h_vendor.vendor_cmd;
|
|
|
|
|
@@ -2720,18 +2885,19 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
|
|
if (rc)
|
|
|
goto loopback_test_exit;
|
|
|
|
|
|
- rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri);
|
|
|
- if (rc) {
|
|
|
- lpfcdiag_loop_self_unreg(phba, rpi);
|
|
|
- goto loopback_test_exit;
|
|
|
- }
|
|
|
+ if (phba->sli_rev < LPFC_SLI_REV4) {
|
|
|
+ rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri);
|
|
|
+ if (rc) {
|
|
|
+ lpfcdiag_loop_self_unreg(phba, rpi);
|
|
|
+ goto loopback_test_exit;
|
|
|
+ }
|
|
|
|
|
|
- rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size);
|
|
|
- if (rc) {
|
|
|
- lpfcdiag_loop_self_unreg(phba, rpi);
|
|
|
- goto loopback_test_exit;
|
|
|
+ rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size);
|
|
|
+ if (rc) {
|
|
|
+ lpfcdiag_loop_self_unreg(phba, rpi);
|
|
|
+ goto loopback_test_exit;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid,
|
|
|
SLI_CT_ELX_LOOPBACK);
|
|
|
if (!evt) {
|
|
@@ -2746,7 +2912,8 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
|
|
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
|
|
|
|
|
cmdiocbq = lpfc_sli_get_iocbq(phba);
|
|
|
- rspiocbq = lpfc_sli_get_iocbq(phba);
|
|
|
+ if (phba->sli_rev < LPFC_SLI_REV4)
|
|
|
+ rspiocbq = lpfc_sli_get_iocbq(phba);
|
|
|
txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
|
|
|
|
|
if (txbmp) {
|
|
@@ -2759,14 +2926,18 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer ||
|
|
|
- !txbmp->virt) {
|
|
|
+ if (!cmdiocbq || !txbmp || !txbpl || !txbuffer || !txbmp->virt) {
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto err_loopback_test_exit;
|
|
|
+ }
|
|
|
+ if ((phba->sli_rev < LPFC_SLI_REV4) && !rspiocbq) {
|
|
|
rc = -ENOMEM;
|
|
|
goto err_loopback_test_exit;
|
|
|
}
|
|
|
|
|
|
cmd = &cmdiocbq->iocb;
|
|
|
- rsp = &rspiocbq->iocb;
|
|
|
+ if (phba->sli_rev < LPFC_SLI_REV4)
|
|
|
+ rsp = &rspiocbq->iocb;
|
|
|
|
|
|
INIT_LIST_HEAD(&head);
|
|
|
list_add_tail(&head, &txbuffer->dma.list);
|
|
@@ -2796,7 +2967,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
|
|
list_del(&head);
|
|
|
|
|
|
/* Build the XMIT_SEQUENCE iocb */
|
|
|
-
|
|
|
num_bde = (uint32_t)txbuffer->flag;
|
|
|
|
|
|
cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys);
|
|
@@ -2813,16 +2983,27 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
|
|
cmd->ulpBdeCount = 1;
|
|
|
cmd->ulpLe = 1;
|
|
|
cmd->ulpClass = CLASS3;
|
|
|
- cmd->ulpContext = txxri;
|
|
|
|
|
|
+ if (phba->sli_rev < LPFC_SLI_REV4) {
|
|
|
+ cmd->ulpContext = txxri;
|
|
|
+ } else {
|
|
|
+ cmd->un.xseq64.bdl.ulpIoTag32 = 0;
|
|
|
+ cmd->un.ulpWord[3] = phba->sli4_hba.rpi_ids[rpi];
|
|
|
+ cmdiocbq->context3 = txbmp;
|
|
|
+ cmdiocbq->sli4_xritag = NO_XRI;
|
|
|
+ cmd->unsli3.rcvsli3.ox_id = 0xffff;
|
|
|
+ }
|
|
|
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
|
|
|
cmdiocbq->vport = phba->pport;
|
|
|
-
|
|
|
iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
|
|
|
rspiocbq, (phba->fc_ratov * 2) +
|
|
|
LPFC_DRVR_TIMEOUT);
|
|
|
|
|
|
- if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) {
|
|
|
+ if ((iocb_stat != IOCB_SUCCESS) || ((phba->sli_rev < LPFC_SLI_REV4) &&
|
|
|
+ (rsp->ulpStatus != IOCB_SUCCESS))) {
|
|
|
+ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
|
|
|
+ "3126 Failed loopback test issue iocb: "
|
|
|
+ "iocb_stat:x%x\n", iocb_stat);
|
|
|
rc = -EIO;
|
|
|
goto err_loopback_test_exit;
|
|
|
}
|
|
@@ -2832,9 +3013,12 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
|
|
evt->wq, !list_empty(&evt->events_to_see),
|
|
|
((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ);
|
|
|
evt->waiting = 0;
|
|
|
- if (list_empty(&evt->events_to_see))
|
|
|
+ if (list_empty(&evt->events_to_see)) {
|
|
|
rc = (time_left) ? -EINTR : -ETIMEDOUT;
|
|
|
- else {
|
|
|
+ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
|
|
|
+ "3125 Not receiving unsolicited event, "
|
|
|
+ "rc:x%x\n", rc);
|
|
|
+ } else {
|
|
|
spin_lock_irqsave(&phba->ct_ev_lock, flags);
|
|
|
list_move(evt->events_to_see.prev, &evt->events_to_get);
|
|
|
evdat = list_entry(evt->events_to_get.prev,
|
|
@@ -2891,7 +3075,7 @@ loopback_test_exit:
|
|
|
job->reply->result = rc;
|
|
|
job->dd_data = NULL;
|
|
|
/* complete the job back to userspace if no error */
|
|
|
- if (rc == 0)
|
|
|
+ if (rc == IOCB_SUCCESS)
|
|
|
job->job_done(job);
|
|
|
return rc;
|
|
|
}
|
|
@@ -3078,7 +3262,9 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
|
|
|
&& (mb->un.varWords[1] == 1)) {
|
|
|
phba->wait_4_mlo_maint_flg = 1;
|
|
|
} else if (mb->un.varWords[0] == SETVAR_MLORST) {
|
|
|
+ spin_lock_irq(&phba->hbalock);
|
|
|
phba->link_flag &= ~LS_LOOPBACK_MODE;
|
|
|
+ spin_unlock_irq(&phba->hbalock);
|
|
|
phba->fc_topology = LPFC_TOPOLOGY_PT_PT;
|
|
|
}
|
|
|
break;
|
|
@@ -3140,6 +3326,9 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
|
|
|
unsigned long flags;
|
|
|
uint32_t size;
|
|
|
int rc = 0;
|
|
|
+ struct lpfc_dmabuf *dmabuf;
|
|
|
+ struct lpfc_sli_config_mbox *sli_cfg_mbx;
|
|
|
+ uint8_t *pmbx;
|
|
|
|
|
|
spin_lock_irqsave(&phba->ct_ev_lock, flags);
|
|
|
dd_data = pmboxq->context1;
|
|
@@ -3156,7 +3345,19 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
|
|
|
*/
|
|
|
pmb = (uint8_t *)&pmboxq->u.mb;
|
|
|
pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb;
|
|
|
+ /* Copy the byte swapped response mailbox back to the user */
|
|
|
memcpy(pmb_buf, pmb, sizeof(MAILBOX_t));
|
|
|
+ /* if there is any non-embedded extended data copy that too */
|
|
|
+ dmabuf = phba->mbox_ext_buf_ctx.mbx_dmabuf;
|
|
|
+ sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt;
|
|
|
+ if (!bsg_bf_get(lpfc_mbox_hdr_emb,
|
|
|
+ &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) {
|
|
|
+ pmbx = (uint8_t *)dmabuf->virt;
|
|
|
+ /* byte swap the extended data following the mailbox command */
|
|
|
+ lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)],
|
|
|
+ &pmbx[sizeof(MAILBOX_t)],
|
|
|
+ sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len);
|
|
|
+ }
|
|
|
|
|
|
job = dd_data->context_un.mbox.set_job;
|
|
|
if (job) {
|
|
@@ -3519,6 +3720,18 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
|
|
/* state change */
|
|
|
phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
|
|
|
|
|
|
+ /*
|
|
|
+ * Non-embedded mailbox subcommand data gets byte swapped here because
|
|
|
+ * the lower level driver code only does the first 64 mailbox words.
|
|
|
+ */
|
|
|
+ if ((!bsg_bf_get(lpfc_mbox_hdr_emb,
|
|
|
+ &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) &&
|
|
|
+ (nemb_tp == nemb_mse))
|
|
|
+ lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)],
|
|
|
+ &pmbx[sizeof(MAILBOX_t)],
|
|
|
+ sli_cfg_mbx->un.sli_config_emb0_subsys.
|
|
|
+ mse[0].buf_len);
|
|
|
+
|
|
|
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
|
|
|
if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) {
|
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
@@ -3575,7 +3788,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
|
|
&sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr);
|
|
|
if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) {
|
|
|
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
|
|
|
- "2953 Handled SLI_CONFIG(mse) wr, "
|
|
|
+ "2953 Failed SLI_CONFIG(mse) wr, "
|
|
|
"ext_buf_cnt(%d) out of range(%d)\n",
|
|
|
ext_buf_cnt,
|
|
|
LPFC_MBX_SLI_CONFIG_MAX_MSE);
|
|
@@ -3593,7 +3806,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
|
|
ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count;
|
|
|
if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) {
|
|
|
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
|
|
|
- "2954 Handled SLI_CONFIG(hbd) wr, "
|
|
|
+ "2954 Failed SLI_CONFIG(hbd) wr, "
|
|
|
"ext_buf_cnt(%d) out of range(%d)\n",
|
|
|
ext_buf_cnt,
|
|
|
LPFC_MBX_SLI_CONFIG_MAX_HBD);
|
|
@@ -3687,6 +3900,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
|
|
"2956 Failed to issue SLI_CONFIG ext-buffer "
|
|
|
"maibox command, rc:x%x\n", rc);
|
|
|
rc = -EPIPE;
|
|
|
+ goto job_error;
|
|
|
}
|
|
|
|
|
|
/* wait for additoinal external buffers */
|
|
@@ -3721,7 +3935,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
|
|
uint32_t opcode;
|
|
|
int rc = SLI_CONFIG_NOT_HANDLED;
|
|
|
|
|
|
- /* state change */
|
|
|
+ /* state change on new multi-buffer pass-through mailbox command */
|
|
|
phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_HOST;
|
|
|
|
|
|
sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt;
|
|
@@ -3752,18 +3966,36 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
|
|
break;
|
|
|
default:
|
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
- "2959 Not handled SLI_CONFIG "
|
|
|
+ "2959 Reject SLI_CONFIG "
|
|
|
"subsys_fcoe, opcode:x%x\n",
|
|
|
opcode);
|
|
|
- rc = SLI_CONFIG_NOT_HANDLED;
|
|
|
+ rc = -EPERM;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else if (subsys == SLI_CONFIG_SUBSYS_COMN) {
|
|
|
+ switch (opcode) {
|
|
|
+ case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES:
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
+ "3106 Handled SLI_CONFIG "
|
|
|
+ "subsys_fcoe, opcode:x%x\n",
|
|
|
+ opcode);
|
|
|
+ rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job,
|
|
|
+ nemb_mse, dmabuf);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
+ "3107 Reject SLI_CONFIG "
|
|
|
+ "subsys_fcoe, opcode:x%x\n",
|
|
|
+ opcode);
|
|
|
+ rc = -EPERM;
|
|
|
break;
|
|
|
}
|
|
|
} else {
|
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
- "2977 Handled SLI_CONFIG "
|
|
|
+ "2977 Reject SLI_CONFIG "
|
|
|
"subsys:x%d, opcode:x%x\n",
|
|
|
subsys, opcode);
|
|
|
- rc = SLI_CONFIG_NOT_HANDLED;
|
|
|
+ rc = -EPERM;
|
|
|
}
|
|
|
} else {
|
|
|
subsys = bsg_bf_get(lpfc_emb1_subcmnd_subsys,
|
|
@@ -3799,12 +4031,17 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
|
|
}
|
|
|
} else {
|
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
|
|
- "2978 Handled SLI_CONFIG "
|
|
|
+ "2978 Not handled SLI_CONFIG "
|
|
|
"subsys:x%d, opcode:x%x\n",
|
|
|
subsys, opcode);
|
|
|
rc = SLI_CONFIG_NOT_HANDLED;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /* state reset on not handled new multi-buffer mailbox command */
|
|
|
+ if (rc != SLI_CONFIG_HANDLED)
|
|
|
+ phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE;
|
|
|
+
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
@@ -4262,11 +4499,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
|
|
|
|
|
/* extended mailbox commands will need an extended buffer */
|
|
|
if (mbox_req->inExtWLen || mbox_req->outExtWLen) {
|
|
|
- /* any data for the device? */
|
|
|
- if (mbox_req->inExtWLen) {
|
|
|
- from = pmbx;
|
|
|
- ext = from + sizeof(MAILBOX_t);
|
|
|
- }
|
|
|
+ from = pmbx;
|
|
|
+ ext = from + sizeof(MAILBOX_t);
|
|
|
pmboxq->context2 = ext;
|
|
|
pmboxq->in_ext_byte_len =
|
|
|
mbox_req->inExtWLen * sizeof(uint32_t);
|