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

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

scsi: lpfc: NVME Initiator: Merge into FC discovery



NVME Initiator: Merge into FC discovery

Adds NVME PRLI support and Nameserver registrations and Queries for NVME

Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <james.smart@broadcom.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 895427bd
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -123,6 +123,8 @@ struct perf_prof {
	uint16_t wqidx[40];
};

#define LPFC_FC4_TYPE_BITMASK	0x00000100

/* Provide DMA memory definitions the driver uses per port instance. */
struct lpfc_dmabuf {
	struct list_head list;
@@ -391,6 +393,7 @@ struct lpfc_vport {
	uint8_t fc_linkspeed;	/* Link speed after last READ_LA */

	uint32_t num_disc_nodes;	/* in addition to hba_state */
	uint32_t gidft_inp;		/* cnt of outstanding GID_FTs */

	uint32_t fc_nlp_cnt;	/* outstanding NODELIST requests */
	uint32_t fc_rscn_id_cnt;	/* count of RSCNs payloads in list */
@@ -443,7 +446,6 @@ struct lpfc_vport {
	uint32_t cfg_max_scsicmpl_time;
	uint32_t cfg_tgt_queue_depth;
	uint32_t cfg_first_burst_size;

	uint32_t dev_loss_tmo_changed;

	struct fc_vport *fc_vport;
+232 −125
Original line number Diff line number Diff line
@@ -40,8 +40,9 @@
#include "lpfc_sli4.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h"
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_scsi.h"
#include "lpfc_nvme.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
#include "lpfc_version.h"
@@ -453,8 +454,73 @@ lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {
	return NULL;
}

static void
lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type)
{
	struct lpfc_nodelist *ndlp;

	if ((vport->port_type != LPFC_NPIV_PORT) ||
	    !(vport->ct_flags & FC_CT_RFF_ID) || !vport->cfg_restrict_login) {

		ndlp = lpfc_setup_disc_node(vport, Did);

		if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
			/* By default, the driver expects to support FCP FC4 */
			if (fc4_type == FC_TYPE_FCP)
				ndlp->nlp_fc4_type |= NLP_FC4_FCP;

			if (fc4_type == FC_TYPE_NVME)
				ndlp->nlp_fc4_type |= NLP_FC4_NVME;

			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
					 "0238 Process x%06x NameServer Rsp "
					 "Data: x%x x%x x%x x%x\n", Did,
					 ndlp->nlp_flag, ndlp->nlp_fc4_type,
					 vport->fc_flag,
					 vport->fc_rscn_id_cnt);
		} else
			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
					 "0239 Skip x%06x NameServer Rsp "
					 "Data: x%x x%x\n", Did,
					 vport->fc_flag,
					 vport->fc_rscn_id_cnt);

	} else {
		if (!(vport->fc_flag & FC_RSCN_MODE) ||
		    lpfc_rscn_payload_check(vport, Did)) {
			/*
			 * This NPortID was previously a FCP target,
			 * Don't even bother to send GFF_ID.
			 */
			ndlp = lpfc_findnode_did(vport, Did);
			if (ndlp && NLP_CHK_NODE_ACT(ndlp))
				ndlp->nlp_fc4_type = fc4_type;

			if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
				ndlp->nlp_fc4_type = fc4_type;

				if (ndlp->nlp_type & NLP_FCP_TARGET)
					lpfc_setup_disc_node(vport, Did);

				else if (lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
							0, Did) == 0)
					vport->num_disc_nodes++;

				else
					lpfc_setup_disc_node(vport, Did);
			}
		} else
			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
					 "0245 Skip x%06x NameServer Rsp "
					 "Data: x%x x%x\n", Did,
					 vport->fc_flag,
					 vport->fc_rscn_id_cnt);
	}
}

