diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 02:02:04 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-17 02:02:04 +0300 |
commit | 7d69cff26ceadce8638cb65191285932a3de3d4c (patch) | |
tree | 7a23eb561e6a25fbd111af2d0152cc6f34c2cecd /drivers/scsi/lpfc | |
parent | 8fa6f4974d55ad1fb0a9522c5a5cfd050a517048 (diff) | |
parent | 0351b8f81392c6dbbbb036e5c8f73ceff68726e9 (diff) | |
download | linux-7d69cff26ceadce8638cb65191285932a3de3d4c.tar.xz |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"This is the usual grab bag of driver updates (lpfc, qla2xxx, storvsc,
aacraid, ipr) plus an assortment of minor updates. There's also a
major update to aic1542 which moves the driver into this millenium"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (106 commits)
change SCSI Maintainer email
sd, mmc, virtio_blk, string_helpers: fix block size units
ufs: add support to allow non standard behaviours (quirks)
ufs-qcom: save controller revision info in internal structure
qla2xxx: Update driver version to 8.07.00.18-k
qla2xxx: Restore physical port WWPN only, when port down detected for FA-WWPN port.
qla2xxx: Fix virtual port configuration, when switch port is disabled/enabled.
qla2xxx: Prevent multiple firmware dump collection for ISP27XX.
qla2xxx: Disable Interrupt handshake for ISP27XX.
qla2xxx: Add debugging info for MBX timeout.
qla2xxx: Add serdes read/write support for ISP27XX
qla2xxx: Add udev notification to save fw dump for ISP27XX
qla2xxx: Add message for sucessful FW dump collected for ISP27XX.
qla2xxx: Add support to load firmware from file for ISP 26XX/27XX.
qla2xxx: Fix beacon blink for ISP27XX.
qla2xxx: Increase the wait time for firmware to be ready for P3P.
qla2xxx: Fix crash due to wrong casting of reg for ISP27XX.
qla2xxx: Fix warnings reported by static checker.
lpfc: Update version to 10.5.0.0 for upstream patch set
lpfc: Update copyright to 2015
...
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 5 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 25 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.h | 3 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 738 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 19 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 74 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 208 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 8 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 264 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 29 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 83 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 72 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 3 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 6 |
20 files changed, 1099 insertions, 456 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 434e9037908e..9b81a34d7449 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -413,6 +413,9 @@ struct lpfc_vport { uint32_t cfg_fcp_class; uint32_t cfg_use_adisc; uint32_t cfg_fdmi_on; +#define LPFC_FDMI_SUPPORT 1 /* bit 0 - FDMI supported? */ +#define LPFC_FDMI_REG_DELAY 2 /* bit 1 - 60 sec registration delay */ +#define LPFC_FDMI_ALL_ATTRIB 4 /* bit 2 - register ALL attributes? */ uint32_t cfg_discovery_threads; uint32_t cfg_log_verbose; uint32_t cfg_max_luns; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 2f9b96826ac0..d65bd178d131 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -406,8 +406,13 @@ lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + char fwrev[FW_REV_STR_SIZE]; + + if (phba->sli_rev < LPFC_SLI_REV4) + return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion); - return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion); + lpfc_decode_firmware_rev(phba, fwrev, 1); + return snprintf(buf, PAGE_SIZE, "%s\n", fwrev); } /** @@ -4568,12 +4573,18 @@ LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1, /* # lpfc_fdmi_on: controls FDMI support. -# 0 = no FDMI support -# 1 = support FDMI without attribute of hostname -# 2 = support FDMI with attribute of hostname -# Value range [0,2]. Default value is 0. +# Set NOT Set +# bit 0 = FDMI support no FDMI support +# LPFC_FDMI_SUPPORT just turns basic support on/off +# bit 1 = Register delay no register delay (60 seconds) +# LPFC_FDMI_REG_DELAY 60 sec registration delay after FDMI login +# bit 2 = All attributes Use a attribute subset +# LPFC_FDMI_ALL_ATTRIB applies to both port and HBA attributes +# Port attrutes subset: 1 thru 6 OR all: 1 thru 0xd 0x101 0x102 0x103 +# HBA attributes subset: 1 thru 0xb OR all: 1 thru 0xc +# Value range [0,7]. Default value is 0. */ -LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support"); +LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 7, "Enable FDMI support"); /* # Specifies the maximum number of ELS cmds we can have outstanding (for diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index a7bf359aa0c6..b705068079c0 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2014 Emulex. All rights reserved. * + * Copyright (C) 2009-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -3194,6 +3194,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) cmd->unsli3.rcvsli3.ox_id = 0xffff; } cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; + cmdiocbq->iocb_flag |= LPFC_IO_LOOPBACK; cmdiocbq->vport = phba->pport; cmdiocbq->iocb_cmpl = NULL; iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, @@ -4179,6 +4180,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, switch (opcode) { case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: case COMN_OPCODE_GET_CNTL_ATTRIBUTES: + case COMN_OPCODE_GET_PROFILE_CONFIG: lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "3106 Handled SLI_CONFIG " "subsys_comn, opcode:x%x\n", diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index 928ef609f363..e557bcdbcb19 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2010-2014 Emulex. All rights reserved. * + * Copyright (C) 2010-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -246,6 +246,7 @@ struct lpfc_sli_config_emb1_subsys { #define lpfc_emb1_subcmnd_subsys_WORD word6 /* Subsystem COMN (0x01) OpCodes */ #define SLI_CONFIG_SUBSYS_COMN 0x01 +#define COMN_OPCODE_GET_PROFILE_CONFIG 0xA4 #define COMN_OPCODE_READ_OBJECT 0xAB #define COMN_OPCODE_WRITE_OBJECT 0xAC #define COMN_OPCODE_READ_OBJECT_LIST 0xAD diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 00665a5d92fd..587e3e962f2b 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -284,6 +284,7 @@ void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *, struct lpfc_sli_ring *, uint32_t); void lpfc_sli4_handle_received_buffer(struct lpfc_hba *, struct hbq_dmabuf *); void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, uint32_t); void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); @@ -354,6 +355,7 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *); extern struct device_attribute *lpfc_hba_attrs[]; extern struct device_attribute *lpfc_vport_attrs[]; extern struct scsi_host_template lpfc_template; +extern struct scsi_host_template lpfc_template_s3; 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; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 61a32cd23f79..af129966bd11 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -555,7 +555,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) } } } - if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY))) + if (CTentry & (cpu_to_be32(SLI_CT_LAST_ENTRY))) goto nsout1; Cnt -= sizeof (uint32_t); } @@ -641,7 +641,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Good status, continue checking */ CTrsp = (struct lpfc_sli_ct_request *) outp->virt; if (CTrsp->CommandResponse.bits.CmdRsp == - be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { + 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); @@ -1074,11 +1074,48 @@ 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 FV%s DV%s", - vport->phba->ModelName, fwrev, lpfc_release_version); + n = snprintf(symbol, size, "Emulex %s", vport->phba->ModelName); + + if (size < n) + return n; + 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); + + if (size < n) + return n; + n += snprintf(symbol + n, size - n, " HN:%s", init_utsname()->nodename); + + /* Note :- OS name is "Linux" */ + if (size < n) + return n; + n += snprintf(symbol + n, size - n, " OS:%s", init_utsname()->sysname); + return n; } +static uint32_t +lpfc_find_map_node(struct lpfc_vport *vport) +{ + struct lpfc_nodelist *ndlp, *next_ndlp; + struct Scsi_Host *shost; + uint32_t cnt = 0; + + shost = lpfc_shost_from_vport(vport); + spin_lock_irq(shost->host_lock); + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->nlp_type & NLP_FABRIC) + continue; + if ((ndlp->nlp_state == NLP_STE_MAPPED_NODE) || + (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE)) + cnt++; + } + spin_unlock_irq(shost->host_lock); + return cnt; +} + /* * lpfc_ns_cmd * Description: @@ -1177,7 +1214,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, switch (cmdcode) { case SLI_CTNS_GID_FT: CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_GID_FT); + cpu_to_be16(SLI_CTNS_GID_FT); CtReq->un.gid.Fc4Type = SLI_CTPT_FCP; if (vport->port_state < LPFC_NS_QRY) vport->port_state = LPFC_NS_QRY; @@ -1188,7 +1225,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, case SLI_CTNS_GFF_ID: CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_GFF_ID); + cpu_to_be16(SLI_CTNS_GFF_ID); CtReq->un.gff.PortId = cpu_to_be32(context); cmpl = lpfc_cmpl_ct_cmd_gff_id; break; @@ -1196,7 +1233,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, case SLI_CTNS_RFT_ID: vport->ct_flags &= ~FC_CT_RFT_ID; CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RFT_ID); + cpu_to_be16(SLI_CTNS_RFT_ID); CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID); CtReq->un.rft.fcpReg = 1; cmpl = lpfc_cmpl_ct_cmd_rft_id; @@ -1205,7 +1242,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, case SLI_CTNS_RNN_ID: vport->ct_flags &= ~FC_CT_RNN_ID; CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RNN_ID); + cpu_to_be16(SLI_CTNS_RNN_ID); CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID); memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename, sizeof (struct lpfc_name)); @@ -1215,7 +1252,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, case SLI_CTNS_RSPN_ID: vport->ct_flags &= ~FC_CT_RSPN_ID; CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RSPN_ID); + cpu_to_be16(SLI_CTNS_RSPN_ID); CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID); size = sizeof(CtReq->un.rspn.symbname); CtReq->un.rspn.len = @@ -1226,7 +1263,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, case SLI_CTNS_RSNN_NN: vport->ct_flags &= ~FC_CT_RSNN_NN; CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RSNN_NN); + cpu_to_be16(SLI_CTNS_RSNN_NN); memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename, sizeof (struct lpfc_name)); size = sizeof(CtReq->un.rsnn.symbname); @@ -1238,14 +1275,14 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, case SLI_CTNS_DA_ID: /* Implement DA_ID Nameserver request */ CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_DA_ID); + cpu_to_be16(SLI_CTNS_DA_ID); CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID); cmpl = lpfc_cmpl_ct_cmd_da_id; break; case SLI_CTNS_RFF_ID: vport->ct_flags &= ~FC_CT_RFF_ID; CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RFF_ID); + 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; @@ -1299,7 +1336,6 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, uint32_t latt; latt = lpfc_els_chk_latt(vport); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "FDMI cmpl: status:x%x/x%x latt:%d", irsp->ulpStatus, irsp->un.ulpWord[4], latt); @@ -1310,29 +1346,49 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "ulpStatus: x%x, rid x%x\n", be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus, irsp->un.ulpWord[4]); - lpfc_ct_free_iocb(phba, cmdiocb); - return; + goto fail_out; } ndlp = lpfc_findnode_did(vport, FDMI_DID); if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) goto fail_out; - if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { + if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) { /* FDMI rsp failed */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0220 FDMI rsp failed Data: x%x\n", be16_to_cpu(fdmi_cmd)); } +fail_out: + lpfc_ct_free_iocb(phba, cmdiocb); +} + +static void +lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + struct lpfc_dmabuf *inp = cmdiocb->context1; + struct lpfc_sli_ct_request *CTcmd = inp->virt; + uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp; + struct lpfc_nodelist *ndlp; + + lpfc_cmpl_ct_cmd_fdmi(phba, cmdiocb, rspiocb); + + ndlp = lpfc_findnode_did(vport, FDMI_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return; + + /* + * Need to cycle thru FDMI registration for discovery + * DHBA -> DPRT -> RHBA -> RPA + */ switch (be16_to_cpu(fdmi_cmd)) { case SLI_MGMT_RHBA: lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA); break; - case SLI_MGMT_RPA: - break; - case SLI_MGMT_DHBA: lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT); break; @@ -1341,12 +1397,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA); break; } - -fail_out: - lpfc_ct_free_iocb(phba, cmdiocb); - return; } + int lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) { @@ -1355,18 +1408,28 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) struct lpfc_sli_ct_request *CtReq; struct ulp_bde64 *bpl; uint32_t size; - REG_HBA *rh; - PORT_ENTRY *pe; - REG_PORT_ATTRIBUTE *pab; - ATTRIBUTE_BLOCK *ab; - ATTRIBUTE_ENTRY *ae; + uint32_t rsp_size; + struct lpfc_fdmi_reg_hba *rh; + struct lpfc_fdmi_port_entry *pe; + struct lpfc_fdmi_reg_portattr *pab = NULL; + struct lpfc_fdmi_attr_block *ab = NULL; + struct lpfc_fdmi_attr_entry *ae; + struct lpfc_fdmi_attr_def *ad; void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); + if (ndlp == NULL) { + ndlp = lpfc_findnode_did(vport, FDMI_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + return 0; + cmpl = lpfc_cmpl_ct_cmd_fdmi; /* cmd interface */ + } else { + cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */ + } /* fill in BDEs for command */ /* Allocate buffer for command payload */ - mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); + mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (!mp) goto fdmi_cmd_exit; @@ -1375,7 +1438,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) goto fdmi_cmd_free_mp; /* Allocate buffer for Buffer ptr list */ - bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); + bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (!bmp) goto fdmi_cmd_free_mpvirt; @@ -1390,205 +1453,330 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0218 FDMI Request Data: x%x x%x x%x\n", vport->fc_flag, vport->port_state, cmdcode); - CtReq = (struct lpfc_sli_ct_request *) mp->virt; + CtReq = (struct lpfc_sli_ct_request *)mp->virt; + /* First populate the CT_IU preamble */ memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request)); CtReq->RevisionId.bits.Revision = SLI_CT_REVISION; CtReq->RevisionId.bits.InId = 0; CtReq->FsType = SLI_CT_MANAGEMENT_SERVICE; CtReq->FsSubType = SLI_CT_FDMI_Subtypes; + + CtReq->CommandResponse.bits.CmdRsp = cpu_to_be16(cmdcode); + rsp_size = LPFC_BPL_SIZE; size = 0; + /* Next fill in the specific FDMI cmd information */ switch (cmdcode) { + case SLI_MGMT_RHAT: case SLI_MGMT_RHBA: { lpfc_vpd_t *vp = &phba->vpd; uint32_t i, j, incr; - int len; + int len = 0; - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_MGMT_RHBA); - CtReq->CommandResponse.bits.Size = 0; - rh = (REG_HBA *) & CtReq->un.PortID; + rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID; + /* HBA Identifier */ memcpy(&rh->hi.PortName, &vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - /* One entry (port) per adapter */ - rh->rpl.EntryCnt = be32_to_cpu(1); - memcpy(&rh->rpl.pe, &vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - - /* point to the HBA attribute block */ - size = 2 * sizeof (struct lpfc_name) + FOURBYTES; - ab = (ATTRIBUTE_BLOCK *) ((uint8_t *) rh + size); + sizeof(struct lpfc_name)); + + if (cmdcode == SLI_MGMT_RHBA) { + /* Registered Port List */ + /* One entry (port) per adapter */ + rh->rpl.EntryCnt = cpu_to_be32(1); + memcpy(&rh->rpl.pe, &vport->fc_sparam.portName, + sizeof(struct lpfc_name)); + + /* point to the HBA attribute block */ + size = 2 * sizeof(struct lpfc_name) + + FOURBYTES; + } else { + size = sizeof(struct lpfc_name); + } + ab = (struct lpfc_fdmi_attr_block *) + ((uint8_t *)rh + size); ab->EntryCnt = 0; + size += FOURBYTES; - /* Point to the beginning of the first HBA attribute - entry */ + /* + * Point to beginning of first HBA attribute entry + */ /* #1 HBA attribute entry */ - size += FOURBYTES; - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(NODE_NAME); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES - + sizeof (struct lpfc_name)); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(struct lpfc_name)); + ad->AttrType = cpu_to_be16(RHBA_NODENAME); + ad->AttrLen = cpu_to_be16(FOURBYTES + + sizeof(struct lpfc_name)); memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName, - sizeof (struct lpfc_name)); + sizeof(struct lpfc_name)); ab->EntryCnt++; - size += FOURBYTES + sizeof (struct lpfc_name); + size += FOURBYTES + sizeof(struct lpfc_name); + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #2 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(MANUFACTURER); - strncpy(ae->un.Manufacturer, "Emulex Corporation", 64); - len = strlen(ae->un.Manufacturer); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.Manufacturer)); + ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER); + strncpy(ae->un.Manufacturer, "Emulex Corporation", + sizeof(ae->un.Manufacturer)); + len = strnlen(ae->un.Manufacturer, + sizeof(ae->un.Manufacturer)); len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); + ad->AttrLen = cpu_to_be16(FOURBYTES + len); ab->EntryCnt++; size += FOURBYTES + len; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #3 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(SERIAL_NUMBER); - strncpy(ae->un.SerialNumber, phba->SerialNumber, 64); - len = strlen(ae->un.SerialNumber); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.SerialNumber)); + ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER); + strncpy(ae->un.SerialNumber, phba->SerialNumber, + sizeof(ae->un.SerialNumber)); + len = strnlen(ae->un.SerialNumber, + sizeof(ae->un.SerialNumber)); len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); + ad->AttrLen = cpu_to_be16(FOURBYTES + len); ab->EntryCnt++; size += FOURBYTES + len; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #4 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(MODEL); - strncpy(ae->un.Model, phba->ModelName, 256); - len = strlen(ae->un.Model); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.Model)); + ad->AttrType = cpu_to_be16(RHBA_MODEL); + strncpy(ae->un.Model, phba->ModelName, + sizeof(ae->un.Model)); + len = strnlen(ae->un.Model, sizeof(ae->un.Model)); len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); + ad->AttrLen = cpu_to_be16(FOURBYTES + len); ab->EntryCnt++; size += FOURBYTES + len; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #5 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(MODEL_DESCRIPTION); - strncpy(ae->un.ModelDescription, phba->ModelDesc, 256); - len = strlen(ae->un.ModelDescription); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.ModelDescription)); + ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION); + strncpy(ae->un.ModelDescription, phba->ModelDesc, + sizeof(ae->un.ModelDescription)); + len = strnlen(ae->un.ModelDescription, + sizeof(ae->un.ModelDescription)); len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); + ad->AttrLen = cpu_to_be16(FOURBYTES + len); ab->EntryCnt++; size += FOURBYTES + len; + if ((size + 8) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #6 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(HARDWARE_VERSION); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 8); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, 8); + ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION); + ad->AttrLen = cpu_to_be16(FOURBYTES + 8); /* Convert JEDEC ID to ascii for hardware version */ incr = vp->rev.biuRev; for (i = 0; i < 8; i++) { j = (incr & 0xf); if (j <= 9) ae->un.HardwareVersion[7 - i] = - (char)((uint8_t) 0x30 + - (uint8_t) j); + (char)((uint8_t)0x30 + + (uint8_t)j); else ae->un.HardwareVersion[7 - i] = - (char)((uint8_t) 0x61 + - (uint8_t) (j - 10)); + (char)((uint8_t)0x61 + + (uint8_t)(j - 10)); incr = (incr >> 4); } ab->EntryCnt++; size += FOURBYTES + 8; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #7 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(DRIVER_VERSION); - strncpy(ae->un.DriverVersion, - lpfc_release_version, 256); - len = strlen(ae->un.DriverVersion); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.DriverVersion)); + ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION); + strncpy(ae->un.DriverVersion, lpfc_release_version, + sizeof(ae->un.DriverVersion)); + len = strnlen(ae->un.DriverVersion, + sizeof(ae->un.DriverVersion)); len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); + ad->AttrLen = cpu_to_be16(FOURBYTES + len); ab->EntryCnt++; size += FOURBYTES + len; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #8 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(OPTION_ROM_VERSION); - strncpy(ae->un.OptionROMVersion, - phba->OptionROMVersion, 256); - len = strlen(ae->un.OptionROMVersion); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.OptionROMVersion)); + ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION); + strncpy(ae->un.OptionROMVersion, phba->OptionROMVersion, + sizeof(ae->un.OptionROMVersion)); + len = strnlen(ae->un.OptionROMVersion, + sizeof(ae->un.OptionROMVersion)); len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); + ad->AttrLen = cpu_to_be16(FOURBYTES + len); ab->EntryCnt++; size += FOURBYTES + len; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #9 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(FIRMWARE_VERSION); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.FirmwareVersion)); + ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION); lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion, 1); - len = strlen(ae->un.FirmwareVersion); + len = strnlen(ae->un.FirmwareVersion, + sizeof(ae->un.FirmwareVersion)); len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); + ad->AttrLen = cpu_to_be16(FOURBYTES + len); ab->EntryCnt++; size += FOURBYTES + len; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #10 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION); - sprintf(ae->un.OsNameVersion, "%s %s %s", - init_utsname()->sysname, - init_utsname()->release, - init_utsname()->version); - len = strlen(ae->un.OsNameVersion); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.OsNameVersion)); + ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION); + snprintf(ae->un.OsNameVersion, + sizeof(ae->un.OsNameVersion), + "%s %s %s", + init_utsname()->sysname, + init_utsname()->release, + init_utsname()->version); + len = strnlen(ae->un.OsNameVersion, + sizeof(ae->un.OsNameVersion)); len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); + ad->AttrLen = cpu_to_be16(FOURBYTES + len); ab->EntryCnt++; size += FOURBYTES + len; + if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; /* #11 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(MAX_CT_PAYLOAD_LEN); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); - ae->un.MaxCTPayloadLen = (65 * 4096); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ad->AttrType = + cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN); + ad->AttrLen = cpu_to_be16(FOURBYTES + 4); + ae->un.MaxCTPayloadLen = cpu_to_be32(LPFC_MAX_CT_SIZE); ab->EntryCnt++; size += FOURBYTES + 4; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto hba_out; - ab->EntryCnt = be32_to_cpu(ab->EntryCnt); + /* + * Currently switches don't seem to support the + * following extended HBA attributes. + */ + if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB)) + goto hba_out; + + /* #12 HBA attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)rh + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.NodeSymName)); + ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME); + len = lpfc_vport_symbolic_node_name(vport, + ae->un.NodeSymName, sizeof(ae->un.NodeSymName)); + len += (len & 3) ? (4 - (len & 3)) : 4; + ad->AttrLen = cpu_to_be16(FOURBYTES + len); + ab->EntryCnt++; + size += FOURBYTES + len; +hba_out: + ab->EntryCnt = cpu_to_be32(ab->EntryCnt); /* Total size */ size = GID_REQUEST_SZ - 4 + size; } break; + case SLI_MGMT_RPRT: case SLI_MGMT_RPA: { lpfc_vpd_t *vp; struct serv_parm *hsp; - int len; + int len = 0; vp = &phba->vpd; - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_MGMT_RPA); - CtReq->CommandResponse.bits.Size = 0; - pab = (REG_PORT_ATTRIBUTE *) & CtReq->un.PortID; - size = sizeof (struct lpfc_name) + FOURBYTES; - memcpy((uint8_t *) & pab->PortName, - (uint8_t *) & vport->fc_sparam.portName, - sizeof (struct lpfc_name)); + if (cmdcode == SLI_MGMT_RPRT) { + rh = (struct lpfc_fdmi_reg_hba *) + &CtReq->un.PortID; + /* HBA Identifier */ + memcpy(&rh->hi.PortName, + &vport->fc_sparam.portName, + sizeof(struct lpfc_name)); + pab = (struct lpfc_fdmi_reg_portattr *) + &rh->rpl.EntryCnt; + } else + pab = (struct lpfc_fdmi_reg_portattr *) + &CtReq->un.PortID; + size = sizeof(struct lpfc_name) + FOURBYTES; + memcpy((uint8_t *)&pab->PortName, + (uint8_t *)&vport->fc_sparam.portName, + sizeof(struct lpfc_name)); pab->ab.EntryCnt = 0; /* #1 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_FC4_TYPES); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 32); - ae->un.SupportFC4Types[2] = 1; - ae->un.SupportFC4Types[7] = 1; + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.FC4Types)); + ad->AttrType = + cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES); + ad->AttrLen = cpu_to_be16(FOURBYTES + 32); + ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */ + ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */ + ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */ pab->ab.EntryCnt++; size += FOURBYTES + 32; /* #2 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_SPEED); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); - + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED); + ad->AttrLen = cpu_to_be16(FOURBYTES + 4); ae->un.SupportSpeed = 0; if (phba->lmt & LMT_16Gb) ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT; @@ -1602,15 +1790,19 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) ae->un.SupportSpeed |= HBA_PORTSPEED_2GBIT; if (phba->lmt & LMT_1Gb) ae->un.SupportSpeed |= HBA_PORTSPEED_1GBIT; + ae->un.SupportSpeed = + cpu_to_be32(ae->un.SupportSpeed); pab->ab.EntryCnt++; size += FOURBYTES + 4; /* #3 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(PORT_SPEED); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); - switch(phba->fc_linkspeed) { + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED); + ad->AttrLen = cpu_to_be16(FOURBYTES + 4); + switch (phba->fc_linkspeed) { case LPFC_LINK_SPEED_1GHZ: ae->un.PortSpeed = HBA_PORTSPEED_1GBIT; break; @@ -1633,93 +1825,273 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN; break; } + ae->un.PortSpeed = cpu_to_be32(ae->un.PortSpeed); pab->ab.EntryCnt++; size += FOURBYTES + 4; /* #4 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(MAX_FRAME_SIZE); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); - hsp = (struct serv_parm *) & vport->fc_sparam; + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE); + ad->AttrLen = cpu_to_be16(FOURBYTES + 4); + hsp = (struct serv_parm *)&vport->fc_sparam; ae->un.MaxFrameSize = - (((uint32_t) hsp->cmn. - bbRcvSizeMsb) << 8) | (uint32_t) hsp->cmn. + (((uint32_t)hsp->cmn. + bbRcvSizeMsb) << 8) | (uint32_t)hsp->cmn. bbRcvSizeLsb; + ae->un.MaxFrameSize = + cpu_to_be32(ae->un.MaxFrameSize); pab->ab.EntryCnt++; size += FOURBYTES + 4; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; /* #5 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(OS_DEVICE_NAME); - strcpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME); - len = strlen((char *)ae->un.OsDeviceName); + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.OsDeviceName)); + ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME); + strncpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME, + sizeof(ae->un.OsDeviceName)); + len = strnlen((char *)ae->un.OsDeviceName, + sizeof(ae->un.OsDeviceName)); len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); + ad->AttrLen = cpu_to_be16(FOURBYTES + len); pab->ab.EntryCnt++; size += FOURBYTES + len; + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #6 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.HostName)); + snprintf(ae->un.HostName, sizeof(ae->un.HostName), "%s", + init_utsname()->nodename); + ad->AttrType = cpu_to_be16(RPRT_HOST_NAME); + len = strnlen(ae->un.HostName, + sizeof(ae->un.HostName)); + len += (len & 3) ? (4 - (len & 3)) : 4; + ad->AttrLen = + cpu_to_be16(FOURBYTES + len); + pab->ab.EntryCnt++; + size += FOURBYTES + len; + if ((size + sizeof(struct lpfc_name)) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; - if (vport->cfg_fdmi_on == 2) { - /* #6 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + - size); - ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME); - sprintf(ae->un.HostName, "%s", - init_utsname()->nodename); - len = strlen(ae->un.HostName); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = - be16_to_cpu(FOURBYTES + len); - pab->ab.EntryCnt++; - size += FOURBYTES + len; - } - - pab->ab.EntryCnt = be32_to_cpu(pab->ab.EntryCnt); + /* + * Currently switches don't seem to support the + * following extended Port attributes. + */ + if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB)) + goto port_out; + + /* #7 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(struct lpfc_name)); + ad->AttrType = cpu_to_be16(RPRT_NODENAME); + ad->AttrLen = cpu_to_be16(FOURBYTES + + sizeof(struct lpfc_name)); + memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName, + sizeof(struct lpfc_name)); + pab->ab.EntryCnt++; + size += FOURBYTES + sizeof(struct lpfc_name); + if ((size + sizeof(struct lpfc_name)) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #8 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(struct lpfc_name)); + ad->AttrType = cpu_to_be16(RPRT_PORTNAME); + ad->AttrLen = cpu_to_be16(FOURBYTES + + sizeof(struct lpfc_name)); + memcpy(&ae->un.PortName, &vport->fc_sparam.portName, + sizeof(struct lpfc_name)); + pab->ab.EntryCnt++; + size += FOURBYTES + sizeof(struct lpfc_name); + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #9 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.NodeSymName)); + ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME); + len = lpfc_vport_symbolic_port_name(vport, + ae->un.NodeSymName, sizeof(ae->un.NodeSymName)); + len += (len & 3) ? (4 - (len & 3)) : 4; + ad->AttrLen = cpu_to_be16(FOURBYTES + len); + pab->ab.EntryCnt++; + size += FOURBYTES + len; + if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #10 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE); + ae->un.PortState = 0; + ad->AttrLen = cpu_to_be16(FOURBYTES + 4); + pab->ab.EntryCnt++; + size += FOURBYTES + 4; + if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #11 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS); + ae->un.SupportClass = + cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3); + ad->AttrLen = cpu_to_be16(FOURBYTES + 4); + pab->ab.EntryCnt++; + size += FOURBYTES + 4; + if ((size + sizeof(struct lpfc_name)) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #12 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(struct lpfc_name)); + ad->AttrType = cpu_to_be16(RPRT_FABRICNAME); + ad->AttrLen = cpu_to_be16(FOURBYTES + + sizeof(struct lpfc_name)); + memcpy(&ae->un.FabricName, &vport->fabric_nodename, + sizeof(struct lpfc_name)); + pab->ab.EntryCnt++; + size += FOURBYTES + sizeof(struct lpfc_name); + if ((size + LPFC_FDMI_MAX_AE_SIZE) > + (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #13 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + memset(ae, 0, sizeof(ae->un.FC4Types)); + ad->AttrType = + cpu_to_be16(RPRT_ACTIVE_FC4_TYPES); + ad->AttrLen = cpu_to_be16(FOURBYTES + 32); + ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */ + ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */ + ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */ + pab->ab.EntryCnt++; + size += FOURBYTES + 32; + if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #257 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ad->AttrType = cpu_to_be16(RPRT_PORT_STATE); + ae->un.PortState = 0; + ad->AttrLen = cpu_to_be16(FOURBYTES + 4); + pab->ab.EntryCnt++; + size += FOURBYTES + 4; + if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #258 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ad->AttrType = cpu_to_be16(RPRT_DISC_PORT); + ae->un.PortState = lpfc_find_map_node(vport); + ae->un.PortState = cpu_to_be32(ae->un.PortState); + ad->AttrLen = cpu_to_be16(FOURBYTES + 4); + pab->ab.EntryCnt++; + size += FOURBYTES + 4; + if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE)) + goto port_out; + + /* #259 Port attribute entry */ + ad = (struct lpfc_fdmi_attr_def *) + ((uint8_t *)pab + size); + ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; + ad->AttrType = cpu_to_be16(RPRT_PORT_ID); + ae->un.PortId = cpu_to_be32(vport->fc_myDID); + ad->AttrLen = cpu_to_be16(FOURBYTES + 4); + pab->ab.EntryCnt++; + size += FOURBYTES + 4; +port_out: + pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt); /* Total size */ size = GID_REQUEST_SZ - 4 + size; } break; + case SLI_MGMT_GHAT: + case SLI_MGMT_GRPL: + rsp_size = FC_MAX_NS_RSP; case SLI_MGMT_DHBA: - CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DHBA); - CtReq->CommandResponse.bits.Size = 0; - pe = (PORT_ENTRY *) & CtReq->un.PortID; - memcpy((uint8_t *) & pe->PortName, - (uint8_t *) & vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name); + case SLI_MGMT_DHAT: + pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID; + memcpy((uint8_t *)&pe->PortName, + (uint8_t *)&vport->fc_sparam.portName, + sizeof(struct lpfc_name)); + size = GID_REQUEST_SZ - 4 + sizeof(struct lpfc_name); break; + case SLI_MGMT_GPAT: + case SLI_MGMT_GPAS: + rsp_size = FC_MAX_NS_RSP; case SLI_MGMT_DPRT: - CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DPRT); - CtReq->CommandResponse.bits.Size = 0; - pe = (PORT_ENTRY *) & CtReq->un.PortID; - memcpy((uint8_t *) & pe->PortName, - (uint8_t *) & vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name); + case SLI_MGMT_DPA: + pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID; + memcpy((uint8_t *)&pe->PortName, + (uint8_t *)&vport->fc_sparam.portName, + sizeof(struct lpfc_name)); + size = GID_REQUEST_SZ - 4 + sizeof(struct lpfc_name); + break; + case SLI_MGMT_GRHL: + size = GID_REQUEST_SZ - 4; break; + default: + lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY, + "0298 FDMI cmdcode x%x not supported\n", + cmdcode); + goto fdmi_cmd_free_bmpvirt; } + CtReq->CommandResponse.bits.Size = cpu_to_be16(rsp_size); - bpl = (struct ulp_bde64 *) bmp->virt; - bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); - bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); + bpl = (struct ulp_bde64 *)bmp->virt; + bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys)); + bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys)); bpl->tus.f.bdeFlags = 0; bpl->tus.f.bdeSize = size; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - - cmpl = lpfc_cmpl_ct_cmd_fdmi; - /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count + /* + * The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count * to hold ndlp reference for the corresponding callback function. */ - if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0)) + if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, 0)) return 0; - /* Decrement ndlp reference count to release ndlp reference held + /* + * Decrement ndlp reference count to release ndlp reference held * for the failed command's callback function. */ lpfc_nlp_put(ndlp); +fdmi_cmd_free_bmpvirt: lpfc_mbuf_free(phba, bmp->virt, bmp->phys); fdmi_cmd_free_bmp: kfree(bmp); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 5633e7dadc08..513edcb0c2da 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2007-2014 Emulex. All rights reserved. * + * Copyright (C) 2007-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index c66088d0fd2a..851e8efe364e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -2243,8 +2243,7 @@ lpfc_adisc_done(struct lpfc_vport *vport) */ if (vport->port_state < LPFC_VPORT_READY) { /* If we get here, there is nothing to ADISC */ - if (vport->port_type == LPFC_PHYSICAL_PORT) - lpfc_issue_clear_la(phba, vport); + lpfc_issue_clear_la(phba, vport); if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { vport->num_disc_nodes = 0; /* go thru NPR list, issue ELS PLOGIs */ @@ -3338,7 +3337,11 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* FLOGI retry policy */ retry = 1; /* retry FLOGI forever */ - maxretry = 0; + if (phba->link_flag != LS_LOOPBACK_MODE) + maxretry = 0; + else + maxretry = 2; + if (cmdiocb->retry >= 100) delay = 5000; else if (cmdiocb->retry >= 32) @@ -3701,6 +3704,11 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); if (ndlp) { + lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, + "0006 rpi%x DID:%x flg:%x %d map:%x %p\n", + ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount), + ndlp->nlp_usg_map, ndlp); if (NLP_CHK_NODE_ACT(ndlp)) { lpfc_nlp_put(ndlp); /* This is the end of the default RPI cleanup logic for @@ -5198,7 +5206,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, port_state = vport->port_state; vport->fc_flag |= FC_PT2PT; vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - vport->port_state = LPFC_FLOGI; spin_unlock_irq(shost->host_lock); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3311 Rcv Flogi PS x%x new PS x%x " @@ -7173,7 +7180,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) return; } - if (vport->cfg_fdmi_on) { + if (vport->cfg_fdmi_on & LPFC_FDMI_SUPPORT) { /* If this is the first time, allocate an ndlp and initialize * it. Otherwise, make sure the node is enabled and then do the * login. diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 5452f1f4220e..2500f15d437f 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -3439,6 +3439,11 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) pmb->context1 = NULL; pmb->context2 = NULL; + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "0002 rpi:%x DID:%x flg:%x %d map:%x %p\n", + ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount), + ndlp->nlp_usg_map, ndlp); if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; @@ -3855,6 +3860,11 @@ out: ndlp->nlp_flag |= NLP_RPI_REGISTERED; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "0003 rpi:%x DID:%x flg:%x %d map%x %p\n", + ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount), + ndlp->nlp_usg_map, ndlp); if (vport->port_state < LPFC_VPORT_READY) { /* Link up discovery requires Fabric registration. */ @@ -4250,8 +4260,15 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->active_rrqs_xri_bitmap = active_rrqs_xri_bitmap; spin_unlock_irqrestore(&phba->ndlp_lock, flags); - if (vport->phba->sli_rev == LPFC_SLI_REV4) + if (vport->phba->sli_rev == LPFC_SLI_REV4) { ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba); + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "0008 rpi:%x DID:%x flg:%x refcnt:%d " + "map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount), + ndlp->nlp_usg_map, ndlp); + } if (state != NLP_STE_UNUSED_NODE) @@ -4276,9 +4293,12 @@ lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) return; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); - if (vport->phba->sli_rev == LPFC_SLI_REV4) + if (vport->phba->sli_rev == LPFC_SLI_REV4) { lpfc_cleanup_vports_rrqs(vport, ndlp); - lpfc_nlp_put(ndlp); + lpfc_unreg_rpi(vport, ndlp); + } else { + lpfc_nlp_put(ndlp); + } return; } @@ -4515,7 +4535,17 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) mbox->context1 = ndlp; mbox->mbox_cmpl = lpfc_nlp_logo_unreg; } else { - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + if (phba->sli_rev == LPFC_SLI_REV4 && + (!(vport->load_flag & FC_UNLOADING)) && + (bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_2)) { + mbox->context1 = lpfc_nlp_get(ndlp); + mbox->mbox_cmpl = + lpfc_sli4_unreg_rpi_cmpl_clr; + } else + mbox->mbox_cmpl = + lpfc_sli_def_mbox_cmpl; } rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); @@ -4741,6 +4771,11 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* For this case we need to cleanup the default rpi * allocated by the firmware. */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "0005 rpi:%x DID:%x flg:%x %d map:%x %p\n", + ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount), + ndlp->nlp_usg_map, ndlp); if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) { rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID, @@ -5070,8 +5105,7 @@ lpfc_disc_start(struct lpfc_vport *vport) !(vport->fc_flag & FC_PT2PT) && !(vport->fc_flag & FC_RSCN_MODE) && (phba->sli_rev < LPFC_SLI_REV4)) { - if (vport->port_type == LPFC_PHYSICAL_PORT) - lpfc_issue_clear_la(phba, vport); + lpfc_issue_clear_la(phba, vport); lpfc_issue_reg_vpi(phba, vport); return; } @@ -5082,8 +5116,7 @@ lpfc_disc_start(struct lpfc_vport *vport) */ if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) { /* If we get here, there is nothing to ADISC */ - if (vport->port_type == LPFC_PHYSICAL_PORT) - lpfc_issue_clear_la(phba, vport); + lpfc_issue_clear_la(phba, vport); if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { vport->num_disc_nodes = 0; @@ -5484,18 +5517,22 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_flag |= NLP_RPI_REGISTERED; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "0004 rpi:%x DID:%x flg:%x %d map:%x %p\n", + ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount), + ndlp->nlp_usg_map, ndlp); /* * Start issuing Fabric-Device Management Interface (FDMI) command to * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if * fdmi-on=2 (supporting RPA/hostnmae) */ - if (vport->cfg_fdmi_on == 1) - lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA); - else + if (vport->cfg_fdmi_on & LPFC_FDMI_REG_DELAY) mod_timer(&vport->fc_fdmitmo, jiffies + msecs_to_jiffies(1000 * 60)); + else + lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA); /* decrement the node reference count held for this callback * function. @@ -5650,6 +5687,13 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, INIT_LIST_HEAD(&ndlp->nlp_listp); if (vport->phba->sli_rev == LPFC_SLI_REV4) { ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba); + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "0007 rpi:%x DID:%x flg:%x refcnt:%d " + "map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount), + ndlp->nlp_usg_map, ndlp); + ndlp->active_rrqs_xri_bitmap = mempool_alloc(vport->phba->active_rrq_pool, GFP_KERNEL); @@ -5684,9 +5728,9 @@ lpfc_nlp_release(struct kref *kref) lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, "0279 lpfc_nlp_release: ndlp:x%p did %x " - "usgmap:x%x refcnt:%d\n", + "usgmap:x%x refcnt:%d rpi:%x\n", (void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); + atomic_read(&ndlp->kref.refcount), ndlp->nlp_rpi); /* remove ndlp from action. */ lpfc_nlp_remove(ndlp->vport, ndlp); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 236259252379..37beb9dc1311 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -107,6 +107,7 @@ struct lpfc_sli_ct_request { uint8_t ReasonCode; uint8_t Explanation; uint8_t VendorUnique; +#define LPFC_CT_PREAMBLE 20 /* Size of CTReq + 4 up to here */ union { uint32_t PortID; @@ -170,6 +171,8 @@ struct lpfc_sli_ct_request { } un; }; +#define LPFC_MAX_CT_SIZE (60 * 4096) + #define SLI_CT_REVISION 1 #define GID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ sizeof(struct gid)) @@ -1007,78 +1010,45 @@ typedef struct _ELS_PKT { /* Structure is in Big Endian format */ } un; } ELS_PKT; -/* - * FDMI - * HBA MAnagement Operations Command Codes - */ -#define SLI_MGMT_GRHL 0x100 /* Get registered HBA list */ -#define SLI_MGMT_GHAT 0x101 /* Get HBA attributes */ -#define SLI_MGMT_GRPL 0x102 /* Get registered Port list */ -#define SLI_MGMT_GPAT 0x110 /* Get Port attributes */ -#define SLI_MGMT_RHBA 0x200 /* Register HBA */ -#define SLI_MGMT_RHAT 0x201 /* Register HBA attributes */ -#define SLI_MGMT_RPRT 0x210 /* Register Port */ -#define SLI_MGMT_RPA 0x211 /* Register Port attributes */ -#define SLI_MGMT_DHBA 0x300 /* De-register HBA */ -#define SLI_MGMT_DPRT 0x310 /* De-register Port */ +/******** FDMI ********/ -/* - * Management Service Subtypes - */ -#define SLI_CT_FDMI_Subtypes 0x10 +/* lpfc_sli_ct_request defines the CT_IU preamble for FDMI commands */ +#define SLI_CT_FDMI_Subtypes 0x10 /* Management Service Subtype */ /* - * HBA Management Service Reject Code + * Registered Port List Format */ -#define REJECT_CODE 0x9 /* Unable to perform command request */ +struct lpfc_fdmi_reg_port_list { + uint32_t EntryCnt; + uint32_t pe; /* Variable-length array */ +}; -/* - * HBA Management Service Reject Reason Code - * Please refer to the Reason Codes above - */ -/* - * HBA Attribute Types - */ -#define NODE_NAME 0x1 -#define MANUFACTURER 0x2 -#define SERIAL_NUMBER 0x3 -#define MODEL 0x4 -#define MODEL_DESCRIPTION 0x5 -#define HARDWARE_VERSION 0x6 -#define DRIVER_VERSION 0x7 -#define OPTION_ROM_VERSION 0x8 -#define FIRMWARE_VERSION 0x9 -#define OS_NAME_VERSION 0xa -#define MAX_CT_PAYLOAD_LEN 0xb +/* Definitions for HBA / Port attribute entries */ -/* - * Port Attrubute Types - */ -#define SUPPORTED_FC4_TYPES 0x1 -#define SUPPORTED_SPEED 0x2 -#define PORT_SPEED 0x3 -#define MAX_FRAME_SIZE 0x4 -#define OS_DEVICE_NAME 0x5 -#define HOST_NAME 0x6 - -union AttributesDef { +struct lpfc_fdmi_attr_def { /* Defined in TLV format */ /* Structure is in Big Endian format */ - struct { - uint32_t AttrType:16; - uint32_t AttrLen:16; - } bits; - uint32_t word; + uint32_t AttrType:16; + uint32_t AttrLen:16; + uint32_t AttrValue; /* Marks start of Value (ATTRIBUTE_ENTRY) */ }; -/* - * HBA Attribute Entry (8 - 260 bytes) - */ -typedef struct { - union AttributesDef ad; +/* Attribute Entry */ +struct lpfc_fdmi_attr_entry { union { uint32_t VendorSpecific; + uint32_t SupportClass; + uint32_t SupportSpeed; + uint32_t PortSpeed; + uint32_t MaxFrameSize; + uint32_t MaxCTPayloadLen; + uint32_t PortState; + uint32_t PortId; + struct lpfc_name NodeName; + struct lpfc_name PortName; + struct lpfc_name FabricName; + uint8_t FC4Types[32]; uint8_t Manufacturer[64]; uint8_t SerialNumber[64]; uint8_t Model[256]; @@ -1087,97 +1057,115 @@ typedef struct { uint8_t DriverVersion[256]; uint8_t OptionROMVersion[256]; uint8_t FirmwareVersion[256]; - struct lpfc_name NodeName; - uint8_t SupportFC4Types[32]; - uint32_t SupportSpeed; - uint32_t PortSpeed; - uint32_t MaxFrameSize; + uint8_t OsHostName[256]; + uint8_t NodeSymName[256]; uint8_t OsDeviceName[256]; uint8_t OsNameVersion[256]; - uint32_t MaxCTPayloadLen; uint8_t HostName[256]; } un; -} ATTRIBUTE_ENTRY; +}; + +#define LPFC_FDMI_MAX_AE_SIZE sizeof(struct lpfc_fdmi_attr_entry) /* * HBA Attribute Block */ -typedef struct { - uint32_t EntryCnt; /* Number of HBA attribute entries */ - ATTRIBUTE_ENTRY Entry; /* Variable-length array */ -} ATTRIBUTE_BLOCK; +struct lpfc_fdmi_attr_block { + uint32_t EntryCnt; /* Number of HBA attribute entries */ + struct lpfc_fdmi_attr_entry Entry; /* Variable-length array */ +}; /* * Port Entry */ -typedef struct { +struct lpfc_fdmi_port_entry { struct lpfc_name PortName; -} PORT_ENTRY; +}; /* * HBA Identifier */ -typedef struct { +struct lpfc_fdmi_hba_ident { struct lpfc_name PortName; -} HBA_IDENTIFIER; - -/* - * Registered Port List Format - */ -typedef struct { - uint32_t EntryCnt; - PORT_ENTRY pe; /* Variable-length array */ -} REG_PORT_LIST; +}; /* * Register HBA(RHBA) */ -typedef struct { - HBA_IDENTIFIER hi; - REG_PORT_LIST rpl; /* variable-length array */ -/* ATTRIBUTE_BLOCK ab; */ -} REG_HBA; +struct lpfc_fdmi_reg_hba { + struct lpfc_fdmi_hba_ident hi; + struct lpfc_fdmi_reg_port_list rpl; /* variable-length array */ +/* struct lpfc_fdmi_attr_block ab; */ +}; /* * Register HBA Attributes (RHAT) */ -typedef struct { +struct lpfc_fdmi_reg_hbaattr { struct lpfc_name HBA_PortName; - ATTRIBUTE_BLOCK ab; -} REG_HBA_ATTRIBUTE; + struct lpfc_fdmi_attr_block ab; +}; /* * Register Port Attributes (RPA) */ -typedef struct { +struct lpfc_fdmi_reg_portattr { struct lpfc_name PortName; - ATTRIBUTE_BLOCK ab; -} REG_PORT_ATTRIBUTE; + struct lpfc_fdmi_attr_block ab; +}; /* - * Get Registered HBA List (GRHL) Accept Payload Format + * HBA MAnagement Operations Command Codes */ -typedef struct { - uint32_t HBA__Entry_Cnt; /* Number of Registered HBA Identifiers */ - struct lpfc_name HBA_PortName; /* Variable-length array */ -} GRHL_ACC_PAYLOAD; +#define SLI_MGMT_GRHL 0x100 /* Get registered HBA list */ +#define SLI_MGMT_GHAT 0x101 /* Get HBA attributes */ +#define SLI_MGMT_GRPL 0x102 /* Get registered Port list */ +#define SLI_MGMT_GPAT 0x110 /* Get Port attributes */ +#define SLI_MGMT_GPAS 0x120 /* Get Port Statistics */ +#define SLI_MGMT_RHBA 0x200 /* Register HBA */ +#define SLI_MGMT_RHAT 0x201 /* Register HBA attributes */ +#define SLI_MGMT_RPRT 0x210 /* Register Port */ +#define SLI_MGMT_RPA 0x211 /* Register Port attributes */ +#define SLI_MGMT_DHBA 0x300 /* De-register HBA */ +#define SLI_MGMT_DHAT 0x301 /* De-register HBA attributes */ +#define SLI_MGMT_DPRT 0x310 /* De-register Port */ +#define SLI_MGMT_DPA 0x311 /* De-register Port attributes */ /* - * Get Registered Port List (GRPL) Accept Payload Format + * HBA Attribute Types */ -typedef struct { - uint32_t RPL_Entry_Cnt; /* Number of Registered Port Entries */ - PORT_ENTRY Reg_Port_Entry[1]; /* Variable-length array */ -} GRPL_ACC_PAYLOAD; +#define RHBA_NODENAME 0x1 /* 8 byte WWNN */ +#define RHBA_MANUFACTURER 0x2 /* 4 to 64 byte ASCII string */ +#define RHBA_SERIAL_NUMBER 0x3 /* 4 to 64 byte ASCII string */ +#define RHBA_MODEL 0x4 /* 4 to 256 byte ASCII string */ +#define RHBA_MODEL_DESCRIPTION 0x5 /* 4 to 256 byte ASCII string */ +#define RHBA_HARDWARE_VERSION 0x6 /* 4 to 256 byte ASCII string */ +#define RHBA_DRIVER_VERSION 0x7 /* 4 to 256 byte ASCII string */ +#define RHBA_OPTION_ROM_VERSION 0x8 /* 4 to 256 byte ASCII string */ +#define RHBA_FIRMWARE_VERSION 0x9 /* 4 to 256 byte ASCII string */ +#define RHBA_OS_NAME_VERSION 0xa /* 4 to 256 byte ASCII string */ +#define RHBA_MAX_CT_PAYLOAD_LEN 0xb /* 32-bit unsigned int */ +#define RHBA_SYM_NODENAME 0xc /* 4 to 256 byte ASCII string */ /* - * Get Port Attributes (GPAT) Accept Payload Format + * Port Attrubute Types */ - -typedef struct { - ATTRIBUTE_BLOCK pab; -} GPAT_ACC_PAYLOAD; - +#define RPRT_SUPPORTED_FC4_TYPES 0x1 /* 32 byte binary array */ +#define RPRT_SUPPORTED_SPEED 0x2 /* 32-bit unsigned int */ +#define RPRT_PORT_SPEED 0x3 /* 32-bit unsigned int */ +#define RPRT_MAX_FRAME_SIZE 0x4 /* 32-bit unsigned int */ +#define RPRT_OS_DEVICE_NAME 0x5 /* 4 to 256 byte ASCII string */ +#define RPRT_HOST_NAME 0x6 /* 4 to 256 byte ASCII string */ +#define RPRT_NODENAME 0x7 /* 8 byte WWNN */ +#define RPRT_PORTNAME 0x8 /* 8 byte WWNN */ +#define RPRT_SYM_PORTNAME 0x9 /* 4 to 256 byte ASCII string */ +#define RPRT_PORT_TYPE 0xa /* 32-bit unsigned int */ +#define RPRT_SUPPORTED_CLASS 0xb /* 32-bit unsigned int */ +#define RPRT_FABRICNAME 0xc /* 8 byte Fabric WWNN */ +#define RPRT_ACTIVE_FC4_TYPES 0xd /* 32 byte binary array */ +#define RPRT_PORT_STATE 0x101 /* 32-bit unsigned int */ +#define RPRT_DISC_PORT 0x102 /* 32-bit unsigned int */ +#define RPRT_PORT_ID 0x103 /* 32-bit unsigned int */ /* * Begin HBA configuration parameters. diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index f432ec180cf8..1813c45946f4 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2014 Emulex. All rights reserved. * + * Copyright (C) 2009-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -3085,6 +3085,9 @@ struct lpfc_acqe_link { #define LPFC_ASYNC_LINK_SPEED_100MBPS 0x2 #define LPFC_ASYNC_LINK_SPEED_1GBPS 0x3 #define LPFC_ASYNC_LINK_SPEED_10GBPS 0x4 +#define LPFC_ASYNC_LINK_SPEED_20GBPS 0x5 +#define LPFC_ASYNC_LINK_SPEED_25GBPS 0x6 +#define LPFC_ASYNC_LINK_SPEED_40GBPS 0x7 #define lpfc_acqe_link_duplex_SHIFT 16 #define lpfc_acqe_link_duplex_MASK 0x000000FF #define lpfc_acqe_link_duplex_WORD word0 @@ -3166,7 +3169,7 @@ struct lpfc_acqe_fc_la { #define lpfc_acqe_fc_la_speed_SHIFT 24 #define lpfc_acqe_fc_la_speed_MASK 0x000000FF #define lpfc_acqe_fc_la_speed_WORD word0 -#define LPFC_FC_LA_SPEED_UNKOWN 0x0 +#define LPFC_FC_LA_SPEED_UNKNOWN 0x0 #define LPFC_FC_LA_SPEED_1G 0x1 #define LPFC_FC_LA_SPEED_2G 0x2 #define LPFC_FC_LA_SPEED_4G 0x4 @@ -3244,6 +3247,7 @@ struct lpfc_acqe_sli { #define LPFC_SLI_EVENT_TYPE_NVLOG_POST 0x4 #define LPFC_SLI_EVENT_TYPE_DIAG_DUMP 0x5 #define LPFC_SLI_EVENT_TYPE_MISCONFIGURED 0x9 +#define LPFC_SLI_EVENT_TYPE_REMOTE_DPORT 0xA }; /* diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 0b2c53af85c7..e8c8c1ecc1f5 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -1330,13 +1330,14 @@ lpfc_offline_eratt(struct lpfc_hba *phba) void lpfc_sli4_offline_eratt(struct lpfc_hba *phba) { + spin_lock_irq(&phba->hbalock); + phba->link_state = LPFC_HBA_ERROR; + spin_unlock_irq(&phba->hbalock); + lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT); lpfc_offline(phba); - lpfc_sli4_brdreset(phba); lpfc_hba_down_post(phba); - lpfc_sli4_post_status_check(phba); lpfc_unblock_mgmt_io(phba); - phba->link_state = LPFC_HBA_ERROR; } /** @@ -1629,6 +1630,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) uint32_t uerrlo_reg, uemasklo_reg; uint32_t pci_rd_rc1, pci_rd_rc2; bool en_rn_msg = true; + struct temp_event temp_event_data; int rc; /* If the pci channel is offline, ignore possible errors, since @@ -1636,9 +1638,6 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) */ if (pci_channel_offline(phba->pcidev)) return; - /* If resets are disabled then leave the HBA alone and return */ - if (!phba->cfg_enable_hba_reset) - return; if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); switch (if_type) { @@ -1654,6 +1653,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) return; lpfc_sli4_offline_eratt(phba); break; + case LPFC_SLI_INTF_IF_TYPE_2: pci_rd_rc1 = lpfc_readl( phba->sli4_hba.u.if_type2.STATUSregaddr, @@ -1668,15 +1668,27 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr); reg_err2 = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) { - /* TODO: Register for Overtemp async events. */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2889 Port Overtemperature event, " - "taking port offline\n"); + "taking port offline Data: x%x x%x\n", + reg_err1, reg_err2); + + temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; + temp_event_data.event_code = LPFC_CRIT_TEMP; + temp_event_data.data = 0xFFFFFFFF; + + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), + (char *)&temp_event_data, + SCSI_NL_VID_TYPE_PCI + | PCI_VENDOR_ID_EMULEX); + spin_lock_irq(&phba->hbalock); phba->over_temp_state = HBA_OVER_TEMP; spin_unlock_irq(&phba->hbalock); lpfc_sli4_offline_eratt(phba); - break; + return; } if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) { @@ -1693,6 +1705,10 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3145 Port Down: Provisioning\n"); + /* If resets are disabled then leave the HBA alone and return */ + if (!phba->cfg_enable_hba_reset) + return; + /* Check port status register for function reset */ rc = lpfc_sli4_port_sta_fn_reset(phba, LPFC_MBX_NO_WAIT, en_rn_msg); @@ -2759,9 +2775,19 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (NLP_CHK_NODE_ACT(ndlp)) + if (NLP_CHK_NODE_ACT(ndlp)) { ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(phba); + lpfc_printf_vlog(ndlp->vport, KERN_INFO, + LOG_NODE, + "0009 rpi:%x DID:%x " + "flg:%x map:%x %p\n", + ndlp->nlp_rpi, + ndlp->nlp_DID, + ndlp->nlp_flag, + ndlp->nlp_usg_map, + ndlp); + } } } } @@ -2925,8 +2951,18 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) * RPI. Get a new RPI when the adapter port * comes back online. */ - if (phba->sli_rev == LPFC_SLI_REV4) + if (phba->sli_rev == LPFC_SLI_REV4) { + lpfc_printf_vlog(ndlp->vport, + KERN_INFO, LOG_NODE, + "0011 lpfc_offline: " + "ndlp:x%p did %x " + "usgmap:x%x rpi:%x\n", + ndlp, ndlp->nlp_DID, + ndlp->nlp_usg_map, + ndlp->nlp_rpi); + lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); + } lpfc_unreg_rpi(vports[i], ndlp); } } @@ -3241,12 +3277,17 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) struct Scsi_Host *shost; int error = 0; - if (dev != &phba->pcidev->dev) + if (dev != &phba->pcidev->dev) { shost = scsi_host_alloc(&lpfc_vport_template, sizeof(struct lpfc_vport)); - else - shost = scsi_host_alloc(&lpfc_template, + } else { + if (phba->sli_rev == LPFC_SLI_REV4) + shost = scsi_host_alloc(&lpfc_template, sizeof(struct lpfc_vport)); + else + shost = scsi_host_alloc(&lpfc_template_s3, + sizeof(struct lpfc_vport)); + } if (!shost) goto out; @@ -3685,6 +3726,11 @@ lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba, case LPFC_ASYNC_LINK_SPEED_10GBPS: link_speed = LPFC_LINK_SPEED_10GHZ; break; + case LPFC_ASYNC_LINK_SPEED_20GBPS: + case LPFC_ASYNC_LINK_SPEED_25GBPS: + case LPFC_ASYNC_LINK_SPEED_40GBPS: + link_speed = LPFC_LINK_SPEED_UNKNOWN; + break; default: lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0483 Invalid link-attention link speed: x%x\n", @@ -3756,46 +3802,55 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code, switch (evt_code) { case LPFC_TRAILER_CODE_LINK: switch (speed_code) { - case LPFC_EVT_CODE_LINK_NO_LINK: + case LPFC_ASYNC_LINK_SPEED_ZERO: port_speed = 0; break; - case LPFC_EVT_CODE_LINK_10_MBIT: + case LPFC_ASYNC_LINK_SPEED_10MBPS: port_speed = 10; break; - case LPFC_EVT_CODE_LINK_100_MBIT: + case LPFC_ASYNC_LINK_SPEED_100MBPS: port_speed = 100; break; - case LPFC_EVT_CODE_LINK_1_GBIT: + case LPFC_ASYNC_LINK_SPEED_1GBPS: port_speed = 1000; break; - case LPFC_EVT_CODE_LINK_10_GBIT: + case LPFC_ASYNC_LINK_SPEED_10GBPS: port_speed = 10000; break; + case LPFC_ASYNC_LINK_SPEED_20GBPS: + port_speed = 20000; + break; + case LPFC_ASYNC_LINK_SPEED_25GBPS: + port_speed = 25000; + break; + case LPFC_ASYNC_LINK_SPEED_40GBPS: + port_speed = 40000; + break; default: port_speed = 0; } break; case LPFC_TRAILER_CODE_FC: switch (speed_code) { - case LPFC_EVT_CODE_FC_NO_LINK: + case LPFC_FC_LA_SPEED_UNKNOWN: port_speed = 0; break; - case LPFC_EVT_CODE_FC_1_GBAUD: + case LPFC_FC_LA_SPEED_1G: port_speed = 1000; break; - case LPFC_EVT_CODE_FC_2_GBAUD: + case LPFC_FC_LA_SPEED_2G: port_speed = 2000; break; - case LPFC_EVT_CODE_FC_4_GBAUD: + case LPFC_FC_LA_SPEED_4G: port_speed = 4000; break; - case LPFC_EVT_CODE_FC_8_GBAUD: + case LPFC_FC_LA_SPEED_8G: port_speed = 8000; break; - case LPFC_EVT_CODE_FC_10_GBAUD: + case LPFC_FC_LA_SPEED_10G: port_speed = 10000; break; - case LPFC_EVT_CODE_FC_16_GBAUD: + case LPFC_FC_LA_SPEED_16G: port_speed = 16000; break; default: @@ -4044,18 +4099,21 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) char port_name; char message[128]; uint8_t status; + uint8_t evt_type; + struct temp_event temp_event_data; struct lpfc_acqe_misconfigured_event *misconfigured; + struct Scsi_Host *shost; + + evt_type = bf_get(lpfc_trailer_type, acqe_sli); - /* special case misconfigured event as it contains data for all ports */ - if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_2) || - (bf_get(lpfc_trailer_type, acqe_sli) != - LPFC_SLI_EVENT_TYPE_MISCONFIGURED)) { + /* Special case Lancer */ + if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != + LPFC_SLI_INTF_IF_TYPE_2) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2901 Async SLI event - Event Data1:x%08x Event Data2:" "x%08x SLI Event Type:%d\n", acqe_sli->event_data1, acqe_sli->event_data2, - bf_get(lpfc_trailer_type, acqe_sli)); + evt_type); return; } @@ -4063,58 +4121,107 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) if (port_name == 0x00) port_name = '?'; /* get port name is empty */ - misconfigured = (struct lpfc_acqe_misconfigured_event *) + switch (evt_type) { + case LPFC_SLI_EVENT_TYPE_OVER_TEMP: + temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; + temp_event_data.event_code = LPFC_THRESHOLD_TEMP; + temp_event_data.data = (uint32_t)acqe_sli->event_data1; + + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3190 Over Temperature:%d Celsius- Port Name %c\n", + acqe_sli->event_data1, port_name); + + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), + (char *)&temp_event_data, + SCSI_NL_VID_TYPE_PCI + | PCI_VENDOR_ID_EMULEX); + break; + case LPFC_SLI_EVENT_TYPE_NORM_TEMP: + temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; + temp_event_data.event_code = LPFC_NORMAL_TEMP; + temp_event_data.data = (uint32_t)acqe_sli->event_data1; + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3191 Normal Temperature:%d Celsius - Port Name %c\n", + acqe_sli->event_data1, port_name); + + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), + (char *)&temp_event_data, + SCSI_NL_VID_TYPE_PCI + | PCI_VENDOR_ID_EMULEX); + break; + case LPFC_SLI_EVENT_TYPE_MISCONFIGURED: + misconfigured = (struct lpfc_acqe_misconfigured_event *) &acqe_sli->event_data1; - /* fetch the status for this port */ - switch (phba->sli4_hba.lnk_info.lnk_no) { - case LPFC_LINK_NUMBER_0: - status = bf_get(lpfc_sli_misconfigured_port0, + /* fetch the status for this port */ + switch (phba->sli4_hba.lnk_info.lnk_no) { + case LPFC_LINK_NUMBER_0: + status = bf_get(lpfc_sli_misconfigured_port0, &misconfigured->theEvent); - break; - case LPFC_LINK_NUMBER_1: - status = bf_get(lpfc_sli_misconfigured_port1, + break; + case LPFC_LINK_NUMBER_1: + status = bf_get(lpfc_sli_misconfigured_port1, &misconfigured->theEvent); - break; - case LPFC_LINK_NUMBER_2: - status = bf_get(lpfc_sli_misconfigured_port2, + break; + case LPFC_LINK_NUMBER_2: + status = bf_get(lpfc_sli_misconfigured_port2, &misconfigured->theEvent); - break; - case LPFC_LINK_NUMBER_3: - status = bf_get(lpfc_sli_misconfigured_port3, + break; + case LPFC_LINK_NUMBER_3: + status = bf_get(lpfc_sli_misconfigured_port3, &misconfigured->theEvent); - break; - default: - status = ~LPFC_SLI_EVENT_STATUS_VALID; - break; - } + break; + default: + status = ~LPFC_SLI_EVENT_STATUS_VALID; + break; + } - switch (status) { - case LPFC_SLI_EVENT_STATUS_VALID: - return; /* no message if the sfp is okay */ - case LPFC_SLI_EVENT_STATUS_NOT_PRESENT: - sprintf(message, "Optics faulted/incorrectly installed/not " \ - "installed - Reseat optics, if issue not " - "resolved, replace."); - break; - case LPFC_SLI_EVENT_STATUS_WRONG_TYPE: - sprintf(message, - "Optics of two types installed - Remove one optic or " \ - "install matching pair of optics."); - break; - case LPFC_SLI_EVENT_STATUS_UNSUPPORTED: - sprintf(message, "Incompatible optics - Replace with " \ + switch (status) { + case LPFC_SLI_EVENT_STATUS_VALID: + return; /* no message if the sfp is okay */ + case LPFC_SLI_EVENT_STATUS_NOT_PRESENT: + sprintf(message, "Optics faulted/incorrectly " + "installed/not installed - Reseat optics, " + "if issue not resolved, replace."); + break; + case LPFC_SLI_EVENT_STATUS_WRONG_TYPE: + sprintf(message, + "Optics of two types installed - Remove one " + "optic or install matching pair of optics."); + break; + case LPFC_SLI_EVENT_STATUS_UNSUPPORTED: + sprintf(message, "Incompatible optics - Replace with " "compatible optics for card to function."); + break; + default: + /* firmware is reporting a status we don't know about */ + sprintf(message, "Unknown event status x%02x", status); + break; + } + + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3176 Misconfigured Physical Port - " + "Port Name %c %s\n", port_name, message); + break; + case LPFC_SLI_EVENT_TYPE_REMOTE_DPORT: + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3192 Remote DPort Test Initiated - " + "Event Data1:x%08x Event Data2: x%08x\n", + acqe_sli->event_data1, acqe_sli->event_data2); break; default: - /* firmware is reporting a status we don't know about */ - sprintf(message, "Unknown event status x%02x", status); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3193 Async SLI event - Event Data1:x%08x Event Data2:" + "x%08x SLI Event Type:%d\n", + acqe_sli->event_data1, acqe_sli->event_data2, + evt_type); break; } - - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3176 Misconfigured Physical Port - " - "Port Name %c %s\n", port_name, message); } /** @@ -5183,6 +5290,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) rc = lpfc_pci_function_reset(phba); if (unlikely(rc)) return -ENODEV; + phba->temp_sensor_support = 1; } /* Create the bootstrap mailbox command */ @@ -7647,6 +7755,14 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) goto out_destroy_els_rq; } } + + /* + * Configure EQ delay multipier for interrupt coalescing using + * MODIFY_EQ_DELAY for all EQs created, LPFC_MAX_EQ_DELAY at a time. + */ + for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_io_channel; + fcp_eqidx += LPFC_MAX_EQ_DELAY) + lpfc_modify_fcp_eq_delay(phba, fcp_eqidx); return 0; out_destroy_els_rq: @@ -7953,7 +8069,7 @@ wait: * up to 30 seconds. If the port doesn't respond, treat * it as an error. */ - for (rdy_chk = 0; rdy_chk < 3000; rdy_chk++) { + for (rdy_chk = 0; rdy_chk < 1500; rdy_chk++) { if (lpfc_readl(phba->sli4_hba.u.if_type2. STATUSregaddr, ®_data.word0)) { rc = -ENODEV; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 06241f590c1e..816f596cda60 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 5cc1103d811e..4cb9882af157 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2013 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -276,6 +276,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; + uint64_t nlp_portwwn = 0; uint32_t *lp; IOCB_t *icmd; struct serv_parm *sp; @@ -332,6 +333,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, NULL); return 0; } + + nlp_portwwn = wwn_to_u64(ndlp->nlp_portname.u.wwn); if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) { /* Reject this request because invalid parameters */ stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; @@ -367,7 +370,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; - /* no need to reg_login if we are already in one of these states */ + /* if already logged in, do implicit logout */ switch (ndlp->nlp_state) { case NLP_STE_NPR_NODE: if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) @@ -376,8 +379,26 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, case NLP_STE_PRLI_ISSUE: case NLP_STE_UNMAPPED_NODE: case NLP_STE_MAPPED_NODE: - lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); - return 1; + /* lpfc_plogi_confirm_nport skips fabric did, handle it here */ + if (!(ndlp->nlp_type & NLP_FABRIC)) { + lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, + ndlp, NULL); + return 1; + } + if (nlp_portwwn != 0 && + nlp_portwwn != wwn_to_u64(sp->portName.u.wwn)) + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0143 PLOGI recv'd from DID: x%x " + "WWPN changed: old %llx new %llx\n", + ndlp->nlp_DID, + (unsigned long long)nlp_portwwn, + (unsigned long long) + wwn_to_u64(sp->portName.u.wwn)); + + ndlp->nlp_prev_state = ndlp->nlp_state; + /* rport needs to be unregistered first */ + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + break; } /* Check for Nport to NPort pt2pt protocol */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 4f9222eb2266..cb73cf9e9ba5 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -1130,6 +1130,25 @@ lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) } /** + * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB + * @data: A pointer to the immediate command data portion of the IOCB. + * @fcp_cmnd: The FCP Command that is provided by the SCSI layer. + * + * The routine copies the entire FCP command from @fcp_cmnd to @data while + * byte swapping the data to big endian format for transmission on the wire. + **/ +static void +lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) +{ + int i, j; + + for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); + i += sizeof(uint32_t), j++) { + ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); + } +} + +/** * lpfc_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec * @phba: The Hba for which this call is being executed. * @lpfc_cmd: The scsi buffer which is going to be mapped. @@ -1264,6 +1283,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) * we need to set word 4 of IOCB here */ iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); + lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); return 0; } @@ -4127,24 +4147,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } /** - * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB - * @data: A pointer to the immediate command data portion of the IOCB. - * @fcp_cmnd: The FCP Command that is provided by the SCSI layer. - * - * The routine copies the entire FCP command from @fcp_cmnd to @data while - * byte swapping the data to big endian format for transmission on the wire. - **/ -static void -lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) -{ - int i, j; - for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); - i += sizeof(uint32_t), j++) { - ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); - } -} - -/** * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: The scsi command which needs to send. @@ -4223,9 +4225,6 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, fcp_cmnd->fcpCntl3 = 0; phba->fc4ControlRequests++; } - if (phba->sli_rev == 3 && - !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) - lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); /* * Finish initializing those IOCB fields that are independent * of the scsi_cmnd request_buffer @@ -5118,9 +5117,10 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) int status; rdata = lpfc_rport_data_from_scsi_device(cmnd->device); - if (!rdata) { + if (!rdata || !rdata->pnode) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0798 Device Reset rport failure: rdata x%p\n", rdata); + "0798 Device Reset rport failure: rdata x%p\n", + rdata); return FAILED; } pnode = rdata->pnode; @@ -5202,10 +5202,12 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) if (status == FAILED) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, "0722 Target Reset rport failure: rdata x%p\n", rdata); - spin_lock_irq(shost->host_lock); - pnode->nlp_flag &= ~NLP_NPR_ADISC; - pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - spin_unlock_irq(shost->host_lock); + if (pnode) { + spin_lock_irq(shost->host_lock); + pnode->nlp_flag &= ~NLP_NPR_ADISC; + pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + spin_unlock_irq(shost->host_lock); + } lpfc_reset_flush_io_context(vport, tgt_id, lun_id, LPFC_CTX_TGT); return FAST_IO_FAIL; @@ -5857,6 +5859,31 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, return false; } +struct scsi_host_template lpfc_template_s3 = { + .module = THIS_MODULE, + .name = LPFC_DRIVER_NAME, + .info = lpfc_info, + .queuecommand = lpfc_queuecommand, + .eh_abort_handler = lpfc_abort_handler, + .eh_device_reset_handler = lpfc_device_reset_handler, + .eh_target_reset_handler = lpfc_target_reset_handler, + .eh_bus_reset_handler = lpfc_bus_reset_handler, + .slave_alloc = lpfc_slave_alloc, + .slave_configure = lpfc_slave_configure, + .slave_destroy = lpfc_slave_destroy, + .scan_finished = lpfc_scan_finished, + .this_id = -1, + .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, + .cmd_per_lun = LPFC_CMD_PER_LUN, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = lpfc_hba_attrs, + .max_sectors = 0xFFFF, + .vendor_id = LPFC_NL_VENDOR_ID, + .change_queue_depth = scsi_change_queue_depth, + .use_blk_tags = 1, + .track_queue_depth = 1, +}; + struct scsi_host_template lpfc_template = { .module = THIS_MODULE, .name = LPFC_DRIVER_NAME, diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 0389ac1e7b83..474e30cdee6e 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 207a43d952fa..56f73682d4bd 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -918,12 +918,16 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) lpfc_cmd = (struct lpfc_scsi_buf *) piocbq->context1; ndlp = lpfc_cmd->rdata->pnode; } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) && - !(piocbq->iocb_flag & LPFC_IO_LIBDFC)) + !(piocbq->iocb_flag & LPFC_IO_LIBDFC)) { ndlp = piocbq->context_un.ndlp; - else if (piocbq->iocb_flag & LPFC_IO_LIBDFC) - ndlp = piocbq->context_un.ndlp; - else + } else if (piocbq->iocb_flag & LPFC_IO_LIBDFC) { + if (piocbq->iocb_flag & LPFC_IO_LOOPBACK) + ndlp = NULL; + else + ndlp = piocbq->context_un.ndlp; + } else { ndlp = piocbq->context1; + } list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list); start_sglq = sglq; @@ -2213,6 +2217,46 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) else mempool_free(pmb, phba->mbox_mem_pool); } + /** + * lpfc_sli4_unreg_rpi_cmpl_clr - mailbox completion handler + * @phba: Pointer to HBA context object. + * @pmb: Pointer to mailbox object. + * + * This function is the unreg rpi mailbox completion handler. It + * frees the memory resources associated with the completed mailbox + * command. An additional refrenece is put on the ndlp to prevent + * lpfc_nlp_release from freeing the rpi bit in the bitmask before + * the unreg mailbox command completes, this routine puts the + * reference back. + * + **/ +void +lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + struct lpfc_vport *vport = pmb->vport; + struct lpfc_nodelist *ndlp; + + ndlp = pmb->context1; + if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) { + if (phba->sli_rev == LPFC_SLI_REV4 && + (bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf) == + LPFC_SLI_INTF_IF_TYPE_2)) { + if (ndlp) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "0010 UNREG_LOGIN vpi:%x " + "rpi:%x DID:%x map:%x %p\n", + vport->vpi, ndlp->nlp_rpi, + ndlp->nlp_DID, + ndlp->nlp_usg_map, ndlp); + + lpfc_nlp_put(ndlp); + } + } + } + + mempool_free(pmb, phba->mbox_mem_pool); +} /** * lpfc_sli_handle_mb_event - Handle mailbox completions from firmware @@ -12842,7 +12886,7 @@ lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset) * fails this function will return -ENXIO. **/ int -lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint16_t startq) +lpfc_modify_fcp_eq_delay(struct lpfc_hba *phba, uint32_t startq) { struct lpfc_mbx_modify_eq_delay *eq_delay; LPFC_MBOXQ_t *mbox; @@ -12959,11 +13003,8 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) bf_set(lpfc_eq_context_size, &eq_create->u.request.context, LPFC_EQE_SIZE); bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1); - /* Calculate delay multiper from maximum interrupt per second */ - if (imax > LPFC_DMULT_CONST) - dmult = 0; - else - dmult = LPFC_DMULT_CONST/imax - 1; + /* don't setup delay multiplier using EQ_CREATE */ + dmult = 0; bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context, dmult); switch (eq->entry_count) { @@ -15662,14 +15703,14 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) struct lpfc_rpi_hdr *rpi_hdr; unsigned long iflag; - max_rpi = phba->sli4_hba.max_cfg_param.max_rpi; - rpi_limit = phba->sli4_hba.next_rpi; - /* * Fetch the next logical rpi. Because this index is logical, * the driver starts at 0 each time. */ spin_lock_irqsave(&phba->hbalock, iflag); + max_rpi = phba->sli4_hba.max_cfg_param.max_rpi; + rpi_limit = phba->sli4_hba.next_rpi; + rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, 0); if (rpi >= rpi_limit) rpi = LPFC_RPI_ALLOC_ERROR; @@ -15678,6 +15719,9 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) phba->sli4_hba.max_cfg_param.rpi_used++; phba->sli4_hba.rpi_count++; } + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "0001 rpi:%x max:%x lim:%x\n", + (int) rpi, max_rpi, rpi_limit); /* * Don't try to allocate more rpi header regions if the device limit diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 4a01452415cf..7fe99ff80846 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -80,6 +80,7 @@ struct lpfc_iocbq { #define LPFC_IO_OAS 0x10000 /* OAS FCP IO */ #define LPFC_IO_FOF 0x20000 /* FOF FCP IO */ +#define LPFC_IO_LOOPBACK 0x40000 /* Loopback IO */ uint32_t drvrTimeout; /* driver timeout in seconds */ uint32_t fcp_wqidx; /* index to FCP work queue */ diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 22ceb2b05ba1..6eca3b8124d3 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2014 Emulex. All rights reserved. * + * Copyright (C) 2009-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -671,7 +671,7 @@ struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t, uint32_t); void lpfc_sli4_queue_free(struct lpfc_queue *); int lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint32_t); -int lpfc_modify_fcp_eq_delay(struct lpfc_hba *, uint16_t); +int lpfc_modify_fcp_eq_delay(struct lpfc_hba *, uint32_t); int lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *, struct lpfc_queue *, uint32_t, uint32_t); int32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *, diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 89413add2252..c37bb9f91c3b 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2014 Emulex. All rights reserved. * + * Copyright (C) 2004-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "10.4.8000.0." +#define LPFC_DRIVER_VERSION "10.5.0.0." #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ @@ -30,4 +30,4 @@ #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright(c) 2004-2014 Emulex. All rights reserved." +#define LPFC_COPYRIGHT "Copyright(c) 2004-2015 Emulex. All rights reserved." |