Commit 7ea92eb4 authored by James Smart's avatar James Smart Committed by Martin K. Petersen
Browse files

scsi: lpfc: Implement GID_PT on Nameserver query to support faster failover



The switches seem to respond faster to GID_PT vs GID_FT NameServer
queries.  Add support for GID_PT to be used over GID_FT to enable
faster storage failover detection. Includes addition of new module
parameter to select between GID_PT and GID_FT (GID_FT is default).

Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent d83ca3ea
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -784,6 +784,7 @@ struct lpfc_hba {
#define LPFC_FCF_PRIORITY 2	/* Priority fcf failover */
	uint32_t cfg_fcf_failover_policy;
	uint32_t cfg_fcp_io_sched;
	uint32_t cfg_ns_query;
	uint32_t cfg_fcp2_no_tgt_reset;
	uint32_t cfg_cr_delay;
	uint32_t cfg_cr_count;
+14 −0
Original line number Diff line number Diff line
@@ -5069,6 +5069,18 @@ LPFC_ATTR_RW(fcp_io_sched, LPFC_FCP_SCHED_ROUND_ROBIN,
	     "Determine scheduling algorithm for "
	     "issuing commands [0] - Round Robin, [1] - Current CPU");

/*
 * lpfc_ns_query: Determine algrithmn for NameServer queries after RSCN
 * range is [0,1]. Default value is 0.
 * For [0], GID_FT is used for NameServer queries after RSCN (default)
 * For [1], GID_PT is used for NameServer queries after RSCN
 *
 */
LPFC_ATTR_RW(ns_query, LPFC_NS_QUERY_GID_FT,
	     LPFC_NS_QUERY_GID_FT, LPFC_NS_QUERY_GID_PT,
	     "Determine algorithm NameServer queries after RSCN "
	     "[0] - GID_FT, [1] - GID_PT");

/*
# lpfc_fcp2_no_tgt_reset: Determine bus reset behavior
# range is [0,1]. Default value is 0.
@@ -5514,6 +5526,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
	&dev_attr_lpfc_scan_down,
	&dev_attr_lpfc_link_speed,
	&dev_attr_lpfc_fcp_io_sched,
	&dev_attr_lpfc_ns_query,
	&dev_attr_lpfc_fcp2_no_tgt_reset,
	&dev_attr_lpfc_cr_delay,
	&dev_attr_lpfc_cr_count,
@@ -6564,6 +6577,7 @@ void
lpfc_get_cfgparam(struct lpfc_hba *phba)
{
	lpfc_fcp_io_sched_init(phba, lpfc_fcp_io_sched);
	lpfc_ns_query_init(phba, lpfc_ns_query);
	lpfc_fcp2_no_tgt_reset_init(phba, lpfc_fcp2_no_tgt_reset);
	lpfc_cr_delay_init(phba, lpfc_cr_delay);
	lpfc_cr_count_init(phba, lpfc_cr_count);
+1 −0
Original line number Diff line number Diff line
@@ -175,6 +175,7 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *);
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
			 struct lpfc_iocbq *);
int lpfc_ct_handle_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *);
int lpfc_issue_gidpt(struct lpfc_vport *vport);
int lpfc_issue_gidft(struct lpfc_vport *vport);
int lpfc_get_gidft_type(struct lpfc_vport *vport, struct lpfc_iocbq *iocbq);
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
+206 −0
Original line number Diff line number Diff line
@@ -831,6 +831,198 @@ out:
	return;
}

static void
lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			struct lpfc_iocbq *rspiocb)
{
	struct lpfc_vport *vport = cmdiocb->vport;
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	IOCB_t *irsp;
	struct lpfc_dmabuf *outp;
	struct lpfc_dmabuf *inp;
	struct lpfc_sli_ct_request *CTrsp;
	struct lpfc_sli_ct_request *CTreq;
	struct lpfc_nodelist *ndlp;
	int rc;

	/* First save ndlp, before we overwrite it */
	ndlp = cmdiocb->context_un.ndlp;

	/* we pass cmdiocb to state machine which needs rspiocb as well */
	cmdiocb->context_un.rsp_iocb = rspiocb;
	inp = (struct lpfc_dmabuf *)cmdiocb->context1;
	outp = (struct lpfc_dmabuf *)cmdiocb->context2;
	irsp = &rspiocb->iocb;

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
			      "GID_PT cmpl:     status:x%x/x%x rtry:%d",
			      irsp->ulpStatus, irsp->un.ulpWord[4],
			      vport->fc_ns_retry);

	/* Don't bother processing response if vport is being torn down. */
	if (vport->load_flag & FC_UNLOADING) {
		if (vport->fc_flag & FC_RSCN_MODE)
			lpfc_els_flush_rscn(vport);
		goto out;
	}

	if (lpfc_els_chk_latt(vport)) {
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
				 "4108 Link event during NS query\n");
		if (vport->fc_flag & FC_RSCN_MODE)
			lpfc_els_flush_rscn(vport);
		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
		goto out;
	}
	if (lpfc_error_lost_link(irsp)) {
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
				 "4101 NS query failed due to link event\n");
		if (vport->fc_flag & FC_RSCN_MODE)
			lpfc_els_flush_rscn(vport);
		goto out;
	}

	spin_lock_irq(shost->host_lock);
	if (vport->fc_flag & FC_RSCN_DEFERRED) {
		vport->fc_flag &= ~FC_RSCN_DEFERRED;
		spin_unlock_irq(shost->host_lock);

		/* This is a GID_PT completing so the gidft_inp counter was
		 * incremented before the GID_PT was issued to the wire.
		 */
		vport->gidft_inp--;

		/*
		 * Skip processing the NS response
		 * Re-issue the NS cmd
		 */
		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
				 "4102 Process Deferred RSCN Data: x%x x%x\n",
				 vport->fc_flag, vport->fc_rscn_id_cnt);
		lpfc_els_handle_rscn(vport);

		goto out;
	}
	spin_unlock_irq(shost->host_lock);

	if (irsp->ulpStatus) {
		/* Check for retry */
		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
			if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
			    (irsp->un.ulpWord[4] & IOERR_PARAM_MASK) !=
			    IOERR_NO_RESOURCES)
				vport->fc_ns_retry++;

			/* CT command is being retried */
			vport->gidft_inp--;
			rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_PT,
					 vport->fc_ns_retry, GID_PT_N_PORT);
			if (rc == 0)
				goto out;
		}
		if (vport->fc_flag & FC_RSCN_MODE)
			lpfc_els_flush_rscn(vport);
		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "4103 GID_FT Query error: 0x%x 0x%x\n",
				 irsp->ulpStatus, vport->fc_ns_retry);
	} else {
		/* Good status, continue checking */
		CTreq = (struct lpfc_sli_ct_request *)inp->virt;
		CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) {
			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
					 "4105 NameServer Rsp Data: x%x x%x\n",
					 vport->fc_flag,
					 CTreq->un.gid.Fc4Type);

			lpfc_ns_rsp(vport,
				    outp,
				    CTreq->un.gid.Fc4Type,
				    (uint32_t)(irsp->un.genreq64.bdl.bdeSize));
		} else if (CTrsp->CommandResponse.bits.CmdRsp ==
			   be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
			/* NameServer Rsp Error */
			if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
			    && (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
				lpfc_printf_vlog(
					vport, KERN_INFO, LOG_DISCOVERY,
					"4106 No NameServer Entries "
					"Data: x%x x%x x%x x%x\n",
					CTrsp->CommandResponse.bits.CmdRsp,
					(uint32_t)CTrsp->ReasonCode,
					(uint32_t)CTrsp->Explanation,
					vport->fc_flag);

				lpfc_debugfs_disc_trc(
				vport, LPFC_DISC_TRC_CT,
				"GID_PT no entry  cmd:x%x rsn:x%x exp:x%x",
				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
				(uint32_t)CTrsp->ReasonCode,
				(uint32_t)CTrsp->Explanation);
			} else {
				lpfc_printf_vlog(
					vport, KERN_INFO, LOG_DISCOVERY,
					"4107 NameServer Rsp Error "
					"Data: x%x x%x x%x x%x\n",
					CTrsp->CommandResponse.bits.CmdRsp,
					(uint32_t)CTrsp->ReasonCode,
					(uint32_t)CTrsp->Explanation,
					vport->fc_flag);

				lpfc_debugfs_disc_trc(
				vport, LPFC_DISC_TRC_CT,
				"GID_PT rsp err1  cmd:x%x rsn:x%x exp:x%x",
				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
				(uint32_t)CTrsp->ReasonCode,
				(uint32_t)CTrsp->Explanation);
			}
		} else {
			/* NameServer Rsp Error */
			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
					 "4109 NameServer Rsp Error "
					 "Data: x%x x%x x%x x%x\n",
					 CTrsp->CommandResponse.bits.CmdRsp,
					 (uint32_t)CTrsp->ReasonCode,
					 (uint32_t)CTrsp->Explanation,
					 vport->fc_flag);

			lpfc_debugfs_disc_trc(
				vport, LPFC_DISC_TRC_CT,
				"GID_PT rsp err2  cmd:x%x rsn:x%x exp:x%x",
				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
				(uint32_t)CTrsp->ReasonCode,
				(uint32_t)CTrsp->Explanation);
		}
		vport->gidft_inp--;
	}
	/* Link up / RSCN discovery */
	if ((vport->num_disc_nodes == 0) &&
	    (vport->gidft_inp == 0)) {
		/*
		 * The driver has cycled through all Nports in the RSCN payload.
		 * Complete the handling by cleaning up and marking the
		 * current driver state.
		 */
		if (vport->port_state >= LPFC_DISC_AUTH) {
			if (vport->fc_flag & FC_RSCN_MODE) {
				lpfc_els_flush_rscn(vport);
				spin_lock_irq(shost->host_lock);
				vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
				spin_unlock_irq(shost->host_lock);
			} else {
				lpfc_els_flush_rscn(vport);
			}
		}

		lpfc_disc_start(vport);
	}