static int
lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint8_t fc4_type,
	    uint32_t Size)
{
	struct lpfc_hba  *phba = vport->phba;
	struct lpfc_sli_ct_request *Response =
@@ -499,97 +565,12 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
			 */
			if ((Did != vport->fc_myDID) &&
			    ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
			     vport->cfg_peer_port_login)) {
				if ((vport->port_type != LPFC_NPIV_PORT) ||
				    (!(vport->ct_flags & FC_CT_RFF_ID)) ||
				    (!vport->cfg_restrict_login)) {
					ndlp = lpfc_setup_disc_node(vport, Did);
					if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
						lpfc_debugfs_disc_trc(vport,
						LPFC_DISC_TRC_CT,
						"Parse GID_FTrsp: "
						"did:x%x flg:x%x x%x",
						Did, ndlp->nlp_flag,
						vport->fc_flag);
			     vport->cfg_peer_port_login))
				lpfc_prep_node_fc4type(vport, Did, fc4_type);

						lpfc_printf_vlog(vport,
							KERN_INFO,
							LOG_DISCOVERY,
							"0238 Process "
							"x%x NameServer Rsp"
							"Data: x%x x%x x%x\n",
							Did, ndlp->nlp_flag,
							vport->fc_flag,
							vport->fc_rscn_id_cnt);
					} else {
						lpfc_debugfs_disc_trc(vport,
						LPFC_DISC_TRC_CT,
						"Skip1 GID_FTrsp: "
						"did:x%x flg:x%x cnt:%d",
						Did, vport->fc_flag,
						vport->fc_rscn_id_cnt);

						lpfc_printf_vlog(vport,
							KERN_INFO,
							LOG_DISCOVERY,
							"0239 Skip x%x "
							"NameServer Rsp Data: "
							"x%x x%x\n",
							Did, vport->fc_flag,
							vport->fc_rscn_id_cnt);
					}

				} else {
					if (!(vport->fc_flag & FC_RSCN_MODE) ||
					(lpfc_rscn_payload_check(vport, Did))) {
						lpfc_debugfs_disc_trc(vport,
						LPFC_DISC_TRC_CT,
						"Query GID_FTrsp: "
						"did:x%x flg:x%x cnt:%d",
						Did, vport->fc_flag,
						vport->fc_rscn_id_cnt);

						/* This NPortID was previously
						 * a FCP target, * Don't even
						 * bother to send GFF_ID.
						 */
						ndlp = lpfc_findnode_did(vport,
							Did);
						if (ndlp &&
						    NLP_CHK_NODE_ACT(ndlp)
						    && (ndlp->nlp_type &
						     NLP_FCP_TARGET))
							lpfc_setup_disc_node
								(vport, Did);
						else if (lpfc_ns_cmd(vport,
							SLI_CTNS_GFF_ID,
							0, Did) == 0)
							vport->num_disc_nodes++;
						else
							lpfc_setup_disc_node
								(vport, Did);
					}
					else {
						lpfc_debugfs_disc_trc(vport,
						LPFC_DISC_TRC_CT,
						"Skip2 GID_FTrsp: "
						"did:x%x flg:x%x cnt:%d",
						Did, vport->fc_flag,
						vport->fc_rscn_id_cnt);

						lpfc_printf_vlog(vport,
							KERN_INFO,
							LOG_DISCOVERY,
							"0245 Skip x%x "
							"NameServer Rsp Data: "
							"x%x x%x\n",
							Did, vport->fc_flag,
							vport->fc_rscn_id_cnt);
					}
				}
			}
			if (CTentry & (cpu_to_be32(SLI_CT_LAST_ENTRY)))
				goto nsout1;

			Cnt -= sizeof(uint32_t);
		}
		ctptr = NULL;
@@ -609,16 +590,18 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	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;
	int rc, type;

	/* 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;

@@ -656,9 +639,14 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			    IOERR_NO_RESOURCES)
				vport->fc_ns_retry++;

			type = lpfc_get_gidft_type(vport, cmdiocb);
			if (type == 0)
				goto out;

			/* CT command is being retried */
			vport->gidft_inp--;
			rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
					 vport->fc_ns_retry, 0);
					 vport->fc_ns_retry, type);
			if (rc == 0)
				goto out;
		}
