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

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
...@@ -123,6 +123,8 @@ struct perf_prof { ...@@ -123,6 +123,8 @@ struct perf_prof {
uint16_t wqidx[40]; uint16_t wqidx[40];
}; };
#define LPFC_FC4_TYPE_BITMASK 0x00000100
/* Provide DMA memory definitions the driver uses per port instance. */ /* Provide DMA memory definitions the driver uses per port instance. */
struct lpfc_dmabuf { struct lpfc_dmabuf {
struct list_head list; struct list_head list;
...@@ -390,7 +392,8 @@ struct lpfc_vport { ...@@ -390,7 +392,8 @@ struct lpfc_vport {
int32_t stopped; /* HBA has not been restarted since last ERATT */ int32_t stopped; /* HBA has not been restarted since last ERATT */
uint8_t fc_linkspeed; /* Link speed after last READ_LA */ uint8_t fc_linkspeed; /* Link speed after last READ_LA */
uint32_t num_disc_nodes; /*in addition to hba_state */ 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_nlp_cnt; /* outstanding NODELIST requests */
uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */ uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */
...@@ -443,7 +446,6 @@ struct lpfc_vport { ...@@ -443,7 +446,6 @@ struct lpfc_vport {
uint32_t cfg_max_scsicmpl_time; uint32_t cfg_max_scsicmpl_time;
uint32_t cfg_tgt_queue_depth; uint32_t cfg_tgt_queue_depth;
uint32_t cfg_first_burst_size; uint32_t cfg_first_burst_size;
uint32_t dev_loss_tmo_changed; uint32_t dev_loss_tmo_changed;
struct fc_vport *fc_vport; struct fc_vport *fc_vport;
......
This diff is collapsed.
...@@ -86,6 +86,17 @@ struct lpfc_nodelist { ...@@ -86,6 +86,17 @@ struct lpfc_nodelist {
#define NLP_FABRIC 0x4 /* entry rep a Fabric entity */ #define NLP_FABRIC 0x4 /* entry rep a Fabric entity */
#define NLP_FCP_TARGET 0x8 /* entry is an FCP target */ #define NLP_FCP_TARGET 0x8 /* entry is an FCP target */
#define NLP_FCP_INITIATOR 0x10 /* entry is an FCP Initiator */ #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_rpi;
uint16_t nlp_state; /* state transition indicator */ uint16_t nlp_state; /* state transition indicator */
...@@ -107,8 +118,8 @@ struct lpfc_nodelist { ...@@ -107,8 +118,8 @@ struct lpfc_nodelist {
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
struct lpfc_hba *phba; struct lpfc_hba *phba;
struct fc_rport *rport; /* Corresponding FC transport struct fc_rport *rport; /* scsi_transport_fc port structure */
port structure */ struct lpfc_nvme_rport *nrport; /* nvme transport rport struct. */
struct lpfc_vport *vport; struct lpfc_vport *vport;
struct lpfc_work_evt els_retry_evt; struct lpfc_work_evt els_retry_evt;
struct lpfc_work_evt dev_loss_evt; struct lpfc_work_evt dev_loss_evt;
...@@ -118,6 +129,10 @@ struct lpfc_nodelist { ...@@ -118,6 +129,10 @@ struct lpfc_nodelist {
unsigned long last_change_time; unsigned long last_change_time;
unsigned long *active_rrqs_xri_bitmap; unsigned long *active_rrqs_xri_bitmap;
struct lpfc_scsicmd_bkt *lat_data; /* Latency data */ 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 lpfc_node_rrq {
struct list_head list; struct list_head list;
......
This diff is collapsed.
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
#include <scsi/scsi_device.h> #include <scsi/scsi_device.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.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_hw4.h"
#include "lpfc_hw.h" #include "lpfc_hw.h"
...@@ -38,8 +41,9 @@ ...@@ -38,8 +41,9 @@
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_sli.h" #include "lpfc_sli.h"
#include "lpfc_sli4.h" #include "lpfc_sli4.h"
#include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
#include "lpfc_scsi.h"
#include "lpfc_nvme.h"
#include "lpfc_logmsg.h" #include "lpfc_logmsg.h"
#include "lpfc_crtn.h" #include "lpfc_crtn.h"
#include "lpfc_vport.h" #include "lpfc_vport.h"
...@@ -853,9 +857,12 @@ lpfc_port_link_failure(struct lpfc_vport *vport) ...@@ -853,9 +857,12 @@ lpfc_port_link_failure(struct lpfc_vport *vport)
void void
lpfc_linkdown_port(struct lpfc_vport *vport) lpfc_linkdown_port(struct lpfc_vport *vport)
{ {
struct lpfc_hba *phba = vport->phba;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 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, lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
"Link Down: state:x%x rtry:x%x flg:x%x", "Link Down: state:x%x rtry:x%x flg:x%x",
...@@ -981,7 +988,9 @@ lpfc_linkup_port(struct lpfc_vport *vport) ...@@ -981,7 +988,9 @@ lpfc_linkup_port(struct lpfc_vport *vport)
(vport != phba->pport)) (vport != phba->pport))
return; 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); spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY | 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) ...@@ -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); vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
vport->fc_myDID = 0; vport->fc_myDID = 0;
/* todo: init: revise localport nvme attributes */
goto out; goto out;
} }
...@@ -3819,6 +3830,52 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ...@@ -3819,6 +3830,52 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
return; 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 * This routine handles processing a NameServer REG_LOGIN mailbox
* command upon completion. It is setup in the LPFC_MBOXQ * 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) ...@@ -3835,12 +3892,14 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
pmb->context1 = NULL; pmb->context1 = NULL;
pmb->context2 = NULL; pmb->context2 = NULL;
vport->gidft_inp = 0;
if (mb->mbxStatus) { if (mb->mbxStatus) {
out:
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"0260 Register NameServer error: 0x%x\n", "0260 Register NameServer error: 0x%x\n",
mb->mbxStatus); mb->mbxStatus);
out:
/* decrement the node reference count held for this /* decrement the node reference count held for this
* callback function. * callback function.
*/ */
...@@ -3884,20 +3943,28 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ...@@ -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_RSNN_NN, 0, 0);
lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 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_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 */ /* Issue SCR just before NameServer GID_FT Query */
lpfc_issue_els_scr(vport, SCR_DID, 0); lpfc_issue_els_scr(vport, SCR_DID, 0);
} }
vport->fc_ns_retry = 0; vport->fc_ns_retry = 0;
/* Good status, issue CT Request to NameServer */ if (lpfc_issue_gidft(vport) == 0)
if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0)) {
/* Cannot issue NameServer Query, so finish up discovery */
goto out; 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. * callback function.
*/ */
lpfc_nlp_put(ndlp); lpfc_nlp_put(ndlp);
...@@ -3990,6 +4057,10 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) ...@@ -3990,6 +4057,10 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp)
{ {
struct fc_rport *rport = ndlp->rport; struct fc_rport *rport = ndlp->rport;
struct lpfc_vport *vport = ndlp->vport; 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, lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
"rport delete: did:x%x flg:x%x type x%x", "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, ...@@ -4047,6 +4118,7 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int old_state, int new_state) int old_state, int new_state)
{ {
struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
if (new_state == NLP_STE_UNMAPPED_NODE) { if (new_state == NLP_STE_UNMAPPED_NODE) {
ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
...@@ -4057,23 +4129,51 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -4057,23 +4129,51 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (new_state == NLP_STE_NPR_NODE) if (new_state == NLP_STE_NPR_NODE)
ndlp->nlp_flag &= ~NLP_RCV_PLOGI; ndlp->nlp_flag &= ~NLP_RCV_PLOGI;
/* Transport interface */ /* FCP and NVME Transport interface */
if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE || if ((old_state == NLP_STE_MAPPED_NODE ||
old_state == NLP_STE_UNMAPPED_NODE)) { old_state == NLP_STE_UNMAPPED_NODE)) {
vport->phba->nport_event_cnt++; if (ndlp->rport) {
lpfc_unregister_remote_port(ndlp); 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 || if (new_state == NLP_STE_MAPPED_NODE ||
new_state == NLP_STE_UNMAPPED_NODE) { new_state == NLP_STE_UNMAPPED_NODE) {
vport->phba->nport_event_cnt++; if ((ndlp->nlp_fc4_type & NLP_FC4_FCP) ||
/* (ndlp->nlp_DID == Fabric_DID)) {
* Tell the fc transport about the port, if we haven't vport->phba->nport_event_cnt++;
* already. If we have, and it's a scsi entity, be /*
* sure to unblock any attached scsi devices * Tell the fc transport about the port, if we haven't
*/ * already. If we have, and it's a scsi entity, be
lpfc_register_remote_port(vport, ndlp); */
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) && if ((new_state == NLP_STE_MAPPED_NODE) &&
(vport->stat_data_enabled)) { (vport->stat_data_enabled)) {
/* /*
...@@ -4091,12 +4191,13 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -4091,12 +4191,13 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
"0x%x\n", ndlp->nlp_DID); "0x%x\n", ndlp->nlp_DID);
} }
/* /*
* if we added to Mapped list, but the remote port * If the node just added to Mapped list was an FCP target,
* registration failed or assigned a target id outside * but the remote port registration failed or assigned a target
* our presentable range - move the node to the * id outside the presentable range - move the node to the
* Unmapped List * 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 ||
ndlp->rport->scsi_target_id == -1 || ndlp->rport->scsi_target_id == -1 ||
ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) { ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
...@@ -4230,6 +4331,7 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -4230,6 +4331,7 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->vport = vport; ndlp->vport = vport;
ndlp->phba = vport->phba; ndlp->phba = vport->phba;
ndlp->nlp_sid = NLP_NO_SID; ndlp->nlp_sid = NLP_NO_SID;
ndlp->nlp_fc4_type = NLP_FC4_NONE;
kref_init(&ndlp->kref); kref_init(&ndlp->kref);
NLP_INT_NODE_ACT(ndlp); NLP_INT_NODE_ACT(ndlp);
atomic_set(&ndlp->cmd_pending, 0); atomic_set(&ndlp->cmd_pending, 0);
...@@ -5369,12 +5471,13 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) ...@@ -5369,12 +5471,13 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
switch (vport->port_state) { switch (vport->port_state) {
case LPFC_LOCAL_CFG_LINK: 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, lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY,
"0221 FAN timeout\n"); "0221 FAN timeout\n");
/* Start discovery by sending FLOGI, clean up old rpis */ /* Start discovery by sending FLOGI, clean up old rpis */
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) { nlp_listp) {
...@@ -5445,8 +5548,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) ...@@ -5445,8 +5548,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
/* Try it one more time */ /* Try it one more time */
vport->fc_ns_retry++; vport->fc_ns_retry++;
rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, vport->gidft_inp = 0;
vport->fc_ns_retry, 0); rc = lpfc_issue_gidft(vport);
if (rc == 0) if (rc == 0)
break; break;
} }
......
...@@ -90,8 +90,10 @@ union CtCommandResponse { ...@@ -90,8 +90,10 @@ union CtCommandResponse {
uint32_t word; uint32_t word;
}; };
#define FC4_FEATURE_INIT 0x2 /* FC4 Feature bits for RFF_ID */
#define FC4_FEATURE_TARGET 0x1 #define FC4_FEATURE_TARGET 0x1
#define FC4_FEATURE_INIT 0x2
#define FC4_FEATURE_NVME_DISC 0x4
struct lpfc_sli_ct_request { struct lpfc_sli_ct_request {
/* Structure is in Big Endian format */ /* Structure is in Big Endian format */
...@@ -115,6 +117,16 @@ struct lpfc_sli_ct_request { ...@@ -115,6 +117,16 @@ struct lpfc_sli_ct_request {
uint8_t AreaScope; uint8_t AreaScope;
uint8_t Fc4Type; /* for GID_FT requests */ uint8_t Fc4Type; /* for GID_FT requests */
} gid; } gid;
struct gid_ff {
uint8_t Flags;
uint8_t DomainScope;
uint8_t AreaScope;
uint8_t rsvd1;
uint8_t rsvd2;
uint8_t rsvd3;
uint8_t Fc4FBits;
uint8_t Fc4Type;
} gid_ff;
struct rft { struct rft {
uint32_t PortId; /* For RFT_ID requests */ uint32_t PortId; /* For RFT_ID requests */
...@@ -159,6 +171,12 @@ struct lpfc_sli_ct_request { ...@@ -159,6 +171,12 @@ struct lpfc_sli_ct_request {
struct gff_acc { struct gff_acc {
uint8_t fbits[128]; uint8_t fbits[128];
} gff_acc; } gff_acc;
struct gft {
uint32_t PortId;
} gft;
struct gft_acc {
uint32_t fc4_types[8];
} gft_acc;
#define FCP_TYPE_FEATURE_OFFSET 7 #define FCP_TYPE_FEATURE_OFFSET 7
struct rff { struct rff {
uint32_t PortId; uint32_t PortId;
...@@ -174,8 +192,12 @@ struct lpfc_sli_ct_request { ...@@ -174,8 +192,12 @@ struct lpfc_sli_ct_request {
#define SLI_CT_REVISION 1 #define SLI_CT_REVISION 1
#define GID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ #define GID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
sizeof(struct gid)) sizeof(struct gid))
#define GIDFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
sizeof(struct gid_ff))
#define GFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ #define GFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
sizeof(struct gff)) sizeof(struct gff))
#define GFT_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
sizeof(struct gft))
#define RFT_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ #define RFT_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
sizeof(struct rft)) sizeof(struct rft))
#define RFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ #define RFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
...@@ -271,6 +293,7 @@ struct lpfc_sli_ct_request { ...@@ -271,6 +293,7 @@ struct lpfc_sli_ct_request {
#define SLI_CTNS_GNN_IP 0x0153 #define SLI_CTNS_GNN_IP 0x0153
#define SLI_CTNS_GIPA_IP 0x0156 #define SLI_CTNS_GIPA_IP 0x0156
#define SLI_CTNS_GID_FT 0x0171 #define SLI_CTNS_GID_FT 0x0171
#define SLI_CTNS_GID_FF 0x01F1
#define SLI_CTNS_GID_PT 0x01A1 #define SLI_CTNS_GID_PT 0x01A1
#define SLI_CTNS_RPN_ID 0x0212 #define SLI_CTNS_RPN_ID 0x0212
#define SLI_CTNS_RNN_ID 0x0213 #define SLI_CTNS_RNN_ID 0x0213
...@@ -288,15 +311,16 @@ struct lpfc_sli_ct_request { ...@@ -288,15 +311,16 @@ struct lpfc_sli_ct_request {
* Port Types * Port Types
*/ */
#define SLI_CTPT_N_PORT 0x01 #define SLI_CTPT_N_PORT 0x01
#define SLI_CTPT_NL_PORT 0x02 #define SLI_CTPT_NL_PORT 0x02
#define SLI_CTPT_FNL_PORT 0x03 #define SLI_CTPT_FNL_PORT 0x03
#define SLI_CTPT_IP 0x04 #define SLI_CTPT_IP 0x04
#define SLI_CTPT_FCP 0x08 #define SLI_CTPT_FCP 0x08
#define SLI_CTPT_NX_PORT 0x7F #define SLI_CTPT_NVME 0x28
#define SLI_CTPT_F_PORT 0x81 #define SLI_CTPT_NX_PORT 0x7F
#define SLI_CTPT_FL_PORT 0x82 #define SLI_CTPT_F_PORT 0x81
#define SLI_CTPT_E_PORT 0x84 #define SLI_CTPT_FL_PORT 0x82
#define SLI_CTPT_E_PORT 0x84
#define SLI_CT_LAST_ENTRY 0x80000000 #define SLI_CT_LAST_ENTRY 0x80000000
...@@ -337,6 +361,7 @@ struct lpfc_name { ...@@ -337,6 +361,7 @@ struct lpfc_name {
uint8_t IEEE[6]; /* FC IEEE address */ uint8_t IEEE[6]; /* FC IEEE address */
} s; } s;
uint8_t wwn[8]; uint8_t wwn[8];
uint64_t name;
} u; } u;
}; };
...@@ -549,6 +574,7 @@ struct fc_vft_header { ...@@ -549,6 +574,7 @@ struct fc_vft_header {
#define ELS_CMD_REC 0x13000000 #define ELS_CMD_REC 0x13000000
#define ELS_CMD_RDP 0x18000000 #define ELS_CMD_RDP 0x18000000
#define ELS_CMD_PRLI 0x20100014 #define ELS_CMD_PRLI 0x20100014
#define ELS_CMD_NVMEPRLI 0x20140018
#define ELS_CMD_PRLO 0x21100014 #define ELS_CMD_PRLO 0x21100014
#define ELS_CMD_PRLO_ACC 0x02100014 #define ELS_CMD_PRLO_ACC 0x02100014
#define ELS_CMD_PDISC 0x50000000 #define ELS_CMD_PDISC 0x50000000
...@@ -588,6 +614,7 @@ struct fc_vft_header { ...@@ -588,6 +614,7 @@ struct fc_vft_header {
#define ELS_CMD_REC 0x13 #define ELS_CMD_REC 0x13
#define ELS_CMD_RDP 0x18 #define ELS_CMD_RDP 0x18
#define ELS_CMD_PRLI 0x14001020 #define ELS_CMD_PRLI 0x14001020
#define ELS_CMD_NVMEPRLI 0x18001420
#define ELS_CMD_PRLO 0x14001021 #define ELS_CMD_PRLO 0x14001021
#define ELS_CMD_PRLO_ACC 0x14001002 #define ELS_CMD_PRLO_ACC 0x14001002
#define ELS_CMD_PDISC 0x50 #define ELS_CMD_PDISC 0x50
...@@ -684,6 +711,7 @@ typedef struct _PRLI { /* Structure is in Big Endian format */ ...@@ -684,6 +711,7 @@ typedef struct _PRLI { /* Structure is in Big Endian format */
uint8_t prliType; /* FC Parm Word 0, bit 24:31 */ uint8_t prliType; /* FC Parm Word 0, bit 24:31 */
#define PRLI_FCP_TYPE 0x08 #define PRLI_FCP_TYPE 0x08
#define PRLI_NVME_TYPE 0x28
uint8_t word0Reserved1; /* FC Parm Word 0, bit 16:23 */ uint8_t word0Reserved1; /* FC Parm Word 0, bit 16:23 */
#ifdef __BIG_ENDIAN_BITFIELD #ifdef __BIG_ENDIAN_BITFIELD
...@@ -1243,8 +1271,7 @@ struct fc_rdp_opd_sfp_info { ...@@ -1243,8 +1271,7 @@ struct fc_rdp_opd_sfp_info {
uint8_t vendor_name[16]; uint8_t vendor_name[16];
uint8_t model_number[16]; uint8_t model_number[16];
uint8_t serial_number[16]; uint8_t serial_number[16];
uint8_t revision[2]; uint8_t revision[4];
uint8_t reserved[2];
uint8_t date[8]; uint8_t date[8];
}; };
...@@ -1263,14 +1290,14 @@ struct fc_rdp_req_frame { ...@@ -1263,14 +1290,14 @@ struct fc_rdp_req_frame {
struct fc_rdp_res_frame { struct fc_rdp_res_frame {
uint32_t reply_sequence; /* FC word0 LS_ACC or LS_RJT */ uint32_t reply_sequence; /* FC word0 LS_ACC or LS_RJT */
uint32_t length; /* FC Word 1 */ uint32_t length; /* FC Word 1 */
struct fc_rdp_link_service_desc link_service_desc; /* Word 2 -4 */ struct fc_rdp_link_service_desc link_service_desc; /* Word 2 -4 */
struct fc_rdp_sfp_desc sfp_desc; /* Word 5 -9 */ struct fc_rdp_sfp_desc sfp_desc; /* Word 5 -9 */
struct fc_rdp_port_speed_desc portspeed_desc; /* Word 10-12 */ struct fc_rdp_port_speed_desc portspeed_desc; /* Word 10 -12 */
struct fc_rdp_link_error_status_desc link_error_desc; /* Word 13-21 */ struct fc_rdp_link_error_status_desc link_error_desc; /* Word 13 -21 */
struct fc_rdp_port_name_desc diag_port_names_desc; /* Word 22-27 */ struct fc_rdp_port_name_desc diag_port_names_desc; /* Word 22 -27 */
struct fc_rdp_port_name_desc attached_port_names_desc;/* Word 28-33 */ struct fc_rdp_port_name_desc attached_port_names_desc;/* Word 28 -33 */
struct fc_fec_rdp_desc fec_desc; /* FC word 34-37*/ struct fc_fec_rdp_desc fec_desc; /* FC word 34-37*/
struct fc_rdp_bbc_desc bbc_desc; /* FC Word 38-42*/ struct fc_rdp_bbc_desc bbc_desc; /* FC Word 38-42*/
struct fc_rdp_oed_sfp_desc oed_temp_desc; /* FC Word 43-47*/ struct fc_rdp_oed_sfp_desc oed_temp_desc; /* FC Word 43-47*/
......
...@@ -3922,6 +3922,49 @@ struct gen_req64_wqe { ...@@ -3922,6 +3922,49 @@ struct gen_req64_wqe {
uint32_t max_response_payload_len; uint32_t max_response_payload_len;
}; };
/* Define NVME PRLI request to fabric. NVME is a
* fabric-only protocol.
* Updated to red-lined v1.08 on Sept 16, 2016
*/
struct lpfc_nvme_prli {
uint32_t word1;
/* The Response Code is defined in the FCP PRLI lpfc_hw.h */
#define prli_acc_rsp_code_SHIFT 8
#define prli_acc_rsp_code_MASK 0x0000000f
#define prli_acc_rsp_code_WORD word1
#define prli_estabImagePair_SHIFT 13
#define prli_estabImagePair_MASK 0x00000001
#define prli_estabImagePair_WORD word1
#define prli_type_code_ext_SHIFT 16
#define prli_type_code_ext_MASK 0x000000ff
#define prli_type_code_ext_WORD word1
#define prli_type_code_SHIFT 24
#define prli_type_code_MASK 0x000000ff
#define prli_type_code_WORD word1
uint32_t word_rsvd2;
uint32_t word_rsvd3;
uint32_t word4;
#define prli_fba_SHIFT 0
#define prli_fba_MASK 0x00000001
#define prli_fba_WORD word4
#define prli_disc_SHIFT 3
#define prli_disc_MASK 0x00000001
#define prli_disc_WORD word4
#define prli_tgt_SHIFT 4
#define prli_tgt_MASK 0x00000001
#define prli_tgt_WORD word4
#define prli_init_SHIFT 5
#define prli_init_MASK 0x00000001
#define prli_init_WORD word4
#define prli_recov_SHIFT 8
#define prli_recov_MASK 0x00000001
#define prli_recov_WORD word4
uint32_t word5;
#define prli_fb_sz_SHIFT 0
#define prli_fb_sz_MASK 0x0000ffff
#define prli_fb_sz_WORD word5
};
struct create_xri_wqe { struct create_xri_wqe {
uint32_t rsrvd[5]; /* words 0-4 */ uint32_t rsrvd[5]; /* words 0-4 */
struct wqe_did wqe_dest; /* word 5 */ struct wqe_did wqe_dest; /* word 5 */
......
...@@ -2667,6 +2667,13 @@ lpfc_cleanup(struct lpfc_vport *vport) ...@@ -2667,6 +2667,13 @@ lpfc_cleanup(struct lpfc_vport *vport)
lpfc_disc_state_machine(vport, ndlp, NULL, lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY); NLP_EVT_DEVICE_RECOVERY);
if (ndlp->nlp_fc4_type & NLP_FC4_NVME) {
/* Remove the NVME transport reference now and
* continue to remove the node.
*/
lpfc_nlp_put(ndlp);
}
lpfc_disc_state_machine(vport, ndlp, NULL, lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RM); NLP_EVT_DEVICE_RM);
} }
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#include <scsi/scsi_device.h> #include <scsi/scsi_device.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.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_hw4.h"
#include "lpfc_hw.h" #include "lpfc_hw.h"
...@@ -35,8 +38,9 @@ ...@@ -35,8 +38,9 @@
#include "lpfc_sli4.h" #include "lpfc_sli4.h"
#include "lpfc_nl.h" #include "lpfc_nl.h"
#include "lpfc_disc.h" #include "lpfc_disc.h"
#include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
#include "lpfc_scsi.h"
#include "lpfc_nvme.h"
#include "lpfc_logmsg.h" #include "lpfc_logmsg.h"
#include "lpfc_crtn.h" #include "lpfc_crtn.h"
#include "lpfc_vport.h" #include "lpfc_vport.h"
...@@ -708,6 +712,7 @@ static void ...@@ -708,6 +712,7 @@ static void
lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_iocbq *cmdiocb) struct lpfc_iocbq *cmdiocb)
{ {
struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd; struct lpfc_dmabuf *pcmd;
uint32_t *lp; uint32_t *lp;
PRLI *npr; PRLI *npr;
...@@ -721,11 +726,19 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -721,11 +726,19 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
ndlp->nlp_flag &= ~NLP_FIRSTBURST; ndlp->nlp_flag &= ~NLP_FIRSTBURST;
if (npr->prliType == PRLI_FCP_TYPE) { if ((npr->prliType == PRLI_FCP_TYPE) ||
if (npr->initiatorFunc) (npr->prliType == PRLI_NVME_TYPE)) {
ndlp->nlp_type |= NLP_FCP_INITIATOR; if (npr->initiatorFunc) {
if (npr->prliType == PRLI_FCP_TYPE)
ndlp->nlp_type |= NLP_FCP_INITIATOR;
if (npr->prliType == PRLI_NVME_TYPE)
ndlp->nlp_type |= NLP_NVME_INITIATOR;
}
if (npr->targetFunc) { if (npr->targetFunc) {
ndlp->nlp_type |= NLP_FCP_TARGET; if (npr->prliType == PRLI_FCP_TYPE)
ndlp->nlp_type |= NLP_FCP_TARGET;
if (npr->prliType == PRLI_NVME_TYPE)
ndlp->nlp_type |= NLP_NVME_TARGET;
if (npr->writeXferRdyDis) if (npr->writeXferRdyDis)
ndlp->nlp_flag |= NLP_FIRSTBURST; ndlp->nlp_flag |= NLP_FIRSTBURST;
} }
...@@ -744,7 +757,8 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -744,7 +757,8 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
"rport rolechg: role:x%x did:x%x flg:x%x", "rport rolechg: role:x%x did:x%x flg:x%x",
roles, ndlp->nlp_DID, ndlp->nlp_flag); roles, ndlp->nlp_DID, ndlp->nlp_flag);
fc_remote_port_rolechg(rport, roles); if (phba->cfg_enable_fc4_type != LPFC_ENABLE_NVME)
fc_remote_port_rolechg(rport, roles);
} }
} }
...@@ -1491,7 +1505,9 @@ lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport, ...@@ -1491,7 +1505,9 @@ lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport,
{ {
struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* Initiator mode. */
lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state; return ndlp->nlp_state;
} }
...@@ -1574,9 +1590,11 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, ...@@ -1574,9 +1590,11 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
uint32_t evt) uint32_t evt)
{ {
struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
MAILBOX_t *mb = &pmb->u.mb; MAILBOX_t *mb = &pmb->u.mb;
uint32_t did = mb->un.varWords[1]; uint32_t did = mb->un.varWords[1];
int rc = 0;
if (mb->mbxStatus) { if (mb->mbxStatus) {
/* RegLogin failed */ /* RegLogin failed */
...@@ -1611,19 +1629,52 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, ...@@ -1611,19 +1629,52 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
} }
/* SLI4 ports have preallocated logical rpis. */ /* SLI4 ports have preallocated logical rpis. */
if (vport->phba->sli_rev < LPFC_SLI_REV4) if (phba->sli_rev < LPFC_SLI_REV4)
ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_flag |= NLP_RPI_REGISTERED; ndlp->nlp_flag |= NLP_RPI_REGISTERED;
/* Only if we are not a fabric nport do we issue PRLI */ /* Only if we are not a fabric nport do we issue PRLI */
if (!(ndlp->nlp_type & NLP_FABRIC)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
"3066 RegLogin Complete on x%x x%x x%x\n",
did, ndlp->nlp_type, ndlp->nlp_fc4_type);
if (!(ndlp->nlp_type & NLP_FABRIC) &&
(phba->nvmet_support == 0)) {
/* The driver supports FCP and NVME concurrently. If the
* ndlp's nlp_fc4_type is still zero, the driver doesn't
* know what PRLI to send yet. Figure that out now and
* call PRLI depending on the outcome.
*/
if (vport->fc_flag & FC_PT2PT) {
/* If we are pt2pt, there is no Fabric to determine
* the FC4 type of the remote nport. So if NVME
* is configured try it.
*/
ndlp->nlp_fc4_type |= NLP_FC4_FCP;
if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
(phba->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
ndlp->nlp_fc4_type |= NLP_FC4_NVME;
/* We need to update the localport also */
/* todo: init: revise localport nvme
* attributes
*/
}
} else if (ndlp->nlp_fc4_type == 0) {
rc = lpfc_ns_cmd(vport, SLI_CTNS_GFT_ID,
0, ndlp->nlp_DID);
return ndlp->nlp_state;
}
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
lpfc_issue_els_prli(vport, ndlp, 0); lpfc_issue_els_prli(vport, ndlp, 0);
} else { } else {
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; /* Only Fabric ports should transition */
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); if (ndlp->nlp_type & NLP_FABRIC) {
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
}
} }
return ndlp->nlp_state; return ndlp->nlp_state;
} }
...@@ -1664,7 +1715,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, ...@@ -1664,7 +1715,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_IGNR_REG_CMPL;
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
lpfc_disc_set_adisc(vport, ndlp); lpfc_disc_set_adisc(vport, ndlp);
...@@ -1740,10 +1791,23 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1740,10 +1791,23 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
IOCB_t *irsp; IOCB_t *irsp;
PRLI *npr; PRLI *npr;
struct lpfc_nvme_prli *nvpr;
void *temp_ptr;
cmdiocb = (struct lpfc_iocbq *) arg; cmdiocb = (struct lpfc_iocbq *) arg;
rspiocb = cmdiocb->context_un.rsp_iocb; rspiocb = cmdiocb->context_un.rsp_iocb;
npr = (PRLI *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);
/* A solicited PRLI is either FCP or NVME. The PRLI cmd/rsp
* format is different so NULL the two PRLI types so that the
* driver correctly gets the correct context.
*/
npr = NULL;
nvpr = NULL;
temp_ptr = lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);
if (cmdiocb->iocb_flag & LPFC_PRLI_FCP_REQ)
npr = (PRLI *) temp_ptr;
else if (cmdiocb->iocb_flag & LPFC_PRLI_NVME_REQ)
nvpr = (struct lpfc_nvme_prli *) temp_ptr;
irsp = &rspiocb->iocb; irsp = &rspiocb->iocb;
if (irsp->ulpStatus) { if (irsp->ulpStatus) {
...@@ -1751,7 +1815,21 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1751,7 +1815,21 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
vport->cfg_restrict_login) { vport->cfg_restrict_login) {
goto out; goto out;
} }
/* The LS Req had some error. Don't let this be a
* target.
*/
if ((ndlp->fc4_prli_sent == 1) &&
(ndlp->nlp_state == NLP_STE_PRLI_ISSUE) &&
(ndlp->nlp_type & (NLP_FCP_TARGET | NLP_FCP_INITIATOR)))
/* The FCP PRLI completed successfully but
* the NVME PRLI failed. Since they are sent in
* succession, allow the FCP to complete.
*/
goto out_err;
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
ndlp->nlp_type |= NLP_FCP_INITIATOR;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
return ndlp->nlp_state; return ndlp->nlp_state;
} }
...@@ -1759,9 +1837,16 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1759,9 +1837,16 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Check out PRLI rsp */ /* Check out PRLI rsp */
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
/* NVME or FCP first burst must be negotiated for each PRLI. */
ndlp->nlp_flag &= ~NLP_FIRSTBURST; ndlp->nlp_flag &= ~NLP_FIRSTBURST;
if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) && ndlp->nvme_fb_size = 0;
if (npr && (npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
(npr->prliType == PRLI_FCP_TYPE)) { (npr->prliType == PRLI_FCP_TYPE)) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
"6028 FCP NPR PRLI Cmpl Init %d Target %d\n",
npr->initiatorFunc,
npr->targetFunc);
if (npr->initiatorFunc) if (npr->initiatorFunc)
ndlp->nlp_type |= NLP_FCP_INITIATOR; ndlp->nlp_type |= NLP_FCP_INITIATOR;
if (npr->targetFunc) { if (npr->targetFunc) {
...@@ -1771,6 +1856,49 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1771,6 +1856,49 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
} }
if (npr->Retry) if (npr->Retry)
ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
/* PRLI completed. Decrement count. */
ndlp->fc4_prli_sent--;
} else if (nvpr &&
(bf_get_be32(prli_acc_rsp_code, nvpr) ==
PRLI_REQ_EXECUTED) &&
(bf_get_be32(prli_type_code, nvpr) ==
PRLI_NVME_TYPE)) {
/* Complete setting up the remote ndlp personality. */
if (bf_get_be32(prli_init, nvpr))
ndlp->nlp_type |= NLP_NVME_INITIATOR;
/* Target driver cannot solicit NVME FB. */
if (bf_get_be32(prli_tgt, nvpr)) {
ndlp->nlp_type |= NLP_NVME_TARGET;
if ((bf_get_be32(prli_fba, nvpr) == 1) &&
(bf_get_be32(prli_fb_sz, nvpr) > 0) &&
(phba->cfg_nvme_enable_fb) &&
(!phba->nvmet_support)) {
/* Both sides support FB. The target's first
* burst size is a 512 byte encoded value.
*/
ndlp->nlp_flag |= NLP_FIRSTBURST;
ndlp->nvme_fb_size = bf_get_be32(prli_fb_sz,
nvpr);
}
}
if (bf_get_be32(prli_recov, nvpr))
ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
"6029 NVME PRLI Cmpl w1 x%08x "
"w4 x%08x w5 x%08x flag x%x, "
"fcp_info x%x nlp_type x%x\n",
be32_to_cpu(nvpr->word1),
be32_to_cpu(nvpr->word4),
be32_to_cpu(nvpr->word5),
ndlp->nlp_flag, ndlp->nlp_fcp_info,
ndlp->nlp_type);
/* PRLI completed. Decrement count. */
ndlp->fc4_prli_sent--;
} }
if (!(ndlp->nlp_type & NLP_FCP_TARGET) && if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
(vport->port_type == LPFC_NPIV_PORT) && (vport->port_type == LPFC_NPIV_PORT) &&
...@@ -1786,11 +1914,24 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1786,11 +1914,24 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return ndlp->nlp_state; return ndlp->nlp_state;
} }
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; out_err:
if (ndlp->nlp_type & NLP_FCP_TARGET) /* The ndlp state cannot move to MAPPED or UNMAPPED before all PRLIs
lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); * are complete.
else */
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); if (ndlp->fc4_prli_sent == 0) {
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET))
lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
else
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
} else
lpfc_printf_vlog(vport,
KERN_INFO, LOG_ELS,
"3067 PRLI's still outstanding "
"on x%06x - count %d, Pend Node Mode "
"transition...\n",
ndlp->nlp_DID, ndlp->fc4_prli_sent);
return ndlp->nlp_state; return ndlp->nlp_state;
} }
......
...@@ -5333,7 +5333,8 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) ...@@ -5333,7 +5333,8 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
continue; continue;
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
ndlp->nlp_sid == i && ndlp->nlp_sid == i &&
ndlp->rport) { ndlp->rport &&
ndlp->nlp_type & NLP_FCP_TARGET) {
match = 1; match = 1;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment