summaryrefslogtreecommitdiff
path: root/drivers/scsi/lpfc
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2007-10-27 13:37:17 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-11 18:22:31 -0600
commit7ee5d43e2ea25336a7638715420c75583bd2ed69 (patch)
tree2687f4508fa05465b231a61e606b1063c944d107 /drivers/scsi/lpfc
parent57127f157298ea2dacbbc878a3c5d2a5daca772c (diff)
downloadlinux-3.10-7ee5d43e2ea25336a7638715420c75583bd2ed69.tar.gz
linux-3.10-7ee5d43e2ea25336a7638715420c75583bd2ed69.tar.bz2
linux-3.10-7ee5d43e2ea25336a7638715420c75583bd2ed69.zip
[SCSI] lpfc 8.2.3 : NPIV bug fixes
NPIV bug fixes: - Remove vport params on physical hba when npiv is disabled - Implement new DA_ID CT command to remove vport information from the switch after delete. Some switches didn't clean this up unless the physical link dropped. Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r--drivers/scsi/lpfc/lpfc.h9
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c81
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c76
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c21
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c14
7 files changed, 127 insertions, 81 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index c1343fb2fcf..ff6b7d33cca 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -272,10 +272,16 @@ struct lpfc_vport {
#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */
#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */
#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */
-#define FC_RFF_NOT_SUPPORTED 0x40000 /* RFF_ID was rejected by switch */
#define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */
#define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */
+ uint32_t ct_flags;
+#define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */
+#define FC_CT_RNN_ID 0x2 /* RNN_ID accepted by switch */
+#define FC_CT_RSNN_NN 0x4 /* RSNN_NN accepted by switch */
+#define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */
+#define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */
+
struct list_head fc_nodes;
/* Keep counters for the number of entries in each list. */
@@ -344,6 +350,7 @@ struct lpfc_vport {
uint32_t cfg_discovery_threads;
uint32_t cfg_log_verbose;
uint32_t cfg_max_luns;
+ uint32_t cfg_enable_da_id;
uint32_t dev_loss_tmo_changed;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index bd35e9c7b99..356dede9cd6 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1113,7 +1113,13 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
" 2 - select SLI-2 even on SLI-3 capable HBAs,"
" 3 - select SLI-3");
-LPFC_ATTR_R(enable_npiv, 0, 0, 1, "Enable NPIV functionality");
+int lpfc_enable_npiv = 0;
+module_param(lpfc_enable_npiv, int, 0);
+MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
+lpfc_param_show(enable_npiv);
+lpfc_param_init(enable_npiv, 0, 0, 1);
+static CLASS_DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
+ lpfc_enable_npiv_show, NULL);
/*
# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -1259,6 +1265,13 @@ LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff,
"Verbose logging bit-mask");
/*
+# lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters
+# objects that have been registered with the nameserver after login.
+*/
+LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1,
+ "Deregister nameserver objects before LOGO");
+
+/*
# lun_queue_depth: This parameter is used to limit the number of outstanding
# commands per FCP LUN. Value range is [1,128]. Default value is 30.
*/
@@ -1564,6 +1577,7 @@ struct class_device_attribute *lpfc_vport_attrs[] = {
&class_device_attr_lpfc_max_luns,
&class_device_attr_nport_evt_cnt,
&class_device_attr_npiv_info,
+ &class_device_attr_lpfc_enable_da_id,
NULL,
};
@@ -2349,69 +2363,13 @@ struct fc_function_template lpfc_transport_functions = {
.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
.terminate_rport_io = lpfc_terminate_rport_io,
- .vport_create = lpfc_vport_create,
- .vport_delete = lpfc_vport_delete,
+ /* Vport fields are filled in at runtime based on enable_npiv */
+ .vport_create = NULL,
+ .vport_delete = NULL,
+ .vport_disable = NULL,
.dd_fcvport_size = sizeof(struct lpfc_vport *),
};
-struct fc_function_template lpfc_vport_transport_functions = {
- /* fixed attributes the driver supports */
- .show_host_node_name = 1,
- .show_host_port_name = 1,
- .show_host_supported_classes = 1,
- .show_host_supported_fc4s = 1,
- .show_host_supported_speeds = 1,
- .show_host_maxframe_size = 1,
-
- /* dynamic attributes the driver supports */
- .get_host_port_id = lpfc_get_host_port_id,
- .show_host_port_id = 1,
-
- .get_host_port_type = lpfc_get_host_port_type,
- .show_host_port_type = 1,
-
- .get_host_port_state = lpfc_get_host_port_state,
- .show_host_port_state = 1,
-
- /* active_fc4s is shown but doesn't change (thus no get function) */
- .show_host_active_fc4s = 1,
-
- .get_host_speed = lpfc_get_host_speed,
- .show_host_speed = 1,
-
- .get_host_fabric_name = lpfc_get_host_fabric_name,
- .show_host_fabric_name = 1,
-
- /*
- * The LPFC driver treats linkdown handling as target loss events
- * so there are no sysfs handlers for link_down_tmo.
- */
-
- .get_fc_host_stats = lpfc_get_stats,
- .reset_fc_host_stats = lpfc_reset_stats,
-
- .dd_fcrport_size = sizeof(struct lpfc_rport_data),
- .show_rport_maxframe_size = 1,
- .show_rport_supported_classes = 1,
-
- .set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo,
- .show_rport_dev_loss_tmo = 1,
-
- .get_starget_port_id = lpfc_get_starget_port_id,
- .show_starget_port_id = 1,
-
- .get_starget_node_name = lpfc_get_starget_node_name,
- .show_starget_node_name = 1,
-
- .get_starget_port_name = lpfc_get_starget_port_name,
- .show_starget_port_name = 1,
-
- .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
- .terminate_rport_io = lpfc_terminate_rport_io,
-
- .vport_disable = lpfc_vport_disable,
-};
-
void
lpfc_get_cfgparam(struct lpfc_hba *phba)
{
@@ -2460,5 +2418,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
lpfc_max_luns_init(vport, lpfc_max_luns);
lpfc_scan_down_init(vport, lpfc_scan_down);
+ lpfc_enable_da_id_init(vport, lpfc_enable_da_id);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index f3916645e81..be4b6584167 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -260,8 +260,8 @@ extern struct class_device_attribute *lpfc_vport_attrs[];
extern struct scsi_host_template lpfc_template;
extern struct scsi_host_template lpfc_vport_template;
extern struct fc_function_template lpfc_transport_functions;
-extern struct fc_function_template lpfc_vport_transport_functions;
extern int lpfc_sli_mode;
+extern int lpfc_enable_npiv;
int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
void lpfc_terminate_rport_io(struct fc_rport *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index c701e4d611a..dbe020e66b0 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -458,7 +458,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
((lpfc_find_vport_by_did(phba, Did) == NULL) ||
vport->cfg_peer_port_login)) {
if ((vport->port_type != LPFC_NPIV_PORT) ||
- (vport->fc_flag & FC_RFF_NOT_SUPPORTED) ||
+ (!vport->ct_flags & FC_CT_RFF_ID) ||
(!vport->cfg_restrict_login)) {
ndlp = lpfc_setup_disc_node(vport, Did);
if (ndlp) {
@@ -778,8 +778,8 @@ out:
static void
-lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- struct lpfc_iocbq *rspiocb)
+lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_dmabuf *inp;
@@ -809,7 +809,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "0209 RFT request completes, latt %d, "
+ "0209 CT Request completes, latt %d, "
"ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
latt, irsp->ulpStatus,
CTrsp->CommandResponse.bits.CmdRsp,
@@ -848,10 +848,28 @@ out:
}
static void
+lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_vport *vport = cmdiocb->vport;
+
+ if (irsp->ulpStatus == IOSTAT_SUCCESS)
+ vport->ct_flags |= FC_CT_RFT_ID;
+ lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+ return;
+}
+
+static void
lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
- lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_vport *vport = cmdiocb->vport;
+
+ if (irsp->ulpStatus == IOSTAT_SUCCESS)
+ vport->ct_flags |= FC_CT_RNN_ID;
+ lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
return;
}
@@ -859,7 +877,12 @@ static void
lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
- lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_vport *vport = cmdiocb->vport;
+
+ if (irsp->ulpStatus == IOSTAT_SUCCESS)
+ vport->ct_flags |= FC_CT_RSPN_ID;
+ lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
return;
}
@@ -867,7 +890,24 @@ static void
lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
- lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_vport *vport = cmdiocb->vport;
+
+ if (irsp->ulpStatus == IOSTAT_SUCCESS)
+ vport->ct_flags |= FC_CT_RSNN_NN;
+ lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+ return;
+}
+
+static void
+lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+
+ /* even if it fails we will act as though it succeeded. */
+ vport->ct_flags = 0;
+ lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
return;
}
@@ -878,10 +918,9 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
IOCB_t *irsp = &rspiocb->iocb;
struct lpfc_vport *vport = cmdiocb->vport;
- if (irsp->ulpStatus != IOSTAT_SUCCESS)
- vport->fc_flag |= FC_RFF_NOT_SUPPORTED;
-
- lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+ if (irsp->ulpStatus == IOSTAT_SUCCESS)
+ vport->ct_flags |= FC_CT_RFF_ID;
+ lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
return;
}
@@ -1001,6 +1040,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RSNN_NN)
bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
+ else if (cmdcode == SLI_CTNS_DA_ID)
+ bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RFF_ID)
bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
else
@@ -1034,6 +1075,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
break;
case SLI_CTNS_RFT_ID:
+ vport->ct_flags &= ~FC_CT_RFT_ID;
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RFT_ID);
CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID);
@@ -1042,6 +1084,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
break;
case SLI_CTNS_RNN_ID:
+ vport->ct_flags &= ~FC_CT_RNN_ID;
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RNN_ID);
CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID);
@@ -1051,6 +1094,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
break;
case SLI_CTNS_RSPN_ID:
+ vport->ct_flags &= ~FC_CT_RSPN_ID;
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RSPN_ID);
CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID);
@@ -1061,6 +1105,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
cmpl = lpfc_cmpl_ct_cmd_rspn_id;
break;
case SLI_CTNS_RSNN_NN:
+ vport->ct_flags &= ~FC_CT_RSNN_NN;
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RSNN_NN);
memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
@@ -1071,8 +1116,15 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
CtReq->un.rsnn.symbname, size);
cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
break;
+ case SLI_CTNS_DA_ID:
+ /* Implement DA_ID Nameserver request */
+ CtReq->CommandResponse.bits.CmdRsp =
+ be16_to_cpu(SLI_CTNS_DA_ID);
+ CtReq->un.da_id.port_id = be32_to_cpu(vport->fc_myDID);
+ cmpl = lpfc_cmpl_ct_cmd_da_id;
+ break;
case SLI_CTNS_RFF_ID:
- vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED;
+ vport->ct_flags &= ~FC_CT_RFF_ID;
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RFF_ID);
CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);;
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 098dd022a7e..b075d595648 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -139,6 +139,9 @@ struct lpfc_sli_ct_request {
uint8_t len;
uint8_t symbname[255];
} rsnn;
+ struct da_id { /* For DA_ID requests */
+ uint32_t port_id;
+ } da_id;
struct rspn { /* For RSPN_ID requests */
uint32_t PortId;
uint8_t len;
@@ -177,6 +180,8 @@ struct lpfc_sli_ct_request {
sizeof(struct rnn))
#define RSNN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
sizeof(struct rsnn))
+#define DA_ID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct da_id))
#define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
sizeof(struct rspn))
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 17f445478be..86c2f2b15b6 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -2294,12 +2294,24 @@ lpfc_init(void)
printk(LPFC_MODULE_DESC "\n");
printk(LPFC_COPYRIGHT "\n");
+ if (lpfc_enable_npiv) {
+ lpfc_transport_functions.vport_create = lpfc_vport_create;
+ lpfc_transport_functions.vport_delete = lpfc_vport_delete;
+ }
lpfc_transport_template =
fc_attach_transport(&lpfc_transport_functions);
- lpfc_vport_transport_template =
- fc_attach_transport(&lpfc_vport_transport_functions);
- if (!lpfc_transport_template || !lpfc_vport_transport_template)
+ if (lpfc_transport_template == NULL)
return -ENOMEM;
+ if (lpfc_enable_npiv) {
+ lpfc_transport_functions.vport_create = NULL;
+ lpfc_transport_functions.vport_delete = NULL;
+ lpfc_transport_functions.issue_fc_host_lip = NULL;
+ lpfc_transport_functions.vport_disable = lpfc_vport_disable;
+ lpfc_vport_transport_template =
+ fc_attach_transport(&lpfc_transport_functions);
+ if (lpfc_vport_transport_template == NULL)
+ return -ENOMEM;
+ }
error = pci_register_driver(&lpfc_driver);
if (error) {
fc_release_transport(lpfc_transport_template);
@@ -2314,7 +2326,8 @@ lpfc_exit(void)
{
pci_unregister_driver(&lpfc_driver);
fc_release_transport(lpfc_transport_template);
- fc_release_transport(lpfc_vport_transport_template);
+ if (lpfc_enable_npiv)
+ fc_release_transport(lpfc_vport_transport_template);
}
module_init(lpfc_init);
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index dcb415e717c..3b705ccc771 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -482,8 +482,18 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
- phba->link_state >= LPFC_LINK_UP) {
-
+ phba->link_state >= LPFC_LINK_UP) {
+ if (vport->cfg_enable_da_id) {
+ timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
+ if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0))
+ while (vport->ct_flags && timeout)
+ timeout = schedule_timeout(timeout);
+ else
+ lpfc_printf_log(vport->phba, KERN_WARNING,
+ LOG_VPORT,
+ "1829 CT command failed to "
+ "delete objects on fabric. \n");
+ }
/* First look for the Fabric ndlp */
ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (!ndlp) {