@@ -670,13 +658,18 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
				 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,
					 "0208 NameServer Rsp Data: x%x\n",
					 vport->fc_flag);
			lpfc_ns_rsp(vport, outp,
					 "0208 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)) {
@@ -731,9 +724,11 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
				(uint32_t) CTrsp->ReasonCode,
				(uint32_t) CTrsp->Explanation);
		}
		vport->gidft_inp--;
	}
	/* Link up / RSCN discovery */
	if (vport->num_disc_nodes == 0) {
	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
@@ -881,6 +876,56 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	return;
}

static void
lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
				struct lpfc_iocbq *rspiocb)
{
	struct lpfc_vport *vport = cmdiocb->vport;
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *)cmdiocb->context1;
	struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *)cmdiocb->context2;
	struct lpfc_sli_ct_request *CTrsp;
	int did;
	struct lpfc_nodelist *ndlp;
	uint32_t fc4_data_0, fc4_data_1;

	did = ((struct lpfc_sli_ct_request *)inp->virt)->un.gft.PortId;
	did = be32_to_cpu(did);

	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		/* Good status, continue checking */
		CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
		fc4_data_0 = be32_to_cpu(CTrsp->un.gft_acc.fc4_types[0]);
		fc4_data_1 = be32_to_cpu(CTrsp->un.gft_acc.fc4_types[1]);
		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
				 "3062 DID x%06x GFT Wd0 x%08x Wd1 x%08x\n",
				 did, fc4_data_0, fc4_data_1);

		ndlp = lpfc_findnode_did(vport, did);
		if (ndlp) {
			/* The bitmask value for FCP and NVME FCP types is
			 * the same because they are 32 bits distant from
			 * each other in word0 and word0.
			 */
			if (fc4_data_0 & LPFC_FC4_TYPE_BITMASK)
				ndlp->nlp_fc4_type |= NLP_FC4_FCP;
			if (fc4_data_1 &  LPFC_FC4_TYPE_BITMASK)
				ndlp->nlp_fc4_type |= NLP_FC4_NVME;
			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
					 "3064 Setting ndlp %p, DID x%06x with "
					 "FC4 x%08x, Data: x%08x x%08x\n",
					 ndlp, did, ndlp->nlp_fc4_type,
					 FC_TYPE_FCP, FC_TYPE_NVME);
		}
		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
		lpfc_issue_els_prli(vport, ndlp, 0);
	} else
		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
				 "3065 GFT_ID failed x%08x\n", irsp->ulpStatus);

	lpfc_ct_free_iocb(phba, cmdiocb);
}

static void
lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
@@ -1071,31 +1116,27 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	return;
}

/*
 * Although the symbolic port name is thought to be an integer
 * as of January 18, 2016, leave it as a string until more of
 * the record state becomes defined.
 */
int
lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
	size_t size)
{
	int n;
	uint8_t *wwn = vport->phba->wwpn;

	n = snprintf(symbol, size,
		     "Emulex PPN-%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
		     wwn[0], wwn[1], wwn[2], wwn[3],
		     wwn[4], wwn[5], wwn[6], wwn[7]);

	if (vport->port_type == LPFC_PHYSICAL_PORT)
		return n;

	if (n < size)
		n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi);

	if (n < size &&
	    strlen(vport->fc_vport->symbolic_name))
		n += snprintf(symbol + n, size - n, " VName-%s",
			      vport->fc_vport->symbolic_name);
	/*
	 * Use the lpfc board number as the Symbolic Port
	 * Name object.  NPIV is not in play so this integer
	 * value is sufficient and unique per FC-ID.
	 */
	n = snprintf(symbol, size, "%d", vport->phba->brd_no);
	return n;
}


int
lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
	size_t size)
@@ -1106,24 +1147,26 @@ lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
	lpfc_decode_firmware_rev(vport->phba, fwrev, 0);

	n = snprintf(symbol, size, "Emulex %s", vport->phba->ModelName);

	if (size < n)
		return n;
	n += snprintf(symbol + n, size - n, " FV%s", fwrev);

	n += snprintf(symbol + n, size - n, " FV%s", fwrev);
	if (size < n)
		return n;
	n += snprintf(symbol + n, size - n, " DV%s", lpfc_release_version);

	n += snprintf(symbol + n, size - n, " DV%s.",
		      lpfc_release_version);
	if (size < n)
		return n;
	n += snprintf(symbol + n, size - n, " HN:%s", init_utsname()->nodename);

	/* Note :- OS name is "Linux" */
	n += snprintf(symbol + n, size - n, " HN:%s.",
		      init_utsname()->nodename);
	if (size < n)
		return n;
	n += snprintf(symbol + n, size - n, " OS:%s", init_utsname()->sysname);

	/* Note :- OS name is "Linux" */
	n += snprintf(symbol + n, size - n, " OS:%s\n",
		      init_utsname()->sysname);
	return n;
}

