Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b51197d authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc 8.3.28: Add Loopback support for SLI4 adapters



- Add Basic support for SLI4 Loopback.
  (CR 124951, 125766, 124951, 125843, 125832, 125843)
- Added missing protection in setting/clearing of phba->link_flag bit
  field (CR 125994)
- Use link type and link number obtained from READ_CONFIG mailbox
  command. (CR 126264)

Signed-off-by: default avatarAlex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 2e90f4b5
Loading
Loading
Loading
Loading
+272 −86
Original line number Diff line number Diff line
@@ -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:
						if (phba->sli_rev <
						    LPFC_SLI_REV4)
							diag_cmd_data_free(phba,
						(struct lpfc_dmabufext *)
							dmabuf);
							(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 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
	/*
	 * 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 @@ lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag)
	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)
		*rpi = lpfc_sli4_alloc_rpi(phba);
	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);
				(uint8_t *)&phba->pport->fc_sparam,
				mbox, *rpi);
	else {
		*rpi = lpfc_sli4_alloc_rpi(phba);
		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,6 +2277,7 @@ static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi)
		return -ENODEV;
	}

	if (phba->sli_rev < LPFC_SLI_REV4)
		*rpi = mbox->u.mb.un.varWords[0];

	lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys);
@@ -2142,7 +2303,12 @@ static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi)
	if (mbox == NULL)
		return -ENOMEM;

	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,6 +2885,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
	if (rc)
		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);
@@ -2731,7 +2897,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
			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,6 +2912,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);

	cmdiocbq = 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);

@@ -2759,13 +2926,17 @@ 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;
	if (phba->sli_rev < LPFC_SLI_REV4)
		rsp = &rspiocbq->iocb;

	INIT_LIST_HEAD(&head);
@@ -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 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
	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;
+7 −2
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_unregister_vfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *);
struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *,
@@ -453,7 +454,11 @@ int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int);
uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *);
int lpfc_sli4_queue_create(struct lpfc_hba *);
void lpfc_sli4_queue_destroy(struct lpfc_hba *);
int lpfc_sli4_read_config(struct lpfc_hba *phba);
int lpfc_scsi_buf_update(struct lpfc_hba *phba);
void lpfc_sli4_abts_err_handler(struct lpfc_hba *, struct lpfc_nodelist *,
				struct sli4_wcqe_xri_aborted *);
int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t);
int lpfc_issue_reg_vfi(struct lpfc_vport *);
int lpfc_issue_unreg_vfi(struct lpfc_vport *);
int lpfc_selective_reset(struct lpfc_hba *);
int lpfc_sli4_read_config(struct lpfc_hba *phba);
int lpfc_scsi_buf_update(struct lpfc_hba *phba);
+98 −27
Original line number Diff line number Diff line
@@ -421,13 +421,13 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
 * @vport: pointer to a host virtual N_Port data structure.
 *
 * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for
 * the @vport. This mailbox command is necessary for FCoE only.
 * the @vport. This mailbox command is necessary for SLI4 port only.
 *
 * Return code
 *   0 - successfully issued REG_VFI for @vport
 *   A failure code otherwise.
 **/
static int
int
lpfc_issue_reg_vfi(struct lpfc_vport *vport)
{
	struct lpfc_hba  *phba = vport->phba;
@@ -438,11 +438,15 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
	int rc = 0;

	sp = &phba->fc_fabparam;
	/* move forward in case of SLI4 FC port loopback test */
	if ((phba->sli_rev == LPFC_SLI_REV4) &&
	    !(phba->link_flag & LS_LOOPBACK_MODE)) {
		ndlp = lpfc_findnode_did(vport, Fabric_DID);
		if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
			rc = -ENODEV;
			goto fail;
		}
	}

	dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
	if (!dmabuf) {
@@ -486,6 +490,54 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
	return rc;
}

/**
 * lpfc_issue_unreg_vfi - Unregister VFI for this vport's fabric login
 * @vport: pointer to a host virtual N_Port data structure.
 *
 * This routine issues a UNREG_VFI mailbox with the vfi, vpi, fcfi triplet for
 * the @vport. This mailbox command is necessary for SLI4 port only.
 *
 * Return code
 *   0 - successfully issued REG_VFI for @vport
 *   A failure code otherwise.
 **/
int
lpfc_issue_unreg_vfi(struct lpfc_vport *vport)
{
	struct lpfc_hba *phba = vport->phba;
	struct Scsi_Host *shost;
	LPFC_MBOXQ_t *mboxq;
	int rc;

	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	if (!mboxq) {
		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
				"2556 UNREG_VFI mbox allocation failed"
				"HBA state x%x\n", phba->pport->port_state);
		return -ENOMEM;
	}

	lpfc_unreg_vfi(mboxq, vport);
	mboxq->vport = vport;
	mboxq->mbox_cmpl = lpfc_unregister_vfi_cmpl;

	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
	if (rc == MBX_NOT_FINISHED) {
		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
				"2557 UNREG_VFI issue mbox failed rc x%x "
				"HBA state x%x\n",
				rc, phba->pport->port_state);
		mempool_free(mboxq, phba->mbox_mem_pool);
		return -EIO;
	}

	shost = lpfc_shost_from_vport(vport);
	spin_lock_irq(shost->host_lock);
	vport->fc_flag &= ~FC_VFI_REGISTERED;
	spin_unlock_irq(shost->host_lock);
	return 0;
}