out:
	cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
	lpfc_ct_free_iocb(phba, cmdiocb);
}

static void
lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			struct lpfc_iocbq *rspiocb)
@@ -1365,6 +1557,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
	bpl->tus.f.bdeFlags = 0;
	if (cmdcode == SLI_CTNS_GID_FT)
		bpl->tus.f.bdeSize = GID_REQUEST_SZ;
	else if (cmdcode == SLI_CTNS_GID_PT)
		bpl->tus.f.bdeSize = GID_REQUEST_SZ;
	else if (cmdcode == SLI_CTNS_GFF_ID)
		bpl->tus.f.bdeSize = GFF_REQUEST_SZ;
	else if (cmdcode == SLI_CTNS_GFT_ID)
@@ -1405,6 +1599,18 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
		rsp_size = FC_MAX_NS_RSP;
		break;

	case SLI_CTNS_GID_PT:
		CtReq->CommandResponse.bits.CmdRsp =
		    cpu_to_be16(SLI_CTNS_GID_PT);
		CtReq->un.gid.PortType = context;

		if (vport->port_state < LPFC_NS_QRY)
			vport->port_state = LPFC_NS_QRY;
		lpfc_set_disctmo(vport);
		cmpl = lpfc_cmpl_ct_cmd_gid_pt;
		rsp_size = FC_MAX_NS_RSP;
		break;

	case SLI_CTNS_GFF_ID:
		CtReq->CommandResponse.bits.CmdRsp =
			cpu_to_be16(SLI_CTNS_GFF_ID);
+9 −1
Original line number Diff line number Diff line
@@ -6371,6 +6371,7 @@ int
lpfc_els_handle_rscn(struct lpfc_vport *vport)
{
	struct lpfc_nodelist *ndlp;
	struct lpfc_hba  *phba = vport->phba;

	/* Ignore RSCN if the port is being torn down. */
	if (vport->load_flag & FC_UNLOADING) {
@@ -6399,8 +6400,15 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
		 * flush the RSCN.  Otherwise, the outstanding requests
		 * need to complete.
		 */
		if (phba->cfg_ns_query == LPFC_NS_QUERY_GID_FT) {
			if (lpfc_issue_gidft(vport) > 0)
				return 1;
		} else if (phba->cfg_ns_query == LPFC_NS_QUERY_GID_PT) {
			if (lpfc_issue_gidpt(vport) > 0)
				return 1;
		} else {
			return 1;
		}
	} else {
		/* Nameserver login in question.  Revalidate. */
		if (ndlp) {
Loading