@@ -1147,6 +1190,27 @@ lpfc_find_map_node(struct lpfc_vport *vport)
	return cnt;
}

/*
 * This routine will return the FC4 Type associated with the CT
 * GID_FT command.
 */
int
lpfc_get_gidft_type(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb)
{
	struct lpfc_sli_ct_request *CtReq;
	struct lpfc_dmabuf *mp;
	uint32_t type;

	mp = cmdiocb->context1;
	if (mp == NULL)
		return 0;
	CtReq = (struct lpfc_sli_ct_request *)mp->virt;
	type = (uint32_t)CtReq->un.gid.Fc4Type;
	if ((type != SLI_CTPT_FCP) && (type != SLI_CTPT_NVME))
		return 0;
	return type;
}

/*
 * lpfc_ns_cmd
 * Description:
@@ -1207,8 +1271,9 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,

	/* NameServer Req */
	lpfc_printf_vlog(vport, KERN_INFO ,LOG_DISCOVERY,
			 "0236 NameServer Req Data: x%x x%x x%x\n",
			 cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt);
			 "0236 NameServer Req Data: x%x x%x x%x x%x\n",
			 cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt,
			 context);

	bpl = (struct ulp_bde64 *) bmp->virt;
	memset(bpl, 0, sizeof(struct ulp_bde64));
@@ -1219,6 +1284,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
		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)
		bpl->tus.f.bdeSize = GFT_REQUEST_SZ;
	else if (cmdcode == SLI_CTNS_RFT_ID)
		bpl->tus.f.bdeSize = RFT_REQUEST_SZ;
	else if (cmdcode == SLI_CTNS_RNN_ID)
@@ -1246,7 +1313,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
	case SLI_CTNS_GID_FT:
		CtReq->CommandResponse.bits.CmdRsp =
		    cpu_to_be16(SLI_CTNS_GID_FT);
		CtReq->un.gid.Fc4Type = SLI_CTPT_FCP;
		CtReq->un.gid.Fc4Type = context;

		if (vport->port_state < LPFC_NS_QRY)
			vport->port_state = LPFC_NS_QRY;
		lpfc_set_disctmo(vport);
@@ -1261,12 +1329,32 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
		cmpl = lpfc_cmpl_ct_cmd_gff_id;
		break;

	case SLI_CTNS_GFT_ID:
		CtReq->CommandResponse.bits.CmdRsp =
			cpu_to_be16(SLI_CTNS_GFT_ID);
		CtReq->un.gft.PortId = cpu_to_be32(context);
		cmpl = lpfc_cmpl_ct_cmd_gft_id;
		break;

	case SLI_CTNS_RFT_ID:
		vport->ct_flags &= ~FC_CT_RFT_ID;
		CtReq->CommandResponse.bits.CmdRsp =
		    cpu_to_be16(SLI_CTNS_RFT_ID);
		CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);

		/* Register FC4 FCP type if enabled.  */
		if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
		    (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP))
			CtReq->un.rft.fcpReg = 1;

		/* Register NVME type if enabled.  Defined LE and swapped.
		 * rsvd[0] is used as word1 because of the hard-coded
		 * word0 usage in the ct_request data structure.
		 */
		if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
		    (phba->cfg_enable_fc4_type == LPFC_ENABLE_NVME))
			CtReq->un.rft.rsvd[0] = cpu_to_be32(0x00000100);

		cmpl = lpfc_cmpl_ct_cmd_rft_id;
		break;