/**
 * lpfc_check_clean_addr_bit - Check whether assigned FCID is clean.
 * @vport: pointer to a host virtual N_Port data structure.
@@ -615,7 +667,9 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
					 "1816 FLOGI NPIV supported, "
					 "response data 0x%x\n",
					 sp->cmn.response_multiple_NPort);
			spin_lock_irq(&phba->hbalock);
			phba->link_flag |= LS_NPIV_FAB_SUPPORTED;
			spin_unlock_irq(&phba->hbalock);
		} else {
			/* Because we asked f/w for NPIV it still expects us
			to call reg_vnpid atleast for the physcial host */
@@ -623,7 +677,9 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
					 LOG_ELS | LOG_VPORT,
					 "1817 Fabric does not support NPIV "
					 "- configuring single port mode.\n");
			spin_lock_irq(&phba->hbalock);
			phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
			spin_unlock_irq(&phba->hbalock);
		}
	}

@@ -686,11 +742,16 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			lpfc_do_scr_ns_plogi(phba, vport);
		} else if (vport->fc_flag & FC_VFI_REGISTERED)
			lpfc_issue_init_vpi(vport);
		else
		else {
			lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
					"3135 Need register VFI: (x%x/%x)\n",
					vport->fc_prevDID, vport->fc_myDID);
			lpfc_issue_reg_vfi(vport);
		}
	}
	return 0;
}

/**
 * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port
 * @vport: pointer to a host virtual N_Port data structure.
@@ -907,9 +968,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
		 * alpa map would take too long otherwise.
		 */
		if (phba->alpa_map[0] == 0) {
		if (phba->alpa_map[0] == 0)
			vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
		}
		if ((phba->sli_rev == LPFC_SLI_REV4) &&
		    (!(vport->fc_flag & FC_VFI_REGISTERED) ||
		     (vport->fc_prevDID != vport->fc_myDID))) {
@@ -1164,8 +1224,7 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba)
	spin_lock_irq(&phba->hbalock);
	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
		icmd = &iocb->iocb;
		if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
		    icmd->un.elsreq64.bdl.ulpIoTag32) {
		if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) {
			ndlp = (struct lpfc_nodelist *)(iocb->context1);
			if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
			    (ndlp->nlp_DID == Fabric_DID))
@@ -4879,10 +4938,11 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
			    sizeof(struct lpfc_name));

		if (!rc) {
			mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
			if (phba->sli_rev < LPFC_SLI_REV4) {
				mbox = mempool_alloc(phba->mbox_mem_pool,
						     GFP_KERNEL);
				if (!mbox)
					return 1;

				lpfc_linkdown(phba);
				lpfc_init_link(phba, mbox,
					       phba->cfg_topology,
@@ -4890,12 +4950,19 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
				mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
				mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
				mbox->vport = vport;
			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
				rc = lpfc_sli_issue_mbox(phba, mbox,
							 MBX_NOWAIT);
				lpfc_set_loopback_flag(phba);
			if (rc == MBX_NOT_FINISHED) {
				if (rc == MBX_NOT_FINISHED)
					mempool_free(mbox, phba->mbox_mem_pool);
			}
				return 1;
			} else {
				/* abort the flogi coming back to ourselves
				 * due to external loopback on the port.
				 */
				lpfc_els_abort_flogi(phba);
				return 0;
			}
		} else if (rc > 0) {	/* greater than */
			spin_lock_irq(shost->host_lock);
			vport->fc_flag |= FC_PT2PT_PLOGI;
@@ -5850,10 +5917,14 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
			vport->fc_myDID = vport->fc_prevDID;
			if (phba->sli_rev < LPFC_SLI_REV4)
				lpfc_issue_fabric_reglogin(vport);
			else
			else {
				lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
					"3138 Need register VFI: (x%x/%x)\n",
					vport->fc_prevDID, vport->fc_myDID);
				lpfc_issue_reg_vfi(vport);
			}
		}
	}
	return 0;
}

+22 −38

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -1858,8 +1858,8 @@ typedef struct {
	uint8_t fabric_AL_PA;	/* If using a Fabric Assigned AL_PA */
#endif

#define FLAGS_LOCAL_LB               0x01 /* link_flags (=1) ENDEC loopback */
#define FLAGS_TOPOLOGY_MODE_LOOP_PT  0x00 /* Attempt loop then pt-pt */
#define FLAGS_LOCAL_LB               0x01 /* link_flags (=1) ENDEC loopback */
#define FLAGS_TOPOLOGY_MODE_PT_PT    0x02 /* Attempt pt-pt only */
#define FLAGS_TOPOLOGY_MODE_LOOP     0x04 /* Attempt loop only */
#define FLAGS_TOPOLOGY_MODE_PT_LOOP  0x06 /* Attempt pt-pt then loop */
Loading