From 7ee5d43e2ea25336a7638715420c75583bd2ed69 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 27 Oct 2007 13:37:17 -0400 Subject: [PATCH] [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 Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 9 +++- drivers/scsi/lpfc/lpfc_attr.c | 81 +++++++++------------------------- drivers/scsi/lpfc/lpfc_crtn.h | 2 +- drivers/scsi/lpfc/lpfc_ct.c | 76 ++++++++++++++++++++++++++----- drivers/scsi/lpfc/lpfc_hw.h | 5 +++ drivers/scsi/lpfc/lpfc_init.c | 21 +++++++-- drivers/scsi/lpfc/lpfc_vport.c | 14 +++++- 7 files changed, 127 insertions(+), 81 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index c1343fb2fc..ff6b7d33cc 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 bd35e9c7b9..356dede9cd 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 @@ -1258,6 +1264,13 @@ static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR, 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 f3916645e8..be4b658416 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 c701e4d611..dbe020e66b 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 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, @@ -847,11 +847,29 @@ out: return; } +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 098dd022a7..b075d59564 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 17f445478b..86c2f2b15b 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 dcb415e717..3b705ccc77 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) { -- 2.39.5