@@ -1316,7 +1404,25 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
		    cpu_to_be16(SLI_CTNS_RFF_ID);
		CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);
		CtReq->un.rff.fbits = FC4_FEATURE_INIT;
		CtReq->un.rff.type_code = FC_TYPE_FCP;

		/* The driver always supports FC_TYPE_FCP.  However, the
		 * caller can specify NVME (type x28) as well.  But only
		 * these that FC4 type is supported.
		 */
		if (((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
		     (phba->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) &&
		    (context == FC_TYPE_NVME)) {
			/* todo: init: revise localport nvme attributes */
			CtReq->un.rff.type_code = context;

		} else if (((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
			    (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP)) &&
			   (context == FC_TYPE_FCP))
			CtReq->un.rff.type_code = context;

		else
			goto ns_cmd_free_bmpvirt;

		cmpl = lpfc_cmpl_ct_cmd_rff_id;
		break;
	}
@@ -1337,6 +1443,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
	 */
	lpfc_nlp_put(ndlp);

ns_cmd_free_bmpvirt:
	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
ns_cmd_free_bmp:
	kfree(bmp);
+17 −2
Original line number Diff line number Diff line
@@ -86,6 +86,17 @@ struct lpfc_nodelist {
#define NLP_FABRIC         0x4			/* entry rep a Fabric entity */
#define NLP_FCP_TARGET     0x8			/* entry is an FCP target */
#define NLP_FCP_INITIATOR  0x10			/* entry is an FCP Initiator */
#define NLP_NVME_TARGET    0x20			/* entry is a NVME Target */
#define NLP_NVME_INITIATOR 0x40			/* entry is a NVME Initiator */

	uint16_t	nlp_fc4_type;		/* FC types node supports. */
						/* Assigned from GID_FF, only
						 * FCP (0x8) and NVME (0x28)
						 * supported.
						 */
#define NLP_FC4_NONE	0x0
#define NLP_FC4_FCP	0x1			/* FC4 Type FCP (value x8)) */
#define NLP_FC4_NVME	0x2			/* FC4 TYPE NVME (value x28) */

	uint16_t        nlp_rpi;
	uint16_t        nlp_state;		/* state transition indicator */
@@ -107,8 +118,8 @@ struct lpfc_nodelist {

	struct timer_list   nlp_delayfunc;	/* Used for delayed ELS cmds */
	struct lpfc_hba *phba;
	struct fc_rport *rport;			/* Corresponding FC transport
						   port structure */
	struct fc_rport *rport;		/* scsi_transport_fc port structure */
	struct lpfc_nvme_rport *nrport;	/* nvme transport rport struct. */
	struct lpfc_vport *vport;
	struct lpfc_work_evt els_retry_evt;
	struct lpfc_work_evt dev_loss_evt;
@@ -118,6 +129,10 @@ struct lpfc_nodelist {
	unsigned long last_change_time;
	unsigned long *active_rrqs_xri_bitmap;
	struct lpfc_scsicmd_bkt *lat_data;	/* Latency data */
	uint32_t fc4_prli_sent;
	uint32_t upcall_flags;
	uint32_t nvme_fb_size; /* NVME target's supported byte cnt */
#define NVME_FB_BIT_SHIFT 9    /* PRLI Rsp first burst in 512B units. */
};
struct lpfc_node_rrq {
	struct list_head list;
+203 −77

File changed.

Preview size limit exceeded, changes collapsed.

+136 −33
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/fc/fc_fs.h>

#include <linux/nvme-fc-driver.h>

#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -38,8 +41,9 @@
#include "lpfc_disc.h"
#include "lpfc_sli.h"
#include "lpfc_sli4.h"
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_scsi.h"
#include "lpfc_nvme.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
#include "lpfc_vport.h"
@@ -853,9 +857,12 @@ lpfc_port_link_failure(struct lpfc_vport *vport)
void
lpfc_linkdown_port(struct lpfc_vport *vport)
{
	struct lpfc_hba  *phba = vport->phba;
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);

	fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
	if (phba->cfg_enable_fc4_type != LPFC_ENABLE_NVME)
		fc_host_post_event(shost, fc_get_event_number(),
				   FCH_EVT_LINKDOWN, 0);

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
		"Link Down:       state:x%x rtry:x%x flg:x%x",
@@ -981,7 +988,9 @@ lpfc_linkup_port(struct lpfc_vport *vport)
		(vport != phba->pport))
		return;

	fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKUP, 0);
	if (phba->cfg_enable_fc4_type != LPFC_ENABLE_NVME)
		fc_host_post_event(shost, fc_get_event_number(),
				   FCH_EVT_LINKUP, 0);

	spin_lock_irq(shost->host_lock);
	vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
@@ -3570,6 +3579,8 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
		vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
		spin_unlock_irq(shost->host_lock);
		vport->fc_myDID = 0;

		/* todo: init: revise localport nvme attributes */
		goto out;
	}

@@ -3819,6 +3830,52 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
	return;
}

 /*
  * This routine will issue a GID_FT for each FC4 Type supported
  * by the driver. ALL GID_FTs must complete before discovery is started.
  */
int
lpfc_issue_gidft(struct lpfc_vport *vport)
{
	struct lpfc_hba *phba = vport->phba;

	/* Good status, issue CT Request to NameServer */
	if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
	    (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP)) {
		if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, SLI_CTPT_FCP)) {
			/* Cannot issue NameServer FCP Query, so finish up
			 * discovery
			 */
			lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI,
					 "0604 %s FC TYPE %x %s\n",
					 "Failed to issue GID_FT to ",
					 FC_TYPE_FCP,
					 "Finishing discovery.");
			return 0;
		}
		vport->gidft_inp++;
	}

	if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
	    (phba->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
		if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, SLI_CTPT_NVME)) {
			/* Cannot issue NameServer NVME Query, so finish up
			 * discovery
			 */
			lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI,
					 "0605 %s FC_TYPE %x %s %d\n",
					 "Failed to issue GID_FT to ",
					 FC_TYPE_NVME,
					 "Finishing discovery: gidftinp ",
					 vport->gidft_inp);
			if (vport->gidft_inp == 0)
				return 0;
		} else
			vport->gidft_inp++;
	}
	return vport->gidft_inp;
}

/*
 * This routine handles processing a NameServer REG_LOGIN mailbox
 * command upon completion. It is setup in the LPFC_MBOXQ
@@ -3835,12 +3892,14 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)

	pmb->context1 = NULL;
	pmb->context2 = NULL;
	vport->gidft_inp = 0;

	if (mb->mbxStatus) {
out:
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0260 Register NameServer error: 0x%x\n",
				 mb->mbxStatus);

out:
		/* decrement the node reference count held for this
		 * callback function.
		 */
@@ -3884,20 +3943,28 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
		lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0);
		lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0);
		lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0);
		lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, 0);

		if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
		    (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP))
			lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, FC_TYPE_FCP);

		if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
		    (phba->cfg_enable_fc4_type == LPFC_ENABLE_NVME))
			lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, FC_TYPE_NVME);

		/* Issue SCR just before NameServer GID_FT Query */
		lpfc_issue_els_scr(vport, SCR_DID, 0);
	}

	vport->fc_ns_retry = 0;
	/* Good status, issue CT Request to NameServer */
	if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0)) {
		/* Cannot issue NameServer Query, so finish up discovery */
	if (lpfc_issue_gidft(vport) == 0)
		goto out;
	}

	/* decrement the node reference count held for this
	/*
	 * At this point in time we may need to wait for multiple
	 * SLI_CTNS_GID_FT CT commands to complete before we start discovery.
	 *
	 * decrement the node reference count held for this
	 * callback function.
	 */
	lpfc_nlp_put(ndlp);
@@ -3990,6 +4057,10 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp)
{
	struct fc_rport *rport = ndlp->rport;
	struct lpfc_vport *vport = ndlp->vport;
	struct lpfc_hba  *phba = vport->phba;

	if (phba->cfg_enable_fc4_type == LPFC_ENABLE_NVME)
		return;

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
		"rport delete:    did:x%x flg:x%x type x%x",
@@ -4047,6 +4118,7 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		       int old_state, int new_state)
{
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba *phba = vport->phba;

	if (new_state == NLP_STE_UNMAPPED_NODE) {
		ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
@@ -4057,23 +4129,51 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	if (new_state == NLP_STE_NPR_NODE)
		ndlp->nlp_flag &= ~NLP_RCV_PLOGI;

	/* Transport interface */
	if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE ||
	/* FCP and NVME Transport interface */
	if ((old_state == NLP_STE_MAPPED_NODE ||
	     old_state == NLP_STE_UNMAPPED_NODE)) {
		if (ndlp->rport) {
			vport->phba->nport_event_cnt++;
			lpfc_unregister_remote_port(ndlp);
		}

		/* Notify the NVME transport of this rport's loss */
		if (((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
		     (phba->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) &&
		    (vport->phba->nvmet_support == 0) &&
		    ((ndlp->nlp_fc4_type & NLP_FC4_NVME) ||
		    (ndlp->nlp_DID == Fabric_DID))) {
			vport->phba->nport_event_cnt++;
			/* todo: init: unregister rport from nvme */
		}
	}

	/* FCP and NVME Transport interfaces */

	if (new_state ==  NLP_STE_MAPPED_NODE ||
	    new_state == NLP_STE_UNMAPPED_NODE) {
		if ((ndlp->nlp_fc4_type & NLP_FC4_FCP) ||
		    (ndlp->nlp_DID == Fabric_DID)) {
			vport->phba->nport_event_cnt++;
			/*
			 * Tell the fc transport about the port, if we haven't
			 * already. If we have, and it's a scsi entity, be
		 * sure to unblock any attached scsi devices
			 */
			lpfc_register_remote_port(vport, ndlp);
		}
		/* Notify the NVME transport of this new rport. */
		if (ndlp->nlp_fc4_type & NLP_FC4_NVME) {
			if (vport->phba->nvmet_support == 0) {
				/* Register this rport with the transport.
				 * Initiators take the NDLP ref count in
				 * the register.
				 */
				vport->phba->nport_event_cnt++;
				/* todo: init: register rport with nvme */
			}
		}
	}

	if ((new_state ==  NLP_STE_MAPPED_NODE) &&
		(vport->stat_data_enabled)) {
		/*
@@ -4091,12 +4191,13 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
				"0x%x\n", ndlp->nlp_DID);
	}
	/*
	 * if we added to Mapped list, but the remote port
	 * registration failed or assigned a target id outside
	 * our presentable range - move the node to the
	 * Unmapped List
	 * If the node just added to Mapped list was an FCP target,
	 * but the remote port registration failed or assigned a target
	 * id outside the presentable range - move the node to the
	 * Unmapped List.
	 */
	if (new_state == NLP_STE_MAPPED_NODE &&
	if ((new_state == NLP_STE_MAPPED_NODE) &&
	    (ndlp->nlp_type & NLP_FCP_TARGET) &&
	    (!ndlp->rport ||
	     ndlp->rport->scsi_target_id == -1 ||
	     ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
@@ -4230,6 +4331,7 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	ndlp->vport = vport;
	ndlp->phba = vport->phba;
	ndlp->nlp_sid = NLP_NO_SID;
	ndlp->nlp_fc4_type = NLP_FC4_NONE;
	kref_init(&ndlp->kref);
	NLP_INT_NODE_ACT(ndlp);
	atomic_set(&ndlp->cmd_pending, 0);
@@ -5369,12 +5471,13 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
	switch (vport->port_state) {

	case LPFC_LOCAL_CFG_LINK:
	/* port_state is identically  LPFC_LOCAL_CFG_LINK while waiting for
	 * FAN
		/*
		 * port_state is identically  LPFC_LOCAL_CFG_LINK while
		 * waiting for FAN timeout
		 */
				/* FAN timeout */
		lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY,
				 "0221 FAN timeout\n");

		/* Start discovery by sending FLOGI, clean up old rpis */
		list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
					 nlp_listp) {
@@ -5445,8 +5548,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
			/* Try it one more time */
			vport->fc_ns_retry++;
			rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
					 vport->fc_ns_retry, 0);
			vport->gidft_inp = 0;
			rc = lpfc_issue_gidft(vport);
			if (rc == 0)
				break;
		}
Loading