Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 27 Jul 2016 21:48:37 +0000 (14:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 27 Jul 2016 21:48:37 +0000 (14:48 -0700)
Pull SCSI updates from James Bottomley:
 "This update includes the usual round of driver updates (fcoe, lpfc,
  ufs, qla2xxx, hisi_sas).  The most important other change is removing
  the flag to allow non-blk_mq on a per host basis (it's unused); there
  is still a global module parameter for all of SCSI just in case.

  The rest are an assortment of minor fixes and typo updates"

* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (101 commits)
  scsi:libsas: fix oops caused by assigning a freed task to ->lldd_task
  fnic: pci_dma_mapping_error() doesn't return an error code
  scsi: lpfc: avoid harmless comparison warning
  fcoe: implement FIP VLAN responder
  fcoe: Rename 'fip_frame' to 'fip_vn2vn_notify_frame'
  lpfc: call lpfc_sli_validate_fcp_iocb() with the hbalock held
  scsi: ufs: remove unnecessary goto label
  hpsa: change hpsa_passthru_ioctl timeout
  hpsa: correct skipping masked peripherals
  qla2xxx: Update driver version to 8.07.00.38-k
  qla2xxx: Fix BBCR offset
  qla2xxx: Fix duplicate message id.
  qla2xxx: Disable the adapter and skip error recovery in case of register disconnect.
  qla2xxx: Separate ISP type bits out from device type.
  qla2xxx: Correction to function qla26xx_dport_diagnostics().
  qla2xxx: Add support to handle Loop Init error Asynchronus event.
  qla2xxx: Let DPORT be enabled purely by nvram.
  qla2xxx: Add bsg interface to support statistics counter reset.
  qla2xxx: Add bsg interface to support D_Port Diagnostics.
  qla2xxx: Check for device state before unloading the driver.
  ...

91 files changed:
Documentation/devicetree/bindings/ufs/tc-dwc-g210-pltfrm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
MAINTAINERS
drivers/scsi/53c700.c
drivers/scsi/53c700.h
drivers/scsi/Kconfig
drivers/scsi/aacraid/commctrl.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/cxlflash/main.c
drivers/scsi/cxlflash/main.h
drivers/scsi/cxlflash/sislite.h
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe_ctlr.c
drivers/scsi/fcoe/fcoe_sysfs.c
drivers/scsi/fcoe/fcoe_transport.c
drivers/scsi/fnic/fnic_fcs.c
drivers/scsi/fnic/fnic_fip.h
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hosts.c
drivers/scsi/hpsa.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_attr.h [new file with mode: 0644]
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_ids.h [new file with mode: 0644]
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_scsi.h
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/mpt3sas/mpt3sas_transport.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_bsg.h
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_tmpl.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/snic/snic_disc.c
drivers/scsi/snic/snic_fwint.h
drivers/scsi/storvsc_drv.c
drivers/scsi/ufs/Kconfig
drivers/scsi/ufs/Makefile
drivers/scsi/ufs/tc-dwc-g210-pci.c [new file with mode: 0644]
drivers/scsi/ufs/tc-dwc-g210-pltfrm.c [new file with mode: 0644]
drivers/scsi/ufs/tc-dwc-g210.c [new file with mode: 0644]
drivers/scsi/ufs/tc-dwc-g210.h [new file with mode: 0644]
drivers/scsi/ufs/ufshcd-dwc.c [new file with mode: 0644]
drivers/scsi/ufs/ufshcd-dwc.h [new file with mode: 0644]
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/scsi/ufs/ufshci-dwc.h [new file with mode: 0644]
drivers/scsi/ufs/ufshci.h
drivers/scsi/ufs/unipro.h
drivers/scsi/vmw_pvscsi.c
drivers/scsi/vmw_pvscsi.h
drivers/scsi/wd7000.c
include/scsi/fc/fc_fip.h
include/scsi/libfc.h
include/scsi/libfcoe.h
include/scsi/scsi_device.h
include/scsi/scsi_host.h

diff --git a/Documentation/devicetree/bindings/ufs/tc-dwc-g210-pltfrm.txt b/Documentation/devicetree/bindings/ufs/tc-dwc-g210-pltfrm.txt
new file mode 100644 (file)
index 0000000..71c0777
--- /dev/null
@@ -0,0 +1,26 @@
+* Universal Flash Storage (UFS) DesignWare Host Controller
+
+DWC_UFS nodes are defined to describe on-chip UFS host controllers and MPHY.
+Each UFS controller instance should have its own node.
+
+Required properties:
+- compatible   : compatible list must contain the PHY type & version:
+                       "snps,g210-tc-6.00-20bit"
+                       "snps,g210-tc-6.00-40bit"
+                 complemented with the Controller IP version:
+                       "snps,dwc-ufshcd-1.40a"
+                 complemented with the JEDEC version:
+                       "jedec,ufs-1.1"
+                       "jedec,ufs-2.0"
+
+- reg          : <registers mapping>
+- interrupts   : <interrupt mapping for UFS host controller IRQ>
+
+Example for a setup using a 1.40a DWC Controller with a 6.00 G210 40-bit TC:
+       dwc-ufs@d0000000 {
+               compatible = "snps,g210-tc-6.00-40bit",
+                            "snps,dwc-ufshcd-1.40a",
+                            "jedec,ufs-2.0";
+               reg = < 0xd0000000 0x10000 >;
+               interrupts = < 24 >;
+       };
index 66f6adf8d44da55c87cb1fdd5ef501e40c3ea273..a99ed5565b26c406ef6e643c99d6c1eb08fedeac 100644 (file)
@@ -4,8 +4,8 @@ UFSHC nodes are defined to describe on-chip UFS host controllers.
 Each UFS controller instance should have its own node.
 
 Required properties:
-- compatible           : must contain "jedec,ufs-1.1", may also list one or more
-                                         of the following:
+- compatible           : must contain "jedec,ufs-1.1" or "jedec,ufs-2.0", may
+                         also list one or more of the following:
                                          "qcom,msm8994-ufshc"
                                          "qcom,msm8996-ufshc"
                                          "qcom,ufshc"
index 403c162b0b2849d6adb06213ac5ee39df569dcf6..c1739eba622d66b5b021e3ea533b581bf4c5cfc3 100644 (file)
@@ -213,7 +213,7 @@ S:  Maintained
 F:     drivers/media/dvb-frontends/a8293*
 
 AACRAID SCSI RAID DRIVER
-M:     Adaptec OEM Raid Solutions <aacraid@adaptec.com>
+M:     Adaptec OEM Raid Solutions <aacraid@microsemi.com>
 L:     linux-scsi@vger.kernel.org
 W:     http://www.adaptec.com/
 S:     Supported
@@ -4699,7 +4699,7 @@ S:        Maintained
 F:     drivers/staging/fbtft/
 
 FCOE SUBSYSTEM (libfc, libfcoe, fcoe)
-M:     Vasu Dev <vasu.dev@intel.com>
+M:     Johannes Thumshirn <jth@kernel.org>
 L:     fcoe-devel@open-fcoe.org
 W:     www.Open-FCoE.org
 S:     Supported
@@ -10260,6 +10260,7 @@ M:      "Martin K. Petersen" <martin.petersen@oracle.com>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
+F:     Documentation/devicetree/bindings/scsi/
 F:     drivers/scsi/
 F:     include/scsi/
 
@@ -11894,6 +11895,12 @@ S:     Supported
 F:     Documentation/scsi/ufs.txt
 F:     drivers/scsi/ufs/
 
+UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER DWC HOOKS
+M:     Joao Pinto <Joao.Pinto@synopsys.com>
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/ufs/*dwc*
+
 UNSORTED BLOCK IMAGES (UBI)
 M:     Artem Bityutskiy <dedekind1@gmail.com>
 M:     Richard Weinberger <richard@nod.at>
@@ -11919,8 +11926,7 @@ S:      Maintained
 F:     drivers/net/wireless/ath/ar5523/
 
 USB ATTACHED SCSI
-M:     Hans de Goede <hdegoede@redhat.com>
-M:     Gerd Hoffmann <kraxel@redhat.com>
+M:     Oliver Neukum <oneukum@suse.com>
 L:     linux-usb@vger.kernel.org
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
@@ -12419,7 +12425,7 @@ S:      Maintained
 F:     drivers/net/vmxnet3/
 
 VMware PVSCSI driver
-M:     Arvind Kumar <arvindkumar@vmware.com>
+M:     Jim Gill <jgill@vmware.com>
 M:     VMware PV-Drivers <pv-drivers@vmware.com>
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
index 3ddc85e6efd65c845fa3a306c832ad2b1a48ac1d..95e32a47face78967efe394f86c7e7c281c7c466 100644 (file)
@@ -1120,9 +1120,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
                                "reselection is tag %d, slot %p(%d)\n",
                                hostdata->msgin[2], slot, slot->tag);
                } else {
-                       struct scsi_cmnd *SCp;
+                       struct NCR_700_Device_Parameters *p = SDp->hostdata;
+                       struct scsi_cmnd *SCp = p->current_cmnd;
 
-                       SCp = SDp->current_cmnd;
                        if(unlikely(SCp == NULL)) {
                                sdev_printk(KERN_ERR, SDp,
                                        "no saved request for untagged cmd\n");
@@ -1825,9 +1825,11 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
                CDEBUG(KERN_DEBUG, SCp, "sending out tag %d, slot %p\n",
                       slot->tag, slot);
        } else {
+               struct NCR_700_Device_Parameters *p = SCp->device->hostdata;
+
                slot->tag = SCSI_NO_TAG;
                /* save current command for reselection */
-               SCp->device->current_cmnd = SCp;
+               p->current_cmnd = SCp;
        }
        /* sanity check: some of the commands generated by the mid-layer
         * have an eccentric idea of their sc_data_direction */
@@ -1892,7 +1894,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
                slot->SG[i].ins = bS_to_host(SCRIPT_RETURN);
                slot->SG[i].pAddr = 0;
                dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG), DMA_TO_DEVICE);
-               DEBUG((" SETTING %08lx to %x\n",
+               DEBUG((" SETTING %p to %x\n",
                       (&slot->pSG[i].ins),
                       slot->SG[i].ins));
        }
index e06bdfeab420013f4655251623a3d6b6f5e56f9b..f34c916b95bc02f13c819f8796d71ef69e7de1bb 100644 (file)
@@ -82,6 +82,7 @@ struct NCR_700_Device_Parameters {
         * cmnd[1], this could be in static storage */
        unsigned char cmnd[MAX_COMMAND_SIZE];
        __u8    depth;
+       struct scsi_cmnd *current_cmnd; /* currently active command */
 };
 
 
@@ -423,23 +424,25 @@ struct NCR_700_Host_Parameters {
 #define script_patch_32(dev, script, symbol, value) \
 { \
        int i; \
+       dma_addr_t da = value; \
        for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
-               __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]) + value; \
+               __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]) + da; \
                (script)[A_##symbol##_used[i]] = bS_to_host(val); \
                dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
-               DEBUG((" script, patching %s at %d to 0x%lx\n", \
-                      #symbol, A_##symbol##_used[i], (value))); \
+               DEBUG((" script, patching %s at %d to %pad\n", \
+                      #symbol, A_##symbol##_used[i], &da)); \
        } \
 }
 
 #define script_patch_32_abs(dev, script, symbol, value) \
 { \
        int i; \
+       dma_addr_t da = value; \
        for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
-               (script)[A_##symbol##_used[i]] = bS_to_host(value); \
+               (script)[A_##symbol##_used[i]] = bS_to_host(da); \
                dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
-               DEBUG((" script, patching %s at %d to 0x%lx\n", \
-                      #symbol, A_##symbol##_used[i], (value))); \
+               DEBUG((" script, patching %s at %d to %pad\n", \
+                      #symbol, A_##symbol##_used[i], &da)); \
        } \
 }
 
index 98e5d51a33460e8979a8396db8d8ebf427919f96..1918f5483b23debd923aa5412e9797a2e6bbb46d 100644 (file)
@@ -1433,7 +1433,7 @@ config SCSI_U14_34F_MAX_TAGS
 
 config SCSI_ULTRASTOR
        tristate "UltraStor SCSI support"
-       depends on X86 && ISA && SCSI
+       depends on X86 && ISA && SCSI && ISA_DMA_API
        ---help---
          This is support for the UltraStor 14F, 24F and 34F SCSI-2 host
          adapter family.  This driver is explained in section 3.12 of the
index 4b3bb52b5108edbabf253d800a083c3f637c9380..b381b3718a98f5d484b1769fc4ef727f5fd4c0bd 100644 (file)
@@ -635,15 +635,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                        }
                } else {
                        struct user_sgmap* usg;
-                       usg = kmalloc(actual_fibsize - sizeof(struct aac_srb)
-                         + sizeof(struct sgmap), GFP_KERNEL);
+                       usg = kmemdup(upsg,
+                                     actual_fibsize - sizeof(struct aac_srb)
+                                     + sizeof(struct sgmap), GFP_KERNEL);
                        if (!usg) {
                                dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n"));
                                rcode = -ENOMEM;
                                goto cleanup;
                        }
-                       memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb)
-                         + sizeof(struct sgmap));
                        actual_fibsize = actual_fibsize64;
 
                        for (i = 0; i < usg->count; i++) {
index a1881993982c4bcf53fde6fd88a43dab0a9fd966..a5052dd8d7e6883d11af96e404c548ddd99c66fb 100644 (file)
@@ -57,7 +57,7 @@ static struct scsi_host_template bnx2fc_shost_template;
 static struct fc_function_template bnx2fc_transport_function;
 static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ;
 static struct fc_function_template bnx2fc_vport_xport_function;
-static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode);
+static int bnx2fc_create(struct net_device *netdev, enum fip_mode fip_mode);
 static void __bnx2fc_destroy(struct bnx2fc_interface *interface);
 static int bnx2fc_destroy(struct net_device *net_device);
 static int bnx2fc_enable(struct net_device *netdev);
@@ -486,7 +486,7 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
 
        __skb_queue_tail(&bg->fcoe_rx_list, skb);
        if (bg->fcoe_rx_list.qlen == 1)
-               wake_up_process(bg->thread);
+               wake_up_process(bg->kthread);
 
        spin_unlock(&bg->fcoe_rx_list.lock);
 
@@ -2260,7 +2260,7 @@ enum bnx2fc_create_link_state {
  * Returns: 0 for success
  */
 static int _bnx2fc_create(struct net_device *netdev,
-                         enum fip_state fip_mode,
+                         enum fip_mode fip_mode,
                          enum bnx2fc_create_link_state link_state)
 {
        struct fcoe_ctlr_device *cdev;
@@ -2412,7 +2412,7 @@ mod_err:
  *
  * Returns: 0 for success
  */
-static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
+static int bnx2fc_create(struct net_device *netdev, enum fip_mode fip_mode)
 {
        return _bnx2fc_create(netdev, fip_mode, BNX2FC_CREATE_LINK_UP);
 }
@@ -2715,7 +2715,7 @@ static int __init bnx2fc_mod_init(void)
        }
        wake_up_process(l2_thread);
        spin_lock_bh(&bg->fcoe_rx_list.lock);
-       bg->thread = l2_thread;
+       bg->kthread = l2_thread;
        spin_unlock_bh(&bg->fcoe_rx_list.lock);
 
        for_each_possible_cpu(cpu) {
@@ -2788,8 +2788,8 @@ static void __exit bnx2fc_mod_exit(void)
        /* Destroy global thread */
        bg = &bnx2fc_global;
        spin_lock_bh(&bg->fcoe_rx_list.lock);
-       l2_thread = bg->thread;
-       bg->thread = NULL;
+       l2_thread = bg->kthread;
+       bg->kthread = NULL;
        while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL)
                kfree_skb(skb);
 
index 026f394a38518f29f5bd9ffdd42ac24dc3b594cd..8f24d60f09d72717a6853d4a7882fceae412a117 100644 (file)
@@ -1758,7 +1758,7 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
                if ((fcp_rsp_len == 4) || (fcp_rsp_len == 8)) {
                        /* Only for task management function */
                        io_req->fcp_rsp_code = rq_data[3];
-                       printk(KERN_ERR PFX "fcp_rsp_code = %d\n",
+                       BNX2FC_IO_DBG(io_req, "fcp_rsp_code = %d\n",
                                io_req->fcp_rsp_code);
                }
 
index fb072cc5e9fdb53f92f318d265313095cd8979e1..42921dbba9272f793a2a4a483e727dfa78809e4b 100644 (file)
@@ -2417,7 +2417,7 @@ static void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba,
        ep = bnx2i_find_ep_in_destroy_list(hba, conn_destroy->iscsi_conn_id);
        if (!ep) {
                printk(KERN_ALERT "bnx2i_conn_destroy_cmpl: no pending "
-                                 "offload request, unexpected complection\n");
+                                 "offload request, unexpected completion\n");
                return;
        }
 
index 8fb9643fe6e31f90cb774407dbb617d39a0dd913..860008d4246679a4859ce9cf9b744651d01f2785 100644 (file)
@@ -764,6 +764,67 @@ static void term_afu(struct cxlflash_cfg *cfg)
        pr_debug("%s: returning\n", __func__);
 }
 
+/**
+ * notify_shutdown() - notifies device of pending shutdown
+ * @cfg:       Internal structure associated with the host.
+ * @wait:      Whether to wait for shutdown processing to complete.
+ *
+ * This function will notify the AFU that the adapter is being shutdown
+ * and will wait for shutdown processing to complete if wait is true.
+ * This notification should flush pending I/Os to the device and halt
+ * further I/Os until the next AFU reset is issued and device restarted.
+ */
+static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait)
+{
+       struct afu *afu = cfg->afu;
+       struct device *dev = &cfg->dev->dev;
+       struct sisl_global_map __iomem *global = &afu->afu_map->global;
+       struct dev_dependent_vals *ddv;
+       u64 reg, status;
+       int i, retry_cnt = 0;
+
+       ddv = (struct dev_dependent_vals *)cfg->dev_id->driver_data;
+       if (!(ddv->flags & CXLFLASH_NOTIFY_SHUTDOWN))
+               return;
+
+       /* Notify AFU */
+       for (i = 0; i < NUM_FC_PORTS; i++) {
+               reg = readq_be(&global->fc_regs[i][FC_CONFIG2 / 8]);
+               reg |= SISL_FC_SHUTDOWN_NORMAL;
+               writeq_be(reg, &global->fc_regs[i][FC_CONFIG2 / 8]);
+       }
+
+       if (!wait)
+               return;
+
+       /* Wait up to 1.5 seconds for shutdown processing to complete */
+       for (i = 0; i < NUM_FC_PORTS; i++) {
+               retry_cnt = 0;
+               while (true) {
+                       status = readq_be(&global->fc_regs[i][FC_STATUS / 8]);
+                       if (status & SISL_STATUS_SHUTDOWN_COMPLETE)
+                               break;
+                       if (++retry_cnt >= MC_RETRY_CNT) {
+                               dev_dbg(dev, "%s: port %d shutdown processing "
+                                       "not yet completed\n", __func__, i);
+                               break;
+                       }
+                       msleep(100 * retry_cnt);
+               }
+       }
+}
+
+/**
+ * cxlflash_shutdown() - shutdown handler
+ * @pdev:      PCI device associated with the host.
+ */
+static void cxlflash_shutdown(struct pci_dev *pdev)
+{
+       struct cxlflash_cfg *cfg = pci_get_drvdata(pdev);
+
+       notify_shutdown(cfg, false);
+}
+
 /**
  * cxlflash_remove() - PCI entry point to tear down host
  * @pdev:      PCI device associated with the host.
@@ -785,6 +846,9 @@ static void cxlflash_remove(struct pci_dev *pdev)
                                                  cfg->tmf_slock);
        spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags);
 
+       /* Notify AFU and wait for shutdown processing to complete */
+       notify_shutdown(cfg, true);
+
        cfg->state = STATE_FAILTERM;
        cxlflash_stop_term_user_contexts(cfg);
 
@@ -1915,6 +1979,19 @@ static int afu_reset(struct cxlflash_cfg *cfg)
        return rc;
 }
 
+/**
+ * drain_ioctls() - wait until all currently executing ioctls have completed
+ * @cfg:       Internal structure associated with the host.
+ *
+ * Obtain write access to read/write semaphore that wraps ioctl
+ * handling to 'drain' ioctls currently executing.
+ */
+static void drain_ioctls(struct cxlflash_cfg *cfg)
+{
+       down_write(&cfg->ioctl_rwsem);
+       up_write(&cfg->ioctl_rwsem);
+}
+
 /**
  * cxlflash_eh_device_reset_handler() - reset a single LUN
  * @scp:       SCSI command to send.
@@ -1986,6 +2063,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp)
        switch (cfg->state) {
        case STATE_NORMAL:
                cfg->state = STATE_RESET;
+               drain_ioctls(cfg);
                cxlflash_mark_contexts_error(cfg);
                rcr = afu_reset(cfg);
                if (rcr) {
@@ -2319,8 +2397,10 @@ static struct scsi_host_template driver_template = {
 /*
  * Device dependent values
  */
-static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
-static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS };
+static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS,
+                                       0ULL };
+static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS,
+                                       CXLFLASH_NOTIFY_SHUTDOWN };
 
 /*
  * PCI device binding table
@@ -2503,19 +2583,6 @@ out_remove:
        goto out;
 }
 
-/**
- * drain_ioctls() - wait until all currently executing ioctls have completed
- * @cfg:       Internal structure associated with the host.
- *
- * Obtain write access to read/write semaphore that wraps ioctl
- * handling to 'drain' ioctls currently executing.
- */
-static void drain_ioctls(struct cxlflash_cfg *cfg)
-{
-       down_write(&cfg->ioctl_rwsem);
-       up_write(&cfg->ioctl_rwsem);
-}
-
 /**
  * cxlflash_pci_error_detected() - called when a PCI error is detected
  * @pdev:      PCI device struct.
@@ -2610,6 +2677,7 @@ static struct pci_driver cxlflash_driver = {
        .id_table = cxlflash_pci_table,
        .probe = cxlflash_probe,
        .remove = cxlflash_remove,
+       .shutdown = cxlflash_shutdown,
        .err_handler = &cxlflash_err_handler,
 };
 
index eb9d8f730b38ec34e86c777d560f3762b48bf3d5..f54bbd5a606264c4bd4c5b1fe899008638c85c84 100644 (file)
@@ -88,6 +88,8 @@ enum undo_level {
 
 struct dev_dependent_vals {
        u64 max_sectors;
+       u64 flags;
+#define CXLFLASH_NOTIFY_SHUTDOWN   0x0000000000000001ULL
 };
 
 struct asyc_intr_info {
index 0b3366f5e6f6c49601edf6ddc9d037bd75316965..347fc16719754e7a7db5db9a5f0f559ddb61f0bb 100644 (file)
@@ -311,6 +311,12 @@ struct sisl_global_regs {
 #define SISL_FC_INTERNAL_MASK  ~(SISL_FC_INTERNAL_UNMASK)
 #define SISL_FC_INTERNAL_SHIFT 32
 
+#define SISL_FC_SHUTDOWN_NORMAL                0x0000000000000010ULL
+#define SISL_FC_SHUTDOWN_ABRUPT                0x0000000000000020ULL
+
+#define SISL_STATUS_SHUTDOWN_ACTIVE    0x0000000000000010ULL
+#define SISL_STATUS_SHUTDOWN_COMPLETE  0x0000000000000020ULL
+
 #define SISL_ASTATUS_UNMASK    0xFFFFULL               /* 1 means unmasked */
 #define SISL_ASTATUS_MASK      ~(SISL_ASTATUS_UNMASK)  /* 1 means masked */
 
index 0efe7112fc1f2157bd157e5b75b4c9ef06500d85..c8a4305c76622a1ed5055ab0cb3d71370760d86c 100644 (file)
@@ -67,9 +67,6 @@ static DEFINE_MUTEX(fcoe_config_mutex);
 
 static struct workqueue_struct *fcoe_wq;
 
-/* fcoe_percpu_clean completion.  Waiter protected by fcoe_create_mutex */
-static DECLARE_COMPLETION(fcoe_flush_completion);
-
 /* fcoe host list */
 /* must only by accessed under the RTNL mutex */
 static LIST_HEAD(fcoe_hostlist);
@@ -80,7 +77,6 @@ static int fcoe_reset(struct Scsi_Host *);
 static int fcoe_xmit(struct fc_lport *, struct fc_frame *);
 static int fcoe_rcv(struct sk_buff *, struct net_device *,
                    struct packet_type *, struct net_device *);
-static int fcoe_percpu_receive_thread(void *);
 static void fcoe_percpu_clean(struct fc_lport *);
 static int fcoe_link_ok(struct fc_lport *);
 
@@ -107,12 +103,11 @@ static int fcoe_ddp_setup(struct fc_lport *, u16, struct scatterlist *,
 static int fcoe_ddp_done(struct fc_lport *, u16);
 static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *,
                           unsigned int);
-static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *);
 static int fcoe_dcb_app_notification(struct notifier_block *notifier,
                                     ulong event, void *ptr);
 
 static bool fcoe_match(struct net_device *netdev);
-static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode);
+static int fcoe_create(struct net_device *netdev, enum fip_mode fip_mode);
 static int fcoe_destroy(struct net_device *netdev);
 static int fcoe_enable(struct net_device *netdev);
 static int fcoe_disable(struct net_device *netdev);
@@ -120,7 +115,7 @@ static int fcoe_disable(struct net_device *netdev);
 /* fcoe_syfs control interface handlers */
 static int fcoe_ctlr_alloc(struct net_device *netdev);
 static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev);
-
+static void fcoe_ctlr_mode(struct fcoe_ctlr_device *ctlr_dev);
 
 static struct fc_seq *fcoe_elsct_send(struct fc_lport *,
                                      u32 did, struct fc_frame *,
@@ -136,11 +131,6 @@ static struct notifier_block fcoe_notifier = {
        .notifier_call = fcoe_device_notification,
 };
 
-/* notification function for CPU hotplug events */
-static struct notifier_block fcoe_cpu_notifier = {
-       .notifier_call = fcoe_cpu_callback,
-};
-
 /* notification function for DCB events */
 static struct notifier_block dcb_notifier = {
        .notifier_call = fcoe_dcb_app_notification,
@@ -156,8 +146,9 @@ static void fcoe_set_vport_symbolic_name(struct fc_vport *);
 static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *);
 static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *);
 
+
 static struct fcoe_sysfs_function_template fcoe_sysfs_templ = {
-       .set_fcoe_ctlr_mode = fcoe_ctlr_set_fip_mode,
+       .set_fcoe_ctlr_mode = fcoe_ctlr_mode,
        .set_fcoe_ctlr_enabled = fcoe_ctlr_enabled,
        .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb,
        .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb,
@@ -682,6 +673,12 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
        fcoe = port->priv;
        ctlr = fcoe_to_ctlr(fcoe);
 
+       /* Figure out the VLAN ID, if any */
+       if (netdev->priv_flags & IFF_802_1Q_VLAN)
+               lport->vlan = vlan_dev_vlan_id(netdev);
+       else
+               lport->vlan = 0;
+
        /*
         * Determine max frame size based on underlying device and optional
         * user-configured limit.  If the MFS is too low, fcoe_link_ok()
@@ -780,9 +777,6 @@ static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev)
        fcoe = port->priv;
        realdev = fcoe->realdev;
 
-       if (!realdev)
-               return;
-
        /* No FDMI state m/c for NPIV ports */
        if (lport->vport)
                return;
@@ -1245,152 +1239,21 @@ static int __exit fcoe_if_exit(void)
        return 0;
 }
 
-/**
- * fcoe_percpu_thread_create() - Create a receive thread for an online CPU
- * @cpu: The CPU index of the CPU to create a receive thread for
- */
-static void fcoe_percpu_thread_create(unsigned int cpu)
+static void fcoe_thread_cleanup_local(unsigned int cpu)
 {
-       struct fcoe_percpu_s *p;
-       struct task_struct *thread;
-
-       p = &per_cpu(fcoe_percpu, cpu);
-
-       thread = kthread_create_on_node(fcoe_percpu_receive_thread,
-                                       (void *)p, cpu_to_node(cpu),
-                                       "fcoethread/%d", cpu);
-
-       if (likely(!IS_ERR(thread))) {
-               kthread_bind(thread, cpu);
-               wake_up_process(thread);
-
-               spin_lock_bh(&p->fcoe_rx_list.lock);
-               p->thread = thread;
-               spin_unlock_bh(&p->fcoe_rx_list.lock);
-       }
-}
-
-/**
- * fcoe_percpu_thread_destroy() - Remove the receive thread of a CPU
- * @cpu: The CPU index of the CPU whose receive thread is to be destroyed
- *
- * Destroys a per-CPU Rx thread. Any pending skbs are moved to the
- * current CPU's Rx thread. If the thread being destroyed is bound to
- * the CPU processing this context the skbs will be freed.
- */
-static void fcoe_percpu_thread_destroy(unsigned int cpu)
-{
-       struct fcoe_percpu_s *p;
-       struct task_struct *thread;
        struct page *crc_eof;
-       struct sk_buff *skb;
-#ifdef CONFIG_SMP
-       struct fcoe_percpu_s *p0;
-       unsigned targ_cpu = get_cpu();
-#endif /* CONFIG_SMP */
-
-       FCOE_DBG("Destroying receive thread for CPU %d\n", cpu);
+       struct fcoe_percpu_s *p;
 
-       /* Prevent any new skbs from being queued for this CPU. */
-       p = &per_cpu(fcoe_percpu, cpu);
+       p = per_cpu_ptr(&fcoe_percpu, cpu);
        spin_lock_bh(&p->fcoe_rx_list.lock);
-       thread = p->thread;
-       p->thread = NULL;
        crc_eof = p->crc_eof_page;
        p->crc_eof_page = NULL;
        p->crc_eof_offset = 0;
        spin_unlock_bh(&p->fcoe_rx_list.lock);
 
-#ifdef CONFIG_SMP
-       /*
-        * Don't bother moving the skb's if this context is running
-        * on the same CPU that is having its thread destroyed. This
-        * can easily happen when the module is removed.
-        */
-       if (cpu != targ_cpu) {
-               p0 = &per_cpu(fcoe_percpu, targ_cpu);
-               spin_lock_bh(&p0->fcoe_rx_list.lock);
-               if (p0->thread) {
-                       FCOE_DBG("Moving frames from CPU %d to CPU %d\n",
-                                cpu, targ_cpu);
-
-                       while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
-                               __skb_queue_tail(&p0->fcoe_rx_list, skb);
-                       spin_unlock_bh(&p0->fcoe_rx_list.lock);
-               } else {
-                       /*
-                        * The targeted CPU is not initialized and cannot accept
-                        * new  skbs. Unlock the targeted CPU and drop the skbs
-                        * on the CPU that is going offline.
-                        */
-                       while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
-                               kfree_skb(skb);
-                       spin_unlock_bh(&p0->fcoe_rx_list.lock);
-               }
-       } else {
-               /*
-                * This scenario occurs when the module is being removed
-                * and all threads are being destroyed. skbs will continue
-                * to be shifted from the CPU thread that is being removed
-                * to the CPU thread associated with the CPU that is processing
-                * the module removal. Once there is only one CPU Rx thread it
-                * will reach this case and we will drop all skbs and later
-                * stop the thread.
-                */
-               spin_lock_bh(&p->fcoe_rx_list.lock);
-               while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
-                       kfree_skb(skb);
-               spin_unlock_bh(&p->fcoe_rx_list.lock);
-       }
-       put_cpu();
-#else
-       /*
-        * This a non-SMP scenario where the singular Rx thread is
-        * being removed. Free all skbs and stop the thread.
-        */
-       spin_lock_bh(&p->fcoe_rx_list.lock);
-       while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
-               kfree_skb(skb);
-       spin_unlock_bh(&p->fcoe_rx_list.lock);
-#endif
-
-       if (thread)
-               kthread_stop(thread);
-
        if (crc_eof)
                put_page(crc_eof);
-}
-
-/**
- * fcoe_cpu_callback() - Handler for CPU hotplug events
- * @nfb:    The callback data block
- * @action: The event triggering the callback
- * @hcpu:   The index of the CPU that the event is for
- *
- * This creates or destroys per-CPU data for fcoe
- *
- * Returns NOTIFY_OK always.
- */
-static int fcoe_cpu_callback(struct notifier_block *nfb,
-                            unsigned long action, void *hcpu)
-{
-       unsigned cpu = (unsigned long)hcpu;
-
-       switch (action) {
-       case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
-               FCOE_DBG("CPU %x online: Create Rx thread\n", cpu);
-               fcoe_percpu_thread_create(cpu);
-               break;
-       case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
-               FCOE_DBG("CPU %x offline: Remove Rx thread\n", cpu);
-               fcoe_percpu_thread_destroy(cpu);
-               break;
-       default:
-               break;
-       }
-       return NOTIFY_OK;
+       flush_work(&p->work);
 }
 
 /**
@@ -1509,26 +1372,6 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
 
        fps = &per_cpu(fcoe_percpu, cpu);
        spin_lock(&fps->fcoe_rx_list.lock);
-       if (unlikely(!fps->thread)) {
-               /*
-                * The targeted CPU is not ready, let's target
-                * the first CPU now. For non-SMP systems this
-                * will check the same CPU twice.
-                */
-               FCOE_NETDEV_DBG(netdev, "CPU is online, but no receive thread "
-                               "ready for incoming skb- using first online "
-                               "CPU.\n");
-
-               spin_unlock(&fps->fcoe_rx_list.lock);
-               cpu = cpumask_first(cpu_online_mask);
-               fps = &per_cpu(fcoe_percpu, cpu);
-               spin_lock(&fps->fcoe_rx_list.lock);
-               if (!fps->thread) {
-                       spin_unlock(&fps->fcoe_rx_list.lock);
-                       goto err;
-               }
-       }
-
        /*
         * We now have a valid CPU that we're targeting for
         * this skb. We also have this receive thread locked,
@@ -1543,8 +1386,7 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
         * in softirq context.
         */
        __skb_queue_tail(&fps->fcoe_rx_list, skb);
-       if (fps->thread->state == TASK_INTERRUPTIBLE)
-               wake_up_process(fps->thread);
+       schedule_work_on(cpu, &fps->work);
        spin_unlock(&fps->fcoe_rx_list.lock);
 
        return NET_RX_SUCCESS;
@@ -1712,15 +1554,6 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
        return 0;
 }
 
-/**
- * fcoe_percpu_flush_done() - Indicate per-CPU queue flush completion
- * @skb: The completed skb (argument required by destructor)
- */
-static void fcoe_percpu_flush_done(struct sk_buff *skb)
-{
-       complete(&fcoe_flush_completion);
-}
-
 /**
  * fcoe_filter_frames() - filter out bad fcoe frames, i.e. bad CRC
  * @lport: The local port the frame was received on
@@ -1792,8 +1625,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
        fr = fcoe_dev_from_skb(skb);
        lport = fr->fr_dev;
        if (unlikely(!lport)) {
-               if (skb->destructor != fcoe_percpu_flush_done)
-                       FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb\n");
+               FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb\n");
                kfree_skb(skb);
                return;
        }
@@ -1857,40 +1689,28 @@ drop:
 }
 
 /**
- * fcoe_percpu_receive_thread() - The per-CPU packet receive thread
- * @arg: The per-CPU context
+ * fcoe_receive_work() - The per-CPU worker
+ * @work: The work struct
  *
- * Return: 0 for success
  */
-static int fcoe_percpu_receive_thread(void *arg)
+static void fcoe_receive_work(struct work_struct *work)
 {
-       struct fcoe_percpu_s *p = arg;
+       struct fcoe_percpu_s *p;
        struct sk_buff *skb;
        struct sk_buff_head tmp;
 
+       p = container_of(work, struct fcoe_percpu_s, work);
        skb_queue_head_init(&tmp);
 
-       set_user_nice(current, MIN_NICE);
-
-       while (!kthread_should_stop()) {
-
-               spin_lock_bh(&p->fcoe_rx_list.lock);
-               skb_queue_splice_init(&p->fcoe_rx_list, &tmp);
-
-               if (!skb_queue_len(&tmp)) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       spin_unlock_bh(&p->fcoe_rx_list.lock);
-                       schedule();
-                       continue;
-               }
-
-               spin_unlock_bh(&p->fcoe_rx_list.lock);
+       spin_lock_bh(&p->fcoe_rx_list.lock);
+       skb_queue_splice_init(&p->fcoe_rx_list, &tmp);
+       spin_unlock_bh(&p->fcoe_rx_list.lock);
 
-               while ((skb = __skb_dequeue(&tmp)) != NULL)
-                       fcoe_recv_frame(skb);
+       if (!skb_queue_len(&tmp))
+               return;
 
-       }
-       return 0;
+       while ((skb = __skb_dequeue(&tmp)))
+               fcoe_recv_frame(skb);
 }
 
 /**
@@ -2162,6 +1982,32 @@ static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev)
        };
 }
 
+/**
+ * fcoe_ctlr_mode() - Switch FIP mode
+ * @cdev: The FCoE Controller that is being modified
+ *
+ * When the FIP mode has been changed we need to update
+ * the multicast addresses to ensure we get the correct
+ * frames.
+ */
+static void fcoe_ctlr_mode(struct fcoe_ctlr_device *ctlr_dev)
+{
+       struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);
+       struct fcoe_interface *fcoe = fcoe_ctlr_priv(ctlr);
+
+       if (ctlr_dev->mode == FIP_CONN_TYPE_VN2VN &&
+           ctlr->mode != FIP_MODE_VN2VN) {
+               dev_mc_del(fcoe->netdev, FIP_ALL_ENODE_MACS);
+               dev_mc_add(fcoe->netdev, FIP_ALL_VN2VN_MACS);
+               dev_mc_add(fcoe->netdev, FIP_ALL_P2P_MACS);
+       } else if (ctlr->mode != FIP_MODE_FABRIC) {
+               dev_mc_del(fcoe->netdev, FIP_ALL_VN2VN_MACS);
+               dev_mc_del(fcoe->netdev, FIP_ALL_P2P_MACS);
+               dev_mc_add(fcoe->netdev, FIP_ALL_ENODE_MACS);
+       }
+       fcoe_ctlr_set_fip_mode(ctlr_dev);
+}
+
 /**
  * fcoe_destroy() - Destroy a FCoE interface
  * @netdev  : The net_device object the Ethernet interface to create on
@@ -2317,7 +2163,7 @@ enum fcoe_create_link_state {
  * consolidation of code can be done when that interface is
  * removed.
  */
-static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode,
+static int _fcoe_create(struct net_device *netdev, enum fip_mode fip_mode,
                        enum fcoe_create_link_state link_state)
 {
        int rc = 0;
@@ -2406,7 +2252,7 @@ out:
  *
  * Returns: 0 for success
  */
-static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
+static int fcoe_create(struct net_device *netdev, enum fip_mode fip_mode)
 {
        return _fcoe_create(netdev, fip_mode, FCOE_CREATE_LINK_UP);
 }
@@ -2450,36 +2296,19 @@ static int fcoe_link_ok(struct fc_lport *lport)
  *
  * Must be called with fcoe_create_mutex held to single-thread completion.
  *
- * This flushes the pending skbs by adding a new skb to each queue and
- * waiting until they are all freed.  This assures us that not only are
- * there no packets that will be handled by the lport, but also that any
- * threads already handling packet have returned.
+ * This flushes the pending skbs by flush the work item for each CPU. The work
+ * item on each possible CPU is flushed because we may have used the per-CPU
+ * struct of an offline CPU.
  */
 static void fcoe_percpu_clean(struct fc_lport *lport)
 {
        struct fcoe_percpu_s *pp;
-       struct sk_buff *skb;
        unsigned int cpu;
 
        for_each_possible_cpu(cpu) {
                pp = &per_cpu(fcoe_percpu, cpu);
 
-               if (!pp->thread || !cpu_online(cpu))
-                       continue;
-
-               skb = dev_alloc_skb(0);
-               if (!skb)
-                       continue;
-
-               skb->destructor = fcoe_percpu_flush_done;
-
-               spin_lock_bh(&pp->fcoe_rx_list.lock);
-               __skb_queue_tail(&pp->fcoe_rx_list, skb);
-               if (pp->fcoe_rx_list.qlen == 1)
-                       wake_up_process(pp->thread);
-               spin_unlock_bh(&pp->fcoe_rx_list.lock);
-
-               wait_for_completion(&fcoe_flush_completion);
+               flush_work(&pp->work);
        }
 }
 
@@ -2625,22 +2454,11 @@ static int __init fcoe_init(void)
        mutex_lock(&fcoe_config_mutex);
 
        for_each_possible_cpu(cpu) {
-               p = &per_cpu(fcoe_percpu, cpu);
+               p = per_cpu_ptr(&fcoe_percpu, cpu);
+               INIT_WORK(&p->work, fcoe_receive_work);
                skb_queue_head_init(&p->fcoe_rx_list);
        }
 
-       cpu_notifier_register_begin();
-
-       for_each_online_cpu(cpu)
-               fcoe_percpu_thread_create(cpu);
-
-       /* Initialize per CPU interrupt thread */
-       rc = __register_hotcpu_notifier(&fcoe_cpu_notifier);
-       if (rc)
-               goto out_free;
-
-       cpu_notifier_register_done();
-
        /* Setup link change notification */
        fcoe_dev_setup();
 
@@ -2652,12 +2470,6 @@ static int __init fcoe_init(void)
        return 0;
 
 out_free:
-       for_each_online_cpu(cpu) {
-               fcoe_percpu_thread_destroy(cpu);
-       }
-
-       cpu_notifier_register_done();
-
        mutex_unlock(&fcoe_config_mutex);
        destroy_workqueue(fcoe_wq);
        return rc;
@@ -2690,14 +2502,8 @@ static void __exit fcoe_exit(void)
        }
        rtnl_unlock();
 
-       cpu_notifier_register_begin();
-
-       for_each_online_cpu(cpu)
-               fcoe_percpu_thread_destroy(cpu);
-
-       __unregister_hotcpu_notifier(&fcoe_cpu_notifier);
-
-       cpu_notifier_register_done();
+       for_each_possible_cpu(cpu)
+               fcoe_thread_cleanup_local(cpu);
 
        mutex_unlock(&fcoe_config_mutex);
 
index 3e83d485f7437d859454304f6c4eb8986eed6c67..a569c65f22b18fbc247c1ab8c0e5c361328ccacb 100644 (file)
@@ -59,6 +59,8 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *);
 static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *);
 static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *, u32, u8 *);
 
+static int fcoe_ctlr_vlan_recv(struct fcoe_ctlr *, struct sk_buff *);
+
 static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
 static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;
 static u8 fcoe_all_vn2vn[ETH_ALEN] = FIP_ALL_VN2VN_MACS;
@@ -149,6 +151,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
 {
        fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
        fip->mode = mode;
+       fip->fip_resp = false;
        INIT_LIST_HEAD(&fip->fcfs);
        mutex_init(&fip->ctlr_mutex);
        spin_lock_init(&fip->ctlr_lock);
@@ -991,7 +994,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
                        LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
                                        "in FIP adv\n", desc->fip_dtype);
                        /* standard says ignore unknown descriptors >= 128 */
-                       if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
+                       if (desc->fip_dtype < FIP_DT_NON_CRITICAL)
                                return -EINVAL;
                        break;
                }
@@ -1232,7 +1235,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
                        LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
                                        "in FIP adv\n", desc->fip_dtype);
                        /* standard says ignore unknown descriptors >= 128 */
-                       if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
+                       if (desc->fip_dtype < FIP_DT_NON_CRITICAL)
                                goto drop;
                        if (desc_cnt <= 2) {
                                LIBFCOE_FIP_DBG(fip, "FIP descriptors "
@@ -1410,7 +1413,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
                        break;
                default:
                        /* standard says ignore unknown descriptors >= 128 */
-                       if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
+                       if (desc->fip_dtype < FIP_DT_NON_CRITICAL)
                                goto err;
                        break;
                }
@@ -1513,6 +1516,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
        struct fip_header *fiph;
        struct ethhdr *eh;
        enum fip_state state;
+       bool fip_vlan_resp = false;
        u16 op;
        u8 sub;
 
@@ -1546,11 +1550,17 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
                state = FIP_ST_ENABLED;
                LIBFCOE_FIP_DBG(fip, "Using FIP mode\n");
        }
+       fip_vlan_resp = fip->fip_resp;
        mutex_unlock(&fip->ctlr_mutex);
 
        if (fip->mode == FIP_MODE_VN2VN && op == FIP_OP_VN2VN)
                return fcoe_ctlr_vn_recv(fip, skb);
 
+       if (fip_vlan_resp && op == FIP_OP_VLAN) {
+               LIBFCOE_FIP_DBG(fip, "fip vlan discovery\n");
+               return fcoe_ctlr_vlan_recv(fip, skb);
+       }
+
        if (state != FIP_ST_ENABLED && state != FIP_ST_VNMP_UP &&
            state != FIP_ST_VNMP_CLAIM)
                goto drop;
@@ -1989,7 +1999,7 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip,
                              const u8 *dest, size_t min_len)
 {
        struct sk_buff *skb;
-       struct fip_frame {
+       struct fip_vn2vn_probe_frame {
                struct ethhdr eth;
                struct fip_header fip;
                struct fip_mac_desc mac;
@@ -2016,7 +2026,7 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip,
        if (!skb)
                return;
 
-       frame = (struct fip_frame *)skb->data;
+       frame = (struct fip_vn2vn_probe_frame *)skb->data;
        memset(frame, 0, len);
        memcpy(frame->eth.h_dest, dest, ETH_ALEN);
 
@@ -2338,7 +2348,7 @@ static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
                        LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
                                        "in FIP probe\n", dtype);
                        /* standard says ignore unknown descriptors >= 128 */
-                       if (dtype < FIP_DT_VENDOR_BASE)
+                       if (dtype < FIP_DT_NON_CRITICAL)
                                return -EINVAL;
                        break;
                }
@@ -2496,14 +2506,13 @@ static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac)
        struct fcoe_rport *frport;
        int ret = -1;
 
-       rcu_read_lock();
        rdata = lport->tt.rport_lookup(lport, port_id);
        if (rdata) {
                frport = fcoe_ctlr_rport(rdata);
                memcpy(mac, frport->enode_mac, ETH_ALEN);
                ret = 0;
+               kref_put(&rdata->kref, lport->tt.rport_destroy);
        }
-       rcu_read_unlock();
        return ret;
 }
 
@@ -2585,11 +2594,7 @@ static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip,
                fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0);
                return;
        }
-       mutex_lock(&lport->disc.disc_mutex);
        rdata = lport->tt.rport_lookup(lport, new->ids.port_id);
-       if (rdata)
-               kref_get(&rdata->kref);
-       mutex_unlock(&lport->disc.disc_mutex);
        if (rdata) {
                if (rdata->ids.node_name == new->ids.node_name &&
                    rdata->ids.port_name == new->ids.port_name) {
@@ -2708,6 +2713,220 @@ drop:
        return rc;
 }
 
+/**
+ * fcoe_ctlr_vlan_parse - parse vlan discovery request or response
+ * @fip: The FCoE controller
+ * @skb: incoming packet
+ * @rdata: buffer for resulting parsed VLAN entry plus fcoe_rport
+ *
+ * Returns non-zero error number on error.
+ * Does not consume the packet.
+ */
+static int fcoe_ctlr_vlan_parse(struct fcoe_ctlr *fip,
+                             struct sk_buff *skb,
+                             struct fc_rport_priv *rdata)
+{
+       struct fip_header *fiph;
+       struct fip_desc *desc = NULL;
+       struct fip_mac_desc *macd = NULL;
+       struct fip_wwn_desc *wwn = NULL;
+       struct fcoe_rport *frport;
+       size_t rlen;
+       size_t dlen;
+       u32 desc_mask = 0;
+       u32 dtype;
+       u8 sub;
+
+       memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
+       frport = fcoe_ctlr_rport(rdata);
+
+       fiph = (struct fip_header *)skb->data;
+       frport->flags = ntohs(fiph->fip_flags);
+
+       sub = fiph->fip_subcode;
+       switch (sub) {
+       case FIP_SC_VL_REQ:
+               desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME);
+               break;
+       default:
+               LIBFCOE_FIP_DBG(fip, "vn_parse unknown subcode %u\n", sub);
+               return -EINVAL;
+       }
+
+       rlen = ntohs(fiph->fip_dl_len) * 4;
+       if (rlen + sizeof(*fiph) > skb->len)
+               return -EINVAL;
+
+       desc = (struct fip_desc *)(fiph + 1);
+       while (rlen > 0) {
+               dlen = desc->fip_dlen * FIP_BPW;
+               if (dlen < sizeof(*desc) || dlen > rlen)
+                       return -EINVAL;
+
+               dtype = desc->fip_dtype;
+               if (dtype < 32) {
+                       if (!(desc_mask & BIT(dtype))) {
+                               LIBFCOE_FIP_DBG(fip,
+                                               "unexpected or duplicated desc "
+                                               "desc type %u in "
+                                               "FIP VN2VN subtype %u\n",
+                                               dtype, sub);
+                               return -EINVAL;
+                       }
+                       desc_mask &= ~BIT(dtype);
+               }
+
+               switch (dtype) {
+               case FIP_DT_MAC:
+                       if (dlen != sizeof(struct fip_mac_desc))
+                               goto len_err;
+                       macd = (struct fip_mac_desc *)desc;
+                       if (!is_valid_ether_addr(macd->fd_mac)) {
+                               LIBFCOE_FIP_DBG(fip,
+                                       "Invalid MAC addr %pM in FIP VN2VN\n",
+                                        macd->fd_mac);
+                               return -EINVAL;
+                       }
+                       memcpy(frport->enode_mac, macd->fd_mac, ETH_ALEN);
+                       break;
+               case FIP_DT_NAME:
+                       if (dlen != sizeof(struct fip_wwn_desc))
+                               goto len_err;
+                       wwn = (struct fip_wwn_desc *)desc;
+                       rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
+                       break;
+               default:
+                       LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
+                                       "in FIP probe\n", dtype);
+                       /* standard says ignore unknown descriptors >= 128 */
+                       if (dtype < FIP_DT_NON_CRITICAL)
+                               return -EINVAL;
+                       break;
+               }
+               desc = (struct fip_desc *)((char *)desc + dlen);
+               rlen -= dlen;
+       }
+       return 0;
+
+len_err:
+       LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n",
+                       dtype, dlen);
+       return -EINVAL;
+}
+
+/**
+ * fcoe_ctlr_vlan_send() - Send a FIP VLAN Notification
+ * @fip: The FCoE controller
+ * @sub: sub-opcode for vlan notification or vn2vn vlan notification
+ * @dest: The destination Ethernet MAC address
+ * @min_len: minimum size of the Ethernet payload to be sent
+ */
+static void fcoe_ctlr_vlan_send(struct fcoe_ctlr *fip,
+                             enum fip_vlan_subcode sub,
+                             const u8 *dest)
+{
+       struct sk_buff *skb;
+       struct fip_vlan_notify_frame {
+               struct ethhdr eth;
+               struct fip_header fip;
+               struct fip_mac_desc mac;
+               struct fip_vlan_desc vlan;
+       } __packed * frame;
+       size_t len;
+       size_t dlen;
+
+       len = sizeof(*frame);
+       dlen = sizeof(frame->mac) + sizeof(frame->vlan);
+       len = max(len, sizeof(struct ethhdr));
+
+       skb = dev_alloc_skb(len);
+       if (!skb)
+               return;
+
+       LIBFCOE_FIP_DBG(fip, "fip %s vlan notification, vlan %d\n",
+                       fip->mode == FIP_MODE_VN2VN ? "vn2vn" : "fcf",
+                       fip->lp->vlan);
+
+       frame = (struct fip_vlan_notify_frame *)skb->data;
+       memset(frame, 0, len);
+       memcpy(frame->eth.h_dest, dest, ETH_ALEN);
+
+       memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN);
+       frame->eth.h_proto = htons(ETH_P_FIP);
+
+       frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
+       frame->fip.fip_op = htons(FIP_OP_VLAN);
+       frame->fip.fip_subcode = sub;
+       frame->fip.fip_dl_len = htons(dlen / FIP_BPW);
+
+       frame->mac.fd_desc.fip_dtype = FIP_DT_MAC;
+       frame->mac.fd_desc.fip_dlen = sizeof(frame->mac) / FIP_BPW;
+       memcpy(frame->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN);
+
+       frame->vlan.fd_desc.fip_dtype = FIP_DT_VLAN;
+       frame->vlan.fd_desc.fip_dlen = sizeof(frame->vlan) / FIP_BPW;
+       put_unaligned_be16(fip->lp->vlan, &frame->vlan.fd_vlan);
+
+       skb_put(skb, len);
+       skb->protocol = htons(ETH_P_FIP);
+       skb->priority = fip->priority;
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+
+       fip->send(fip, skb);
+}
+
+/**
+ * fcoe_ctlr_vlan_disk_reply() - send FIP VLAN Discovery Notification.
+ * @fip: The FCoE controller
+ *
+ * Called with ctlr_mutex held.
+ */
+static void fcoe_ctlr_vlan_disc_reply(struct fcoe_ctlr *fip,
+                                     struct fc_rport_priv *rdata)
+{
+       struct fcoe_rport *frport = fcoe_ctlr_rport(rdata);
+       enum fip_vlan_subcode sub = FIP_SC_VL_NOTE;
+
+       if (fip->mode == FIP_MODE_VN2VN)
+               sub = FIP_SC_VL_VN2VN_NOTE;
+
+       fcoe_ctlr_vlan_send(fip, sub, frport->enode_mac);
+}
+
+/**
+ * fcoe_ctlr_vlan_recv - vlan request receive handler for VN2VN mode.
+ * @lport: The local port
+ * @fp: The received frame
+ *
+ */
+static int fcoe_ctlr_vlan_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
+{
+       struct fip_header *fiph;
+       enum fip_vlan_subcode sub;
+       struct {
+               struct fc_rport_priv rdata;
+               struct fcoe_rport frport;
+       } buf;
+       int rc;
+
+       fiph = (struct fip_header *)skb->data;
+       sub = fiph->fip_subcode;
+       rc = fcoe_ctlr_vlan_parse(fip, skb, &buf.rdata);
+       if (rc) {
+               LIBFCOE_FIP_DBG(fip, "vlan_recv vlan_parse error %d\n", rc);
+               goto drop;
+       }
+       mutex_lock(&fip->ctlr_mutex);
+       if (sub == FIP_SC_VL_REQ)
+               fcoe_ctlr_vlan_disc_reply(fip, &buf.rdata);
+       mutex_unlock(&fip->ctlr_mutex);
+
+drop:
+       kfree(skb);
+       return rc;
+}
+
 /**
  * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode.
  * @lport: The local port
@@ -2869,7 +3088,7 @@ unlock:
  * when nothing is happening.
  */
 static void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip,
-                              enum fip_state fip_mode)
+                              enum fip_mode fip_mode)
 {
        void *priv;
 
index 045c4e11ee5468471dbd26ddd6e83f4f3637e9f5..0675fd128734e15b23513565d83f1c05be328102 100644 (file)
@@ -385,6 +385,44 @@ static FCOE_DEVICE_ATTR(ctlr, enabled, S_IRUGO | S_IWUSR,
                        show_ctlr_enabled_state,
                        store_ctlr_enabled);
 
+static ssize_t store_ctlr_fip_resp(struct device *dev,
+                             struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
+       struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr);
+
+       mutex_lock(&fip->ctlr_mutex);
+       if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) {
+               if (buf[0] == '1') {
+                       fip->fip_resp = 1;
+                       mutex_unlock(&fip->ctlr_mutex);
+                       return count;
+               }
+               if (buf[0] == '0') {
+                       fip->fip_resp = 0;
+                       mutex_unlock(&fip->ctlr_mutex);
+                       return count;
+               }
+       }
+       mutex_unlock(&fip->ctlr_mutex);
+       return -EINVAL;
+}
+
+static ssize_t show_ctlr_fip_resp(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
+       struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr);
+
+       return sprintf(buf, "%d\n", fip->fip_resp ? 1 : 0);
+}
+
+static FCOE_DEVICE_ATTR(ctlr, fip_vlan_responder, S_IRUGO | S_IWUSR,
+                       show_ctlr_fip_resp,
+                       store_ctlr_fip_resp);
+
 static ssize_t
 store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev,
                                         struct device_attribute *attr,
@@ -467,6 +505,7 @@ static struct attribute_group fcoe_ctlr_lesb_attr_group = {
 };
 
 static struct attribute *fcoe_ctlr_attrs[] = {
+       &device_attr_fcoe_ctlr_fip_vlan_responder.attr,
        &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr,
        &device_attr_fcoe_ctlr_enabled.attr,
        &device_attr_fcoe_ctlr_mode.attr,
index 641c60e8fda33b03a3f5f32b41cced7ac9eb8943..7028dd37e5dd4bc6ffe27d4f57d7f58336d4412c 100644 (file)
@@ -133,10 +133,10 @@ int fcoe_link_speed_update(struct fc_lport *lport)
                case SPEED_10000:
                        lport->link_speed = FC_PORTSPEED_10GBIT;
                        break;
-               case 20000:
+               case SPEED_20000:
                        lport->link_speed = FC_PORTSPEED_20GBIT;
                        break;
-               case 40000:
+               case SPEED_40000:
                        lport->link_speed = FC_PORTSPEED_40GBIT;
                        break;
                default:
index 67669a9e73c1c94c7c9deeff3b5c3bc0723cada2..3b7da66e277188c5e5a14d5c4f18b6942f2f2dc8 100644 (file)
@@ -359,7 +359,7 @@ static void fnic_fcoe_send_vlan_req(struct fnic *fnic)
 
        vlan->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
        vlan->fip.fip_op = htons(FIP_OP_VLAN);
-       vlan->fip.fip_subcode = FIP_SC_VL_REQ;
+       vlan->fip.fip_subcode = FIP_SC_VL_NOTE;
        vlan->fip.fip_dl_len = htons(sizeof(vlan->desc) / FIP_BPW);
 
        vlan->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC;
@@ -551,7 +551,7 @@ static int fnic_fcoe_handle_fip_frame(struct fnic *fnic, struct sk_buff *skb)
                        goto drop;
                /* pass it on to fcoe */
                ret = 1;
-       } else if (op == FIP_OP_VLAN && sub == FIP_SC_VL_REP) {
+       } else if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) {
                /* set the vlan as used */
                fnic_fcoe_process_vlan_resp(fnic, skb);
                ret = 0;
@@ -954,8 +954,8 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq)
        skb_put(skb, len);
        pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE);
 
-       r = pci_dma_mapping_error(fnic->pdev, pa);
-       if (r) {
+       if (pci_dma_mapping_error(fnic->pdev, pa)) {
+               r = -ENOMEM;
                printk(KERN_ERR "PCI mapping failed with error %d\n", r);
                goto free_skb;
        }
@@ -1093,8 +1093,8 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp)
 
        pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE);
 
-       ret = pci_dma_mapping_error(fnic->pdev, pa);
-       if (ret) {
+       if (pci_dma_mapping_error(fnic->pdev, pa)) {
+               ret = -ENOMEM;
                printk(KERN_ERR "DMA map failed with error %d\n", ret);
                goto free_skb_on_err;
        }
@@ -1308,7 +1308,7 @@ void fnic_handle_fip_timer(struct fnic *fnic)
        }
        spin_unlock_irqrestore(&fnic->fnic_lock, flags);
 
-       if (fnic->ctlr.mode == FIP_ST_NON_FIP)
+       if (fnic->ctlr.mode == FIP_MODE_NON_FIP)
                return;
 
        spin_lock_irqsave(&fnic->vlans_lock, flags);
index 87e74c2ab971c53daf9e3b35069ae087c7b6402b..7761f33ab5d4c059d4cca1611e048dd18b4e9d73 100644 (file)
 
 #define FINC_MAX_FLOGI_REJECTS   8
 
-/*
- * FIP_DT_VLAN descriptor.
- */
-struct fip_vlan_desc {
-       struct fip_desc fd_desc;
-       __be16 fd_vlan;
-} __attribute__((packed));
-
 struct vlan {
        __be16 vid;
        __be16 type;
index d7cab724f203fadcc2f35cf8d4bd5c0ab68f54ab..4731d324132361f011221055b8516a58e94b9dab 100644 (file)
@@ -23,7 +23,7 @@
 #include <scsi/sas_ata.h>
 #include <scsi/libsas.h>
 
-#define DRV_VERSION "v1.4"
+#define DRV_VERSION "v1.5"
 
 #define HISI_SAS_MAX_PHYS      9
 #define HISI_SAS_MAX_QUEUES    32
index bd20c548876800c405c2862e7953eeb574aec48b..f96560431cf1081af9ea473e67dbe19c30d8af23 100644 (file)
@@ -721,30 +721,41 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
                        return -EIO;
        }
 
-       /* reset and disable clock*/
-       regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
-                       reset_val);
-       regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
-                       reset_val);
-       msleep(1);
-       regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
-       if (reset_val != (val & reset_val)) {
-               dev_err(dev, "SAS reset fail.\n");
-               return -EIO;
-       }
+       if (ACPI_HANDLE(dev)) {
+               acpi_status s;
 
-       /* De-reset and enable clock*/
-       regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
-                       reset_val);
-       regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
-                       reset_val);
-       msleep(1);
-       regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg,
-                       &val);
-       if (val & reset_val) {
-               dev_err(dev, "SAS de-reset fail.\n");
-               return -EIO;
-       }
+               s = acpi_evaluate_object(ACPI_HANDLE(dev), "_RST", NULL, NULL);
+               if (ACPI_FAILURE(s)) {
+                       dev_err(dev, "Reset failed\n");
+                       return -EIO;
+               }
+       } else if (hisi_hba->ctrl) {
+               /* reset and disable clock*/
+               regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
+                               reset_val);
+               regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
+                               reset_val);
+               msleep(1);
+               regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+               if (reset_val != (val & reset_val)) {
+                       dev_err(dev, "SAS reset fail.\n");
+                       return -EIO;
+               }
+
+               /* De-reset and enable clock*/
+               regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
+                               reset_val);
+               regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
+                               reset_val);
+               msleep(1);
+               regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg,
+                               &val);
+               if (val & reset_val) {
+                       dev_err(dev, "SAS de-reset fail.\n");
+                       return -EIO;
+               }
+       } else
+               dev_warn(dev, "no reset method\n");
 
        return 0;
 }
@@ -752,13 +763,12 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
 static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 {
        struct device *dev = &hisi_hba->pdev->dev;
-       struct device_node *np = dev->of_node;
        int i;
 
        /* Global registers init */
 
        /* Deal with am-max-transmissions quirk */
-       if (of_get_property(np, "hip06-sas-v2-quirk-amt", NULL)) {
+       if (device_property_present(dev, "hip06-sas-v2-quirk-amt")) {
                hisi_sas_write32(hisi_hba, AM_CFG_MAX_TRANS, 0x2020);
                hisi_sas_write32(hisi_hba, AM_CFG_SINGLE_PORT_MAX_TRANS,
                                 0x2020);
@@ -1902,14 +1912,9 @@ static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
        struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
        struct sas_ha_struct *sas_ha = &hisi_hba->sha;
-       unsigned long flags;
 
        hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1);
-
-       spin_lock_irqsave(&hisi_hba->lock, flags);
        sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
-       spin_unlock_irqrestore(&hisi_hba->lock, flags);
-
        hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
                             CHL_INT0_SL_RX_BCST_ACK_MSK);
        hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
@@ -2260,12 +2265,20 @@ static const struct of_device_id sas_v2_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sas_v2_of_match);
 
+static const struct acpi_device_id sas_v2_acpi_match[] = {
+       { "HISI0162", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(acpi, sas_v2_acpi_match);
+
 static struct platform_driver hisi_sas_v2_driver = {
        .probe = hisi_sas_v2_probe,
        .remove = hisi_sas_v2_remove,
        .driver = {
                .name = DRV_NAME,
                .of_match_table = sas_v2_of_match,
+               .acpi_match_table = ACPI_PTR(sas_v2_acpi_match),
        },
 };
 
index 1547bd93c70bb7450dc368ff53c54688677245cb..ba9af4a2bd2ab3159ed415b5acc73328925aa3c3 100644 (file)
@@ -486,8 +486,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        else
                shost->dma_boundary = 0xffffffff;
 
-       shost->use_blk_mq = scsi_use_blk_mq && !shost->hostt->disable_blk_mq;
-
        device_initialize(&shost->shost_gendev);
        dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
        shost->shost_gendev.bus = &scsi_bus_type;
index ff8dcd5b0631fb3be397274247c8566db524c1d8..030d0023e1d22491d5db8314a17e762e5f9a002c 100644 (file)
@@ -4105,6 +4105,70 @@ static int hpsa_set_local_logical_count(struct ctlr_info *h,
        return rc;
 }
 
+static bool hpsa_is_disk_spare(struct ctlr_info *h, u8 *lunaddrbytes)
+{
+       struct bmic_identify_physical_device *id_phys;
+       bool is_spare = false;
+       int rc;
+
+       id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+       if (!id_phys)
+               return false;
+
+       rc = hpsa_bmic_id_physical_device(h,
+                                       lunaddrbytes,
+                                       GET_BMIC_DRIVE_NUMBER(lunaddrbytes),
+                                       id_phys, sizeof(*id_phys));
+       if (rc == 0)
+               is_spare = (id_phys->more_flags >> 6) & 0x01;
+
+       kfree(id_phys);
+       return is_spare;
+}
+
+#define RPL_DEV_FLAG_NON_DISK                           0x1
+#define RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED  0x2
+#define RPL_DEV_FLAG_UNCONFIG_DISK                      0x4
+
+#define BMIC_DEVICE_TYPE_ENCLOSURE  6
+
+static bool hpsa_skip_device(struct ctlr_info *h, u8 *lunaddrbytes,
+                               struct ext_report_lun_entry *rle)
+{
+       u8 device_flags;
+       u8 device_type;
+
+       if (!MASKED_DEVICE(lunaddrbytes))
+               return false;
+
+       device_flags = rle->device_flags;
+       device_type = rle->device_type;
+
+       if (device_flags & RPL_DEV_FLAG_NON_DISK) {
+               if (device_type == BMIC_DEVICE_TYPE_ENCLOSURE)
+                       return false;
+               return true;
+       }
+
+       if (!(device_flags & RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED))
+               return false;
+
+       if (device_flags & RPL_DEV_FLAG_UNCONFIG_DISK)
+               return false;
+
+       /*
+        * Spares may be spun down, we do not want to
+        * do an Inquiry to a RAID set spare drive as
+        * that would have them spun up, that is a
+        * performance hit because I/O to the RAID device
+        * stops while the spin up occurs which can take
+        * over 50 seconds.
+        */
+       if (hpsa_is_disk_spare(h, lunaddrbytes))
+               return true;
+
+       return false;
+}
 
 static void hpsa_update_scsi_devices(struct ctlr_info *h)
 {
@@ -4198,6 +4262,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
                u8 *lunaddrbytes, is_OBDR = 0;
                int rc = 0;
                int phys_dev_index = i - (raid_ctlr_position == 0);
+               bool skip_device = false;
 
                physical_device = i < nphysicals + (raid_ctlr_position == 0);
 
@@ -4205,11 +4270,15 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
                lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
                        i, nphysicals, nlogicals, physdev_list, logdev_list);
 
-               /* skip masked non-disk devices */
-               if (MASKED_DEVICE(lunaddrbytes) && physical_device &&
-                  (physdev_list->LUN[phys_dev_index].device_type != 0x06) &&
-                  (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
-                       continue;
+               /*
+                * Skip over some devices such as a spare.
+                */
+               if (!tmpdevice->external && physical_device) {
+                       skip_device = hpsa_skip_device(h, lunaddrbytes,
+                                       &physdev_list->LUN[phys_dev_index]);
+                       if (skip_device)
+                               continue;
+               }
 
                /* Get device type, vendor, model, device id */
                rc = hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
@@ -6455,7 +6524,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
                c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */
        }
        rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
-                                       DEFAULT_TIMEOUT);
+                                       NO_TIMEOUT);
        if (iocommand.buf_size > 0)
                hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL);
        check_ioctl_unit_attention(h, c);
@@ -6588,7 +6657,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
                c->SG[--i].Ext = cpu_to_le32(HPSA_SG_LAST);
        }
        status = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
-                                               DEFAULT_TIMEOUT);
+                                               NO_TIMEOUT);
        if (sg_used)
                hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL);
        check_ioctl_unit_attention(h, c);
index fc523c3e50191a428d0125d948d9e2447ce6e53f..ab67ec4b6bd632587e18bccc30ae72dceb8fdfd8 100644 (file)
@@ -4722,6 +4722,8 @@ static void ibmvfc_rport_add_thread(struct work_struct *work)
                                        tgt_dbg(tgt, "Setting rport roles\n");
                                        fc_remote_port_rolechg(rport, tgt->ids.roles);
                                        put_device(&rport->dev);
+                               } else {
+                                       spin_unlock_irqrestore(vhost->host->host_lock, flags);
                                }
 
                                kref_put(&tgt->kref, ibmvfc_release_tgt);
index d6803a9e5ab8a49ea045bcbfafce7029ef439c5d..1f539c288ae820f6aafb7463688c2c0bc5be4860 100644 (file)
@@ -98,7 +98,7 @@ static unsigned int ipr_transop_timeout = 0;
 static unsigned int ipr_debug = 0;
 static unsigned int ipr_max_devs = IPR_DEFAULT_SIS64_DEVS;
 static unsigned int ipr_dual_ioa_raid = 1;
-static unsigned int ipr_number_of_msix = 2;
+static unsigned int ipr_number_of_msix = 16;
 static unsigned int ipr_fast_reboot;
 static DEFINE_SPINLOCK(ipr_driver_lock);
 
@@ -194,7 +194,8 @@ static const struct ipr_chip_t ipr_chip[] = {
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_RATTLESNAKE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
 };
 
 static int ipr_max_bus_speeds[] = {
@@ -221,7 +222,7 @@ module_param_named(max_devs, ipr_max_devs, int, 0);
 MODULE_PARM_DESC(max_devs, "Specify the maximum number of physical devices. "
                 "[Default=" __stringify(IPR_DEFAULT_SIS64_DEVS) "]");
 module_param_named(number_of_msix, ipr_number_of_msix, int, 0);
-MODULE_PARM_DESC(number_of_msix, "Specify the number of MSIX interrupts to use on capable adapters (1 - 16).  (default:2)");
+MODULE_PARM_DESC(number_of_msix, "Specify the number of MSIX interrupts to use on capable adapters (1 - 16).  (default:16)");
 module_param_named(fast_reboot, ipr_fast_reboot, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(fast_reboot, "Skip adapter shutdown during reboot. Set to 1 to enable. (default: 0)");
 MODULE_LICENSE("GPL");
@@ -10565,6 +10566,10 @@ static struct pci_device_id ipr_pci_table[] = {
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CD2, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2CCD, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_RATTLESNAKE,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_580A, 0, 0, 0 },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_RATTLESNAKE,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_580B, 0, 0, 0 },
        { }
 };
 MODULE_DEVICE_TABLE(pci, ipr_pci_table);
index 56c57068300a1fb947221f8bc32f467aa115ae80..1d42c7464dfc96eae7bd686241a5cc761c5a3c0f 100644 (file)
@@ -60,6 +60,7 @@
 
 #define PCI_DEVICE_ID_IBM_CROC_FPGA_E2          0x033D
 #define PCI_DEVICE_ID_IBM_CROCODILE             0x034A
+#define PCI_DEVICE_ID_IBM_RATTLESNAKE          0x04DA
 
 #define IPR_SUBS_DEV_ID_2780   0x0264
 #define IPR_SUBS_DEV_ID_5702   0x0266
 #define IPR_SUBS_DEV_ID_2CCA   0x04C7
 #define IPR_SUBS_DEV_ID_2CD2   0x04C8
 #define IPR_SUBS_DEV_ID_2CCD   0x04C9
+#define IPR_SUBS_DEV_ID_580A   0x04FC
+#define IPR_SUBS_DEV_ID_580B   0x04FB
 #define IPR_NAME                               "ipr"
 
 /*
index 30f9ef0c0d4f8cea52b182f370a04ed1ba4a9908..e72673b0a8fb4ba810097a4c57b8cc3d3b8d199f 100644 (file)
@@ -908,9 +908,17 @@ static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid)
 {
        struct fc_exch_pool *pool;
        struct fc_exch *ep = NULL;
+       u16 cpu = xid & fc_cpu_mask;
+
+       if (cpu >= nr_cpu_ids || !cpu_possible(cpu)) {
+               printk_ratelimited(KERN_ERR
+                       "libfc: lookup request for XID = %d, "
+                       "indicates invalid CPU %d\n", xid, cpu);
+               return NULL;
+       }
 
        if ((xid >= mp->min_xid) && (xid <= mp->max_xid)) {
-               pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask);
+               pool = per_cpu_ptr(mp->pool, cpu);
                spin_lock_bh(&pool->lock);
                ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order);
                if (ep) {
index e01a29863c384ca3c0ad1189d5b757b72f8fb660..04ce7cfb6d1b6272d26ce138a9b11ee952a20d6f 100644 (file)
@@ -301,7 +301,6 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
 {
        struct fc_host_statistics *fc_stats;
        struct fc_lport *lport = shost_priv(shost);
-       struct timespec v0, v1;
        unsigned int cpu;
        u64 fcp_in_bytes = 0;
        u64 fcp_out_bytes = 0;
@@ -309,9 +308,7 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
        fc_stats = &lport->host_stats;
        memset(fc_stats, 0, sizeof(struct fc_host_statistics));
 
-       jiffies_to_timespec(jiffies, &v0);
-       jiffies_to_timespec(lport->boot_time, &v1);
-       fc_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec);
+       fc_stats->seconds_since_last_reset = (lport->boot_time - jiffies) / HZ;
 
        for_each_possible_cpu(cpu) {
                struct fc_stats *stats;
@@ -2090,7 +2087,7 @@ int fc_lport_bsg_request(struct fc_bsg_job *job)
        struct fc_rport *rport;
        struct fc_rport_priv *rdata;
        int rc = -EINVAL;
-       u32 did;
+       u32 did, tov;
 
        job->reply->reply_payload_rcv_len = 0;
        if (rsp)
@@ -2121,15 +2118,20 @@ int fc_lport_bsg_request(struct fc_bsg_job *job)
 
        case FC_BSG_HST_CT:
                did = ntoh24(job->request->rqst_data.h_ct.port_id);
-               if (did == FC_FID_DIR_SERV)
+               if (did == FC_FID_DIR_SERV) {
                        rdata = lport->dns_rdata;
-               else
+                       if (!rdata)
+                               break;
+                       tov = rdata->e_d_tov;
+               } else {
                        rdata = lport->tt.rport_lookup(lport, did);
+                       if (!rdata)
+                               break;
+                       tov = rdata->e_d_tov;
+                       kref_put(&rdata->kref, lport->tt.rport_destroy);
+               }
 
-               if (!rdata)
-                       break;
-
-               rc = fc_lport_ct_request(job, lport, did, rdata->e_d_tov);
+               rc = fc_lport_ct_request(job, lport, did, tov);
                break;
 
        case FC_BSG_HST_ELS_NOLOGIN:
index 589ff9aedd318088d5f0f61f143f780a223ed00d..93f5961821452b50d0094413658c34bc37cbc9ec 100644 (file)
@@ -95,17 +95,23 @@ static const char *fc_rport_state_names[] = {
  * @lport:   The local port to lookup the remote port on
  * @port_id: The remote port ID to look up
  *
- * The caller must hold either disc_mutex or rcu_read_lock().
+ * The reference count of the fc_rport_priv structure is
+ * increased by one.
  */
 static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
                                             u32 port_id)
 {
-       struct fc_rport_priv *rdata;
+       struct fc_rport_priv *rdata = NULL, *tmp_rdata;
 
-       list_for_each_entry_rcu(rdata, &lport->disc.rports, peers)
-               if (rdata->ids.port_id == port_id)
-                       return rdata;
-       return NULL;
+       rcu_read_lock();
+       list_for_each_entry_rcu(tmp_rdata, &lport->disc.rports, peers)
+               if (tmp_rdata->ids.port_id == port_id &&
+                   kref_get_unless_zero(&tmp_rdata->kref)) {
+                       rdata = tmp_rdata;
+                       break;
+               }
+       rcu_read_unlock();
+       return rdata;
 }
 
 /**
@@ -340,7 +346,6 @@ static void fc_rport_work(struct work_struct *work)
                        fc_remote_port_delete(rport);
                }
 
-               mutex_lock(&lport->disc.disc_mutex);
                mutex_lock(&rdata->rp_mutex);
                if (rdata->rp_state == RPORT_ST_DELETE) {
                        if (port_id == FC_FID_DIR_SERV) {
@@ -370,7 +375,6 @@ static void fc_rport_work(struct work_struct *work)
                                fc_rport_enter_ready(rdata);
                        mutex_unlock(&rdata->rp_mutex);
                }
-               mutex_unlock(&lport->disc.disc_mutex);
                break;
 
        default:
@@ -702,7 +706,7 @@ out:
 err:
        mutex_unlock(&rdata->rp_mutex);
 put:
-       kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
+       kref_put(&rdata->kref, lport->tt.rport_destroy);
        return;
 bad:
        FC_RPORT_DBG(rdata, "Bad FLOGI response\n");
@@ -762,8 +766,6 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport,
        FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n");
 
        disc = &lport->disc;
-       mutex_lock(&disc->disc_mutex);
-
        if (!lport->point_to_multipoint) {
                rjt_data.reason = ELS_RJT_UNSUP;
                rjt_data.explan = ELS_EXPL_NONE;
@@ -808,7 +810,7 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport,
                mutex_unlock(&rdata->rp_mutex);
                rjt_data.reason = ELS_RJT_FIP;
                rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR;
-               goto reject;
+               goto reject_put;
        case RPORT_ST_FLOGI:
        case RPORT_ST_PLOGI_WAIT:
        case RPORT_ST_PLOGI:
@@ -825,13 +827,13 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport,
                mutex_unlock(&rdata->rp_mutex);
                rjt_data.reason = ELS_RJT_BUSY;
                rjt_data.explan = ELS_EXPL_NONE;
-               goto reject;
+               goto reject_put;
        }
        if (fc_rport_login_complete(rdata, fp)) {
                mutex_unlock(&rdata->rp_mutex);
                rjt_data.reason = ELS_RJT_LOGIC;
                rjt_data.explan = ELS_EXPL_NONE;
-               goto reject;
+               goto reject_put;
        }
 
        fp = fc_frame_alloc(lport, sizeof(*flp));
@@ -851,12 +853,13 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport,
                fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
 out:
        mutex_unlock(&rdata->rp_mutex);
-       mutex_unlock(&disc->disc_mutex);
+       kref_put(&rdata->kref, lport->tt.rport_destroy);
        fc_frame_free(rx_fp);
        return;
 
+reject_put:
+       kref_put(&rdata->kref, lport->tt.rport_destroy);
 reject:
-       mutex_unlock(&disc->disc_mutex);
        lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
        fc_frame_free(rx_fp);
 }
@@ -923,7 +926,7 @@ out:
        fc_frame_free(fp);
 err:
        mutex_unlock(&rdata->rp_mutex);
-       kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
+       kref_put(&rdata->kref, lport->tt.rport_destroy);
 }
 
 static bool
@@ -1477,14 +1480,11 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp)
        struct fc_rport_priv *rdata;
        struct fc_seq_els_data els_data;
 
-       mutex_lock(&lport->disc.disc_mutex);
        rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp));
-       if (!rdata) {
-               mutex_unlock(&lport->disc.disc_mutex);
+       if (!rdata)
                goto reject;
-       }
+
        mutex_lock(&rdata->rp_mutex);
-       mutex_unlock(&lport->disc.disc_mutex);
 
        switch (rdata->rp_state) {
        case RPORT_ST_PRLI:
@@ -1494,6 +1494,7 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp)
                break;
        default:
                mutex_unlock(&rdata->rp_mutex);
+               kref_put(&rdata->kref, lport->tt.rport_destroy);
                goto reject;
        }
 
@@ -1524,6 +1525,7 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp)
        }
 
        mutex_unlock(&rdata->rp_mutex);
+       kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
        return;
 
 reject:
@@ -1907,7 +1909,6 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
 
        sid = fc_frame_sid(fp);
 
-       mutex_lock(&lport->disc.disc_mutex);
        rdata = lport->tt.rport_lookup(lport, sid);
        if (rdata) {
                mutex_lock(&rdata->rp_mutex);
@@ -1916,10 +1917,10 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
 
                fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
                mutex_unlock(&rdata->rp_mutex);
+               kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
        } else
                FC_RPORT_ID_DBG(lport, sid,
                                "Received LOGO from non-logged-in port\n");
-       mutex_unlock(&lport->disc.disc_mutex);
        fc_frame_free(fp);
 }
 
index 497bc1558377309aa9729909bbd1553312c7dec5..763f012fdeca00e21f086be86efa1ec12d65c5f0 100644 (file)
@@ -246,6 +246,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
                if (qc->scsicmd)
                        ASSIGN_SAS_TASK(qc->scsicmd, NULL);
                sas_free_task(task);
+               qc->lldd_task = NULL;
                ret = AC_ERR_SYSTEM;
        }
 
index d5bd420595c1ce72c41ecb511f8f6e582c411194..b484859464f6b2695fe41d24a5cfecf8e8824c49 100644 (file)
@@ -647,6 +647,7 @@ struct lpfc_hba {
 #define HBA_RRQ_ACTIVE         0x4000 /* process the rrq active list */
 #define HBA_FCP_IOQ_FLUSH      0x8000 /* FCP I/O queues being flushed */
 #define HBA_FW_DUMP_OP         0x10000 /* Skips fn reset before FW dump */
+#define HBA_RECOVERABLE_UE     0x20000 /* Firmware supports recoverable UE */
        uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
        struct lpfc_dmabuf slim2p;
 
@@ -694,7 +695,8 @@ struct lpfc_hba {
        uint8_t  wwnn[8];
        uint8_t  wwpn[8];
        uint32_t RandomData[7];
-       uint32_t fcp_embed_io;
+       uint8_t  fcp_embed_io;
+       uint8_t  mds_diags_support;
 
        /* HBA Config Parameters */
        uint32_t cfg_ack0;
@@ -741,6 +743,7 @@ struct lpfc_hba {
 #define OAS_FIND_ANY_VPORT     0x01
 #define OAS_FIND_ANY_TARGET    0x02
 #define OAS_LUN_VALID  0x04
+       uint32_t cfg_oas_priority;
        uint32_t cfg_XLanePriority;
        uint32_t cfg_enable_bg;
        uint32_t cfg_hostmem_hgp;
@@ -751,6 +754,8 @@ struct lpfc_hba {
        uint32_t cfg_iocb_cnt;
        uint32_t cfg_suppress_link_up;
        uint32_t cfg_rrq_xri_bitmap_sz;
+       uint32_t cfg_delay_discovery;
+       uint32_t cfg_sli_mode;
 #define LPFC_INITIALIZE_LINK              0    /* do normal init_link mbox */
 #define LPFC_DELAY_INIT_LINK              1    /* layered driver hold off */
 #define LPFC_DELAY_INIT_LINK_INDEFINITELY 2    /* wait, manual intervention */
@@ -759,6 +764,7 @@ struct lpfc_hba {
 #define LPFC_FDMI_NO_SUPPORT   0       /* FDMI not supported */
 #define LPFC_FDMI_SUPPORT      1       /* FDMI supported? */
        uint32_t cfg_enable_SmartSAN;
+       uint32_t cfg_enable_mds_diags;
        lpfc_vpd_t vpd;         /* vital product data */
 
        struct pci_dev *pcidev;
@@ -779,9 +785,9 @@ struct lpfc_hba {
 
        atomic_t fcp_qidx;              /* next work queue to post work to */
 
-       unsigned long pci_bar0_map;     /* Physical address for PCI BAR0 */
-       unsigned long pci_bar1_map;     /* Physical address for PCI BAR1 */
-       unsigned long pci_bar2_map;     /* Physical address for PCI BAR2 */
+       phys_addr_t pci_bar0_map;     /* Physical address for PCI BAR0 */
+       phys_addr_t pci_bar1_map;     /* Physical address for PCI BAR1 */
+       phys_addr_t pci_bar2_map;     /* Physical address for PCI BAR2 */
        void __iomem *slim_memmap_p;    /* Kernel memory mapped address for
                                           PCI BAR0 */
        void __iomem *ctrl_regs_memmap_p;/* Kernel memory mapped address for
@@ -827,6 +833,7 @@ struct lpfc_hba {
 
        struct timer_list fcp_poll_timer;
        struct timer_list eratt_poll;
+       uint32_t eratt_poll_interval;
 
        /*
         * stat  counters
@@ -999,6 +1006,18 @@ struct lpfc_hba {
        spinlock_t devicelock;  /* lock for luns list */
        mempool_t *device_data_mem_pool;
        struct list_head luns;
+#define LPFC_TRANSGRESSION_HIGH_TEMPERATURE    0x0080
+#define LPFC_TRANSGRESSION_LOW_TEMPERATURE     0x0040
+#define LPFC_TRANSGRESSION_HIGH_VOLTAGE                0x0020
+#define LPFC_TRANSGRESSION_LOW_VOLTAGE         0x0010
+#define LPFC_TRANSGRESSION_HIGH_TXBIAS         0x0008
+#define LPFC_TRANSGRESSION_LOW_TXBIAS          0x0004
+#define LPFC_TRANSGRESSION_HIGH_TXPOWER                0x0002
+#define LPFC_TRANSGRESSION_LOW_TXPOWER         0x0001
+#define LPFC_TRANSGRESSION_HIGH_RXPOWER                0x8000
+#define LPFC_TRANSGRESSION_LOW_RXPOWER         0x4000
+       uint16_t sfp_alarm;
+       uint16_t sfp_warning;
 };
 
 static inline struct Scsi_Host *
index cfec2eca4dd3f13d4f779fc95bb32f1b4dd0b7db..f1019908800edd9ae15d10476d6173330c864d30 100644 (file)
@@ -48,6 +48,7 @@
 #include "lpfc_compat.h"
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
+#include "lpfc_attr.h"
 
 #define LPFC_DEF_DEVLOSS_TMO 30
 #define LPFC_MIN_DEVLOSS_TMO 1
@@ -1620,6 +1621,11 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
 }
 
+static inline bool lpfc_rangecheck(uint val, uint min, uint max)
+{
+       return val >= min && val <= max;
+}
+
 /**
  * lpfc_param_show - Return a cfg attribute value in decimal
  *
@@ -1697,7 +1703,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
 static int \
 lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \
 { \
-       if (val >= minval && val <= maxval) {\
+       if (lpfc_rangecheck(val, minval, maxval)) {\
                phba->cfg_##attr = val;\
                return 0;\
        }\
@@ -1732,7 +1738,7 @@ lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \
 static int \
 lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \
 { \
-       if (val >= minval && val <= maxval) {\
+       if (lpfc_rangecheck(val, minval, maxval)) {\
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \
                        "3052 lpfc_" #attr " changed from %d to %d\n", \
                        phba->cfg_##attr, val); \
@@ -1856,7 +1862,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
 static int \
 lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \
 { \
-       if (val >= minval && val <= maxval) {\
+       if (lpfc_rangecheck(val, minval, maxval)) {\
                vport->cfg_##attr = val;\
                return 0;\
        }\
@@ -1888,7 +1894,7 @@ lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \
 static int \
 lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \
 { \
-       if (val >= minval && val <= maxval) {\
+       if (lpfc_rangecheck(val, minval, maxval)) {\
                lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \
                        "3053 lpfc_" #attr \
                        " changed from %d (x%x) to %d (x%x)\n", \
@@ -1939,102 +1945,6 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \
 }
 
 
-#define LPFC_ATTR(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_param_init(name, defval, minval, maxval)
-
-#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_param_show(name)\
-lpfc_param_init(name, defval, minval, maxval)\
-static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
-
-#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_param_show(name)\
-lpfc_param_init(name, defval, minval, maxval)\
-lpfc_param_set(name, defval, minval, maxval)\
-lpfc_param_store(name)\
-static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
-                  lpfc_##name##_show, lpfc_##name##_store)
-
-#define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_param_hex_show(name)\
-lpfc_param_init(name, defval, minval, maxval)\
-static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
-
-#define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_param_hex_show(name)\
-lpfc_param_init(name, defval, minval, maxval)\
-lpfc_param_set(name, defval, minval, maxval)\
-lpfc_param_store(name)\
-static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
-                  lpfc_##name##_show, lpfc_##name##_store)
-
-#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_vport_param_init(name, defval, minval, maxval)
-
-#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_vport_param_show(name)\
-lpfc_vport_param_init(name, defval, minval, maxval)\
-static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
-
-#define LPFC_VPORT_ULL_ATTR_R(name, defval, minval, maxval, desc) \
-static uint64_t lpfc_##name = defval;\
-module_param(lpfc_##name, ullong, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_vport_param_show(name)\
-lpfc_vport_param_init(name, defval, minval, maxval)\
-static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
-
-#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_vport_param_show(name)\
-lpfc_vport_param_init(name, defval, minval, maxval)\
-lpfc_vport_param_set(name, defval, minval, maxval)\
-lpfc_vport_param_store(name)\
-static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
-                  lpfc_##name##_show, lpfc_##name##_store)
-
-#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_vport_param_hex_show(name)\
-lpfc_vport_param_init(name, defval, minval, maxval)\
-static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
-
-#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
-static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, S_IRUGO);\
-MODULE_PARM_DESC(lpfc_##name, desc);\
-lpfc_vport_param_hex_show(name)\
-lpfc_vport_param_init(name, defval, minval, maxval)\
-lpfc_vport_param_set(name, defval, minval, maxval)\
-lpfc_vport_param_store(name)\
-static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
-                  lpfc_##name##_show, lpfc_##name##_store)
-
 static DEVICE_ATTR(bg_info, S_IRUGO, lpfc_bg_info_show, NULL);
 static DEVICE_ATTR(bg_guard_err, S_IRUGO, lpfc_bg_guard_err_show, NULL);
 static DEVICE_ATTR(bg_apptag_err, S_IRUGO, lpfc_bg_apptag_err_show, NULL);
@@ -2400,6 +2310,69 @@ lpfc_oas_tgt_store(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR(lpfc_xlane_tgt, S_IRUGO | S_IWUSR,
                   lpfc_oas_tgt_show, lpfc_oas_tgt_store);
 
+/**
+ * lpfc_oas_priority_show - Return wwpn of target whose luns maybe enabled for
+ *                   Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ *
+ * Returns:
+ * value of count
+ **/
+static ssize_t
+lpfc_oas_priority_show(struct device *dev, struct device_attribute *attr,
+                      char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_priority);
+}
+
+/**
+ * lpfc_oas_priority_store - Store wwpn of target whose luns maybe enabled for
+ *                   Optimized Access Storage (OAS) operations.
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: buffer for passing information.
+ * @count: Size of the data buffer.
+ *
+ * Returns:
+ * -EINVAL count is invalid, invalid wwpn byte invalid
+ * -EPERM oas is not supported by hba
+ * value of count on success
+ **/
+static ssize_t
+lpfc_oas_priority_store(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+       unsigned int cnt = count;
+       unsigned long val;
+       int ret;
+
+       if (!phba->cfg_fof)
+               return -EPERM;
+
+       /* count may include a LF at end of string */
+       if (buf[cnt-1] == '\n')
+               cnt--;
+
+       ret = kstrtoul(buf, 0, &val);
+       if (ret || (val > 0x7f))
+               return -EINVAL;
+
+       if (val)
+               phba->cfg_oas_priority = (uint8_t)val;
+       else
+               phba->cfg_oas_priority = phba->cfg_XLanePriority;
+       return count;
+}
+static DEVICE_ATTR(lpfc_xlane_priority, S_IRUGO | S_IWUSR,
+                  lpfc_oas_priority_show, lpfc_oas_priority_store);
+
 /**
  * lpfc_oas_vpt_show - Return wwpn of vport whose targets maybe enabled
  *                   for Optimized Access Storage (OAS) operations.
@@ -2462,6 +2435,7 @@ lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr,
        else
                phba->cfg_oas_flags &= ~OAS_FIND_ANY_VPORT;
        phba->cfg_oas_flags &= ~OAS_LUN_VALID;
+       phba->cfg_oas_priority = phba->cfg_XLanePriority;
        phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN;
        return count;
 }
@@ -2524,7 +2498,6 @@ lpfc_oas_lun_state_store(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        phba->cfg_oas_lun_state = val;
-
        return strlen(buf);
 }
 static DEVICE_ATTR(lpfc_xlane_lun_state, S_IRUGO | S_IWUSR,
@@ -2572,7 +2545,8 @@ static DEVICE_ATTR(lpfc_xlane_lun_status, S_IRUGO,
  */
 static size_t
 lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
-                      uint8_t tgt_wwpn[], uint64_t lun, uint32_t oas_state)
+                      uint8_t tgt_wwpn[], uint64_t lun,
+                      uint32_t oas_state, uint8_t pri)
 {
 
        int rc = 0;
@@ -2582,7 +2556,8 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
 
        if (oas_state) {
                if (!lpfc_enable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn,
-                                        (struct lpfc_name *)tgt_wwpn, lun))
+                                        (struct lpfc_name *)tgt_wwpn,
+                                        lun, pri))
                        rc = -ENOMEM;
        } else {
                lpfc_disable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn,
@@ -2648,13 +2623,13 @@ lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
 static ssize_t
 lpfc_oas_lun_state_change(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
                          uint8_t tgt_wwpn[], uint64_t lun,
-                         uint32_t oas_state)
+                         uint32_t oas_state, uint8_t pri)
 {
 
        int rc;
 
        rc = lpfc_oas_lun_state_set(phba, vpt_wwpn, tgt_wwpn, lun,
-                                       oas_state);
+                                   oas_state, pri);
        return rc;
 }
 
@@ -2744,16 +2719,16 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-                       "3372 Try to set vport 0x%llx target 0x%llx lun:%lld "
-                       "with oas set to %d\n",
+                       "3372 Try to set vport 0x%llx target 0x%llx lun:0x%llx "
+                       "priority 0x%x with oas state %d\n",
                        wwn_to_u64(phba->cfg_oas_vpt_wwpn),
                        wwn_to_u64(phba->cfg_oas_tgt_wwpn), scsi_lun,
-                       phba->cfg_oas_lun_state);
+                       phba->cfg_oas_priority, phba->cfg_oas_lun_state);
 
        rc = lpfc_oas_lun_state_change(phba, phba->cfg_oas_vpt_wwpn,
-                                          phba->cfg_oas_tgt_wwpn, scsi_lun,
-                                          phba->cfg_oas_lun_state);
-
+                                      phba->cfg_oas_tgt_wwpn, scsi_lun,
+                                      phba->cfg_oas_lun_state,
+                                      phba->cfg_oas_priority);
        if (rc)
                return rc;
 
@@ -2772,19 +2747,14 @@ MODULE_PARM_DESC(lpfc_poll, "FCP ring polling mode control:"
 static DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR,
                   lpfc_poll_show, lpfc_poll_store);
 
-int  lpfc_sli_mode = 0;
-module_param(lpfc_sli_mode, int, S_IRUGO);
-MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
-                " 0 - auto (SLI-3 if supported),"
-                " 2 - select SLI-2 even on SLI-3 capable HBAs,"
-                " 3 - select SLI-3");
+LPFC_ATTR(sli_mode, 0, 0, 3,
+       "SLI mode selector:"
+       " 0 - auto (SLI-3 if supported),"
+       " 2 - select SLI-2 even on SLI-3 capable HBAs,"
+       " 3 - select SLI-3");
 
-int lpfc_enable_npiv = 1;
-module_param(lpfc_enable_npiv, int, S_IRUGO);
-MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
-lpfc_param_show(enable_npiv);
-lpfc_param_init(enable_npiv, 1, 0, 1);
-static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
+LPFC_ATTR_R(enable_npiv, 1, 0, 1,
+       "Enable NPIV functionality");
 
 LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2,
        "FCF Fast failover=1 Priority failover=2");
@@ -4754,11 +4724,8 @@ MODULE_PARM_DESC(lpfc_prot_guard, "host protection guard type");
  * accept and FCID/Fabric name/Fabric portname is changed.
  * Default value is 0.
  */
-int lpfc_delay_discovery;
-module_param(lpfc_delay_discovery, int, S_IRUGO);
-MODULE_PARM_DESC(lpfc_delay_discovery,
-       "Delay NPort discovery when Clean Address bit is cleared. "
-       "Allowed values: 0,1.");
+LPFC_ATTR(delay_discovery, 0, 0, 1,
+       "Delay NPort discovery when Clean Address bit is cleared.");
 
 /*
  * lpfc_sg_seg_cnt - Initial Maximum DMA Segment Count
@@ -4780,6 +4747,14 @@ LPFC_ATTR_R(prot_sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT,
            LPFC_DEFAULT_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT,
            "Max Protection Scatter Gather Segment Count");
 
+/*
+ * lpfc_enable_mds_diags: Enable MDS Diagnostics
+ *       0  = MDS Diagnostics disabled (default)
+ *       1  = MDS Diagnostics enabled
+ * Value range is [0,1]. Default value is 0.
+ */
+LPFC_ATTR_R(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics");
+
 struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_bg_info,
        &dev_attr_bg_guard_err,
@@ -4857,6 +4832,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_xlane_vpt,
        &dev_attr_lpfc_xlane_lun_state,
        &dev_attr_lpfc_xlane_lun_status,
+       &dev_attr_lpfc_xlane_priority,
        &dev_attr_lpfc_sg_seg_cnt,
        &dev_attr_lpfc_max_scsicmpl_time,
        &dev_attr_lpfc_stat_data_ctrl,
@@ -4876,6 +4852,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_sriov_hw_max_virtfn,
        &dev_attr_protocol,
        &dev_attr_lpfc_xlane_supported,
+       &dev_attr_lpfc_enable_mds_diags,
        NULL,
 };
 
@@ -5849,6 +5826,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        phba->cfg_oas_lun_state = 0;
        phba->cfg_oas_lun_status = 0;
        phba->cfg_oas_flags = 0;
+       phba->cfg_oas_priority = 0;
        lpfc_enable_bg_init(phba, lpfc_enable_bg);
        if (phba->sli_rev == LPFC_SLI_REV4)
                phba->cfg_poll = 0;
@@ -5866,7 +5844,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_request_firmware_upgrade_init(phba, lpfc_req_fw_upgrade);
        lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
        lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
+       lpfc_delay_discovery_init(phba, lpfc_delay_discovery);
+       lpfc_sli_mode_init(phba, lpfc_sli_mode);
        phba->cfg_enable_dss = 1;
+       lpfc_enable_mds_diags_init(phba, lpfc_enable_mds_diags);
        return;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_attr.h b/drivers/scsi/lpfc/lpfc_attr.h
new file mode 100644 (file)
index 0000000..b2bd28e
--- /dev/null
@@ -0,0 +1,116 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+#define LPFC_ATTR(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_param_init(name, defval, minval, maxval)
+
+#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_param_show(name)\
+lpfc_param_init(name, defval, minval, maxval)\
+static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL)
+
+#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_param_show(name)\
+lpfc_param_init(name, defval, minval, maxval)\
+lpfc_param_set(name, defval, minval, maxval)\
+lpfc_param_store(name)\
+static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
+                  lpfc_##name##_show, lpfc_##name##_store)
+
+#define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_param_hex_show(name)\
+lpfc_param_init(name, defval, minval, maxval)\
+static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL)
+
+#define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_param_hex_show(name)\
+lpfc_param_init(name, defval, minval, maxval)\
+lpfc_param_set(name, defval, minval, maxval)\
+lpfc_param_store(name)\
+static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
+                  lpfc_##name##_show, lpfc_##name##_store)
+
+#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_init(name, defval, minval, maxval)
+
+#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL)
+
+#define LPFC_VPORT_ULL_ATTR_R(name, defval, minval, maxval, desc) \
+static uint64_t lpfc_##name = defval;\
+module_param(lpfc_##name, ullong, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL)
+
+#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+lpfc_vport_param_set(name, defval, minval, maxval)\
+lpfc_vport_param_store(name)\
+static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
+                  lpfc_##name##_show, lpfc_##name##_store)
+
+#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_hex_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+static DEVICE_ATTR(lpfc_##name, S_IRUGO, lpfc_##name##_show, NULL)
+
+#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
+static uint lpfc_##name = defval;\
+module_param(lpfc_##name, uint, S_IRUGO);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_hex_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+lpfc_vport_param_set(name, defval, minval, maxval)\
+lpfc_vport_param_store(name)\
+static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
+                  lpfc_##name##_show, lpfc_##name##_store)
index 4e55b35180a4c641b65e23b008e7392051230d58..bd7576d452f2921152082a267a2938fe6f7f1ae6 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2015 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -359,9 +359,6 @@ 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;
-extern int lpfc_sli_mode;
-extern int lpfc_enable_npiv;
-extern int lpfc_delay_discovery;
 
 int  lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
 int  lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *,        size_t);
@@ -492,7 +489,7 @@ struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *,
                                        struct lpfc_name *,
                                        struct lpfc_name *, uint64_t);
 bool lpfc_enable_oas_lun(struct lpfc_hba *, struct lpfc_name *,
-                        struct lpfc_name *, uint64_t);
+                        struct lpfc_name *, uint64_t, uint8_t);
 bool lpfc_disable_oas_lun(struct lpfc_hba *, struct lpfc_name *,
                          struct lpfc_name *, uint64_t);
 bool lpfc_find_next_oas_lun(struct lpfc_hba *, struct lpfc_name *,
index a38816e96654963c3785bd93f31359ce541b3ee1..63e48d4277b025173789d16e9c415ab3a0e9d603 100644 (file)
@@ -1510,6 +1510,10 @@ lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
        if (!lpfc_is_link_up(phba))
                return;
 
+       /* Must be connected to a Fabric */
+       if (!(vport->fc_flag & FC_FABRIC))
+               return;
+
        if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
                return;
 
index 0498f5760d2b6097472ef9e26b11ac9f96b0ada0..c0af32f2495467e6bbd301718babeb01b8fc66c2 100644 (file)
@@ -594,6 +594,7 @@ static uint8_t
 lpfc_check_clean_addr_bit(struct lpfc_vport *vport,
                struct serv_parm *sp)
 {
+       struct lpfc_hba *phba = vport->phba;
        uint8_t fabric_param_changed = 0;
        struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
@@ -615,7 +616,7 @@ lpfc_check_clean_addr_bit(struct lpfc_vport *vport,
         * - lpfc_delay_discovery module parameter is set.
         */
        if (fabric_param_changed && !sp->cmn.clean_address_bit &&
-           (vport->fc_prevDID || lpfc_delay_discovery)) {
+           (vport->fc_prevDID || phba->cfg_delay_discovery)) {
                spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_DISC_DELAYED;
                spin_unlock_irq(shost->host_lock);
@@ -3299,6 +3300,12 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                                     FC_VPORT_FABRIC_REJ_WWN);
                        }
                        break;
+               case LSRJT_VENDOR_UNIQUE:
+                       if ((stat.un.b.vendorUnique == 0x45) &&
+                           (cmd == ELS_CMD_FLOGI)) {
+                               goto out_retry;
+                       }
+                       break;
                }
                break;
 
@@ -3344,6 +3351,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        if ((vport->load_flag & FC_UNLOADING) != 0)
                retry = 0;
 
+out_retry:
        if (retry) {
                if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_FDISC)) {
                        /* Stop retrying PLOGI and FDISC if in FCF discovery */
@@ -4609,7 +4617,7 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
        return sentplogi;
 }
 
-void
+uint32_t
 lpfc_rdp_res_link_service(struct fc_rdp_link_service_desc *desc,
                uint32_t word0)
 {
@@ -4617,9 +4625,11 @@ lpfc_rdp_res_link_service(struct fc_rdp_link_service_desc *desc,
        desc->tag = cpu_to_be32(RDP_LINK_SERVICE_DESC_TAG);
        desc->payload.els_req = word0;
        desc->length = cpu_to_be32(sizeof(desc->payload));
+
+       return sizeof(struct fc_rdp_link_service_desc);
 }
 
-void
+uint32_t
 lpfc_rdp_res_sfp_desc(struct fc_rdp_sfp_desc *desc,
                uint8_t *page_a0, uint8_t *page_a2)
 {
@@ -4680,9 +4690,11 @@ lpfc_rdp_res_sfp_desc(struct fc_rdp_sfp_desc *desc,
 
        desc->sfp_info.flags = cpu_to_be16(flag);
        desc->length = cpu_to_be32(sizeof(desc->sfp_info));
+
+       return sizeof(struct fc_rdp_sfp_desc);
 }
 
-void
+uint32_t
 lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc,
                READ_LNK_VAR *stat)
 {
@@ -4707,134 +4719,181 @@ lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc,
        desc->info.link_status.invalid_crc_cnt = cpu_to_be32(stat->crcCnt);
 
        desc->length = cpu_to_be32(sizeof(desc->info));
+
+       return sizeof(struct fc_rdp_link_error_status_desc);
 }
 
-void
+uint32_t
 lpfc_rdp_res_bbc_desc(struct fc_rdp_bbc_desc *desc, READ_LNK_VAR *stat,
                      struct lpfc_vport *vport)
 {
+       uint32_t bbCredit;
+
        desc->tag = cpu_to_be32(RDP_BBC_DESC_TAG);
 
-       desc->bbc_info.port_bbc = cpu_to_be32(
-                               vport->fc_sparam.cmn.bbCreditMsb |
-                               vport->fc_sparam.cmn.bbCreditlsb << 8);
-       if (vport->phba->fc_topology != LPFC_TOPOLOGY_LOOP)
-               desc->bbc_info.attached_port_bbc = cpu_to_be32(
-                               vport->phba->fc_fabparam.cmn.bbCreditMsb |
-                               vport->phba->fc_fabparam.cmn.bbCreditlsb << 8);
-       else
+       bbCredit = vport->fc_sparam.cmn.bbCreditLsb |
+                       (vport->fc_sparam.cmn.bbCreditMsb << 8);
+       desc->bbc_info.port_bbc = cpu_to_be32(bbCredit);
+       if (vport->phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
+               bbCredit = vport->phba->fc_fabparam.cmn.bbCreditLsb |
+                       (vport->phba->fc_fabparam.cmn.bbCreditMsb << 8);
+               desc->bbc_info.attached_port_bbc = cpu_to_be32(bbCredit);
+       } else {
                desc->bbc_info.attached_port_bbc = 0;
+       }
 
        desc->bbc_info.rtt = 0;
        desc->length = cpu_to_be32(sizeof(desc->bbc_info));
+
+       return sizeof(struct fc_rdp_bbc_desc);
 }
 
-void
-lpfc_rdp_res_oed_temp_desc(struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2)
+uint32_t
+lpfc_rdp_res_oed_temp_desc(struct lpfc_hba *phba,
+                          struct fc_rdp_oed_sfp_desc *desc, uint8_t *page_a2)
 {
-       uint32_t flags;
+       uint32_t flags = 0;
 
        desc->tag = cpu_to_be32(RDP_OED_DESC_TAG);
 
-       desc->oed_info.hi_alarm =
-                       cpu_to_be16(page_a2[SSF_TEMP_HIGH_ALARM]);
-       desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_TEMP_LOW_ALARM]);
-       desc->oed_info.hi_warning =
-                       cpu_to_be16(page_a2[SSF_TEMP_HIGH_WARNING]);
-       desc->oed_info.lo_warning =
-                       cpu_to_be16(page_a2[SSF_TEMP_LOW_WARNING]);
-       flags = 0xf; /* All four are valid */
+       desc->oed_info.hi_alarm = page_a2[SSF_TEMP_HIGH_ALARM];
+       desc->oed_info.lo_alarm = page_a2[SSF_TEMP_LOW_ALARM];
+       desc->oed_info.hi_warning = page_a2[SSF_TEMP_HIGH_WARNING];
+       desc->oed_info.lo_warning = page_a2[SSF_TEMP_LOW_WARNING];
+
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_TEMPERATURE)
+               flags |= RDP_OET_HIGH_ALARM;
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_TEMPERATURE)
+               flags |= RDP_OET_LOW_ALARM;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_TEMPERATURE)
+               flags |= RDP_OET_HIGH_WARNING;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_TEMPERATURE)
+               flags |= RDP_OET_LOW_WARNING;
+
        flags |= ((0xf & RDP_OED_TEMPERATURE) << RDP_OED_TYPE_SHIFT);
        desc->oed_info.function_flags = cpu_to_be32(flags);
        desc->length = cpu_to_be32(sizeof(desc->oed_info));
+       return sizeof(struct fc_rdp_oed_sfp_desc);
 }
 
-void
-lpfc_rdp_res_oed_voltage_desc(struct fc_rdp_oed_sfp_desc *desc,
+uint32_t
+lpfc_rdp_res_oed_voltage_desc(struct lpfc_hba *phba,
+                             struct fc_rdp_oed_sfp_desc *desc,
                              uint8_t *page_a2)
 {
-       uint32_t flags;
+       uint32_t flags = 0;
 
        desc->tag = cpu_to_be32(RDP_OED_DESC_TAG);
 
-       desc->oed_info.hi_alarm =
-                       cpu_to_be16(page_a2[SSF_VOLTAGE_HIGH_ALARM]);
-       desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_VOLTAGE_LOW_ALARM]);
-       desc->oed_info.hi_warning =
-                       cpu_to_be16(page_a2[SSF_VOLTAGE_HIGH_WARNING]);
-       desc->oed_info.lo_warning =
-                       cpu_to_be16(page_a2[SSF_VOLTAGE_LOW_WARNING]);
-       flags = 0xf; /* All four are valid */
+       desc->oed_info.hi_alarm = page_a2[SSF_VOLTAGE_HIGH_ALARM];
+       desc->oed_info.lo_alarm = page_a2[SSF_VOLTAGE_LOW_ALARM];
+       desc->oed_info.hi_warning = page_a2[SSF_VOLTAGE_HIGH_WARNING];
+       desc->oed_info.lo_warning = page_a2[SSF_VOLTAGE_LOW_WARNING];
+
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_VOLTAGE)
+               flags |= RDP_OET_HIGH_ALARM;
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_VOLTAGE)
+               flags |= RDP_OET_LOW_ALARM;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_VOLTAGE)
+               flags |= RDP_OET_HIGH_WARNING;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_VOLTAGE)
+               flags |= RDP_OET_LOW_WARNING;
+
        flags |= ((0xf & RDP_OED_VOLTAGE) << RDP_OED_TYPE_SHIFT);
        desc->oed_info.function_flags = cpu_to_be32(flags);
        desc->length = cpu_to_be32(sizeof(desc->oed_info));
+       return sizeof(struct fc_rdp_oed_sfp_desc);
 }
 
-void
-lpfc_rdp_res_oed_txbias_desc(struct fc_rdp_oed_sfp_desc *desc,
+uint32_t
+lpfc_rdp_res_oed_txbias_desc(struct lpfc_hba *phba,
+                            struct fc_rdp_oed_sfp_desc *desc,
                             uint8_t *page_a2)
 {
-       uint32_t flags;
+       uint32_t flags = 0;
 
        desc->tag = cpu_to_be32(RDP_OED_DESC_TAG);
 
-       desc->oed_info.hi_alarm =
-                       cpu_to_be16(page_a2[SSF_BIAS_HIGH_ALARM]);
-       desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_BIAS_LOW_ALARM]);
-       desc->oed_info.hi_warning =
-                       cpu_to_be16(page_a2[SSF_BIAS_HIGH_WARNING]);
-       desc->oed_info.lo_warning =
-                       cpu_to_be16(page_a2[SSF_BIAS_LOW_WARNING]);
-       flags = 0xf; /* All four are valid */
+       desc->oed_info.hi_alarm = page_a2[SSF_BIAS_HIGH_ALARM];
+       desc->oed_info.lo_alarm = page_a2[SSF_BIAS_LOW_ALARM];
+       desc->oed_info.hi_warning = page_a2[SSF_BIAS_HIGH_WARNING];
+       desc->oed_info.lo_warning = page_a2[SSF_BIAS_LOW_WARNING];
+
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_TXBIAS)
+               flags |= RDP_OET_HIGH_ALARM;
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_TXBIAS)
+               flags |= RDP_OET_LOW_ALARM;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_TXBIAS)
+               flags |= RDP_OET_HIGH_WARNING;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_TXBIAS)
+               flags |= RDP_OET_LOW_WARNING;
+
        flags |= ((0xf & RDP_OED_TXBIAS) << RDP_OED_TYPE_SHIFT);
        desc->oed_info.function_flags = cpu_to_be32(flags);
        desc->length = cpu_to_be32(sizeof(desc->oed_info));
+       return sizeof(struct fc_rdp_oed_sfp_desc);
 }
 
-void
-lpfc_rdp_res_oed_txpower_desc(struct fc_rdp_oed_sfp_desc *desc,
+uint32_t
+lpfc_rdp_res_oed_txpower_desc(struct lpfc_hba *phba,
+                             struct fc_rdp_oed_sfp_desc *desc,
                              uint8_t *page_a2)
 {
-       uint32_t flags;
+       uint32_t flags = 0;
 
        desc->tag = cpu_to_be32(RDP_OED_DESC_TAG);
 
-       desc->oed_info.hi_alarm =
-                       cpu_to_be16(page_a2[SSF_TXPOWER_HIGH_ALARM]);
-       desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_TXPOWER_LOW_ALARM]);
-       desc->oed_info.hi_warning =
-                       cpu_to_be16(page_a2[SSF_TXPOWER_HIGH_WARNING]);
-       desc->oed_info.lo_warning =
-                       cpu_to_be16(page_a2[SSF_TXPOWER_LOW_WARNING]);
-       flags = 0xf; /* All four are valid */
+       desc->oed_info.hi_alarm = page_a2[SSF_TXPOWER_HIGH_ALARM];
+       desc->oed_info.lo_alarm = page_a2[SSF_TXPOWER_LOW_ALARM];
+       desc->oed_info.hi_warning = page_a2[SSF_TXPOWER_HIGH_WARNING];
+       desc->oed_info.lo_warning = page_a2[SSF_TXPOWER_LOW_WARNING];
+
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_TXPOWER)
+               flags |= RDP_OET_HIGH_ALARM;
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_TXPOWER)
+               flags |= RDP_OET_LOW_ALARM;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_TXPOWER)
+               flags |= RDP_OET_HIGH_WARNING;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_TXPOWER)
+               flags |= RDP_OET_LOW_WARNING;
+
        flags |= ((0xf & RDP_OED_TXPOWER) << RDP_OED_TYPE_SHIFT);
        desc->oed_info.function_flags = cpu_to_be32(flags);
        desc->length = cpu_to_be32(sizeof(desc->oed_info));
+       return sizeof(struct fc_rdp_oed_sfp_desc);
 }
 
 
-void
-lpfc_rdp_res_oed_rxpower_desc(struct fc_rdp_oed_sfp_desc *desc,
+uint32_t
+lpfc_rdp_res_oed_rxpower_desc(struct lpfc_hba *phba,
+                             struct fc_rdp_oed_sfp_desc *desc,
                              uint8_t *page_a2)
 {
-       uint32_t flags;
+       uint32_t flags = 0;
 
        desc->tag = cpu_to_be32(RDP_OED_DESC_TAG);
 
-       desc->oed_info.hi_alarm =
-                       cpu_to_be16(page_a2[SSF_RXPOWER_HIGH_ALARM]);
-       desc->oed_info.lo_alarm = cpu_to_be16(page_a2[SSF_RXPOWER_LOW_ALARM]);
-       desc->oed_info.hi_warning =
-                       cpu_to_be16(page_a2[SSF_RXPOWER_HIGH_WARNING]);
-       desc->oed_info.lo_warning =
-                       cpu_to_be16(page_a2[SSF_RXPOWER_LOW_WARNING]);
-       flags = 0xf; /* All four are valid */
+       desc->oed_info.hi_alarm = page_a2[SSF_RXPOWER_HIGH_ALARM];
+       desc->oed_info.lo_alarm = page_a2[SSF_RXPOWER_LOW_ALARM];
+       desc->oed_info.hi_warning = page_a2[SSF_RXPOWER_HIGH_WARNING];
+       desc->oed_info.lo_warning = page_a2[SSF_RXPOWER_LOW_WARNING];
+
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_HIGH_RXPOWER)
+               flags |= RDP_OET_HIGH_ALARM;
+       if (phba->sfp_alarm & LPFC_TRANSGRESSION_LOW_RXPOWER)
+               flags |= RDP_OET_LOW_ALARM;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_HIGH_RXPOWER)
+               flags |= RDP_OET_HIGH_WARNING;
+       if (phba->sfp_warning & LPFC_TRANSGRESSION_LOW_RXPOWER)
+               flags |= RDP_OET_LOW_WARNING;
+
        flags |= ((0xf & RDP_OED_RXPOWER) << RDP_OED_TYPE_SHIFT);
        desc->oed_info.function_flags = cpu_to_be32(flags);
        desc->length = cpu_to_be32(sizeof(desc->oed_info));
+       return sizeof(struct fc_rdp_oed_sfp_desc);
 }
 
-void
+uint32_t
 lpfc_rdp_res_opd_desc(struct fc_rdp_opd_sfp_desc *desc,
                      uint8_t *page_a0, struct lpfc_vport *vport)
 {
@@ -4845,9 +4904,10 @@ lpfc_rdp_res_opd_desc(struct fc_rdp_opd_sfp_desc *desc,
        memcpy(desc->opd_info.revision, &page_a0[SSF_VENDOR_REV], 2);
        memcpy(desc->opd_info.date, &page_a0[SSF_DATE_CODE], 8);
        desc->length = cpu_to_be32(sizeof(desc->opd_info));
+       return sizeof(struct fc_rdp_opd_sfp_desc);
 }
 
-int
+uint32_t
 lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat)
 {
        if (bf_get(lpfc_read_link_stat_gec2, stat) == 0)
@@ -4864,7 +4924,7 @@ lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat)
        return sizeof(struct fc_fec_rdp_desc);
 }
 
-void
+uint32_t
 lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
 {
        uint16_t rdp_cap = 0;
@@ -4923,9 +4983,10 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
 
        desc->info.port_speed.capabilities = cpu_to_be16(rdp_cap);
        desc->length = cpu_to_be32(sizeof(desc->info));
+       return sizeof(struct fc_rdp_port_speed_desc);
 }
 
-void
+uint32_t
 lpfc_rdp_res_diag_port_names(struct fc_rdp_port_name_desc *desc,
                struct lpfc_hba *phba)
 {
@@ -4939,9 +5000,10 @@ lpfc_rdp_res_diag_port_names(struct fc_rdp_port_name_desc *desc,
                        sizeof(desc->port_names.wwpn));
 
        desc->length = cpu_to_be32(sizeof(desc->port_names));
+       return sizeof(struct fc_rdp_port_name_desc);
 }
 
-void
+uint32_t
 lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc,
                struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
@@ -4962,6 +5024,7 @@ lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc,
        }
 
        desc->length = cpu_to_be32(sizeof(desc->port_names));
+       return sizeof(struct fc_rdp_port_name_desc);
 }
 
 void
@@ -4976,8 +5039,9 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
        uint8_t *pcmd;
        struct ls_rjt *stat;
        struct fc_rdp_res_frame *rdp_res;
-       uint32_t cmdsize;
-       int rc, fec_size;
+       uint32_t cmdsize, len;
+       uint16_t *flag_ptr;
+       int rc;
 
        if (status != SUCCESS)
                goto error;
@@ -5008,39 +5072,61 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
        memset(pcmd, 0, sizeof(struct fc_rdp_res_frame));
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
 
+       /* Update Alarm and Warning */
+       flag_ptr = (uint16_t *)(rdp_context->page_a2 + SSF_ALARM_FLAGS);
+       phba->sfp_alarm |= *flag_ptr;
+       flag_ptr = (uint16_t *)(rdp_context->page_a2 + SSF_WARNING_FLAGS);
+       phba->sfp_warning |= *flag_ptr;
+
        /* For RDP payload */
-       lpfc_rdp_res_link_service(&rdp_res->link_service_desc, ELS_CMD_RDP);
+       len = 8;
+       len += lpfc_rdp_res_link_service((struct fc_rdp_link_service_desc *)
+                                        (len + pcmd), ELS_CMD_RDP);
 
-       lpfc_rdp_res_sfp_desc(&rdp_res->sfp_desc,
+       len += lpfc_rdp_res_sfp_desc((struct fc_rdp_sfp_desc *)(len + pcmd),
                        rdp_context->page_a0, rdp_context->page_a2);
-       lpfc_rdp_res_speed(&rdp_res->portspeed_desc, phba);
-       lpfc_rdp_res_link_error(&rdp_res->link_error_desc,
-                       &rdp_context->link_stat);
-       lpfc_rdp_res_diag_port_names(&rdp_res->diag_port_names_desc, phba);
-       lpfc_rdp_res_attach_port_names(&rdp_res->attached_port_names_desc,
-                       vport, ndlp);
-       lpfc_rdp_res_bbc_desc(&rdp_res->bbc_desc, &rdp_context->link_stat,
-                             vport);
-       lpfc_rdp_res_oed_temp_desc(&rdp_res->oed_temp_desc,
-                                  rdp_context->page_a2);
-       lpfc_rdp_res_oed_voltage_desc(&rdp_res->oed_voltage_desc,
-                                     rdp_context->page_a2);
-       lpfc_rdp_res_oed_txbias_desc(&rdp_res->oed_txbias_desc,
-                                    rdp_context->page_a2);
-       lpfc_rdp_res_oed_txpower_desc(&rdp_res->oed_txpower_desc,
-                                     rdp_context->page_a2);
-       lpfc_rdp_res_oed_rxpower_desc(&rdp_res->oed_rxpower_desc,
-                                     rdp_context->page_a2);
-       lpfc_rdp_res_opd_desc(&rdp_res->opd_desc, rdp_context->page_a0, vport);
-       fec_size = lpfc_rdp_res_fec_desc(&rdp_res->fec_desc,
+       len += lpfc_rdp_res_speed((struct fc_rdp_port_speed_desc *)(len + pcmd),
+                                 phba);
+       len += lpfc_rdp_res_link_error((struct fc_rdp_link_error_status_desc *)
+                                      (len + pcmd), &rdp_context->link_stat);
+       len += lpfc_rdp_res_diag_port_names((struct fc_rdp_port_name_desc *)
+                                            (len + pcmd), phba);
+       len += lpfc_rdp_res_attach_port_names((struct fc_rdp_port_name_desc *)
+                                       (len + pcmd), vport, ndlp);
+       len += lpfc_rdp_res_fec_desc((struct fc_fec_rdp_desc *)(len + pcmd),
                        &rdp_context->link_stat);
-       rdp_res->length = cpu_to_be32(fec_size + RDP_DESC_PAYLOAD_SIZE);
+       /* Check if nport is logged, BZ190632 */
+       if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED))
+               goto lpfc_skip_descriptor;
+
+       len += lpfc_rdp_res_bbc_desc((struct fc_rdp_bbc_desc *)(len + pcmd),
+                                    &rdp_context->link_stat, vport);
+       len += lpfc_rdp_res_oed_temp_desc(phba,
+                               (struct fc_rdp_oed_sfp_desc *)(len + pcmd),
+                               rdp_context->page_a2);
+       len += lpfc_rdp_res_oed_voltage_desc(phba,
+                               (struct fc_rdp_oed_sfp_desc *)(len + pcmd),
+                               rdp_context->page_a2);
+       len += lpfc_rdp_res_oed_txbias_desc(phba,
+                               (struct fc_rdp_oed_sfp_desc *)(len + pcmd),
+                               rdp_context->page_a2);
+       len += lpfc_rdp_res_oed_txpower_desc(phba,
+                               (struct fc_rdp_oed_sfp_desc *)(len + pcmd),
+                               rdp_context->page_a2);
+       len += lpfc_rdp_res_oed_rxpower_desc(phba,
+                               (struct fc_rdp_oed_sfp_desc *)(len + pcmd),
+                               rdp_context->page_a2);
+       len += lpfc_rdp_res_opd_desc((struct fc_rdp_opd_sfp_desc *)(len + pcmd),
+                                    rdp_context->page_a0, vport);
+
+lpfc_skip_descriptor:
+       rdp_res->length = cpu_to_be32(len - 8);
        elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 
        /* Now that we know the true size of the payload, update the BPL */
        bpl = (struct ulp_bde64 *)
                (((struct lpfc_dmabuf *)(elsiocb->context3))->virt);
-       bpl->tus.f.bdeSize = (fec_size + RDP_DESC_PAYLOAD_SIZE + 8);
+       bpl->tus.f.bdeSize = len;
        bpl->tus.f.bdeFlags = 0;
        bpl->tus.w = le32_to_cpu(bpl->tus.w);
 
@@ -5165,6 +5251,12 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                         be32_to_cpu(rdp_req->nport_id_desc.nport_id),
                         be32_to_cpu(rdp_req->nport_id_desc.length));
 
+       if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED) &&
+           !phba->cfg_enable_SmartSAN) {
+               rjt_err = LSRJT_UNABLE_TPC;
+               rjt_expl = LSEXP_PORT_LOGIN_REQ;
+               goto error;
+       }
        if (sizeof(struct fc_rdp_nport_desc) !=
                        be32_to_cpu(rdp_req->rdp_des_length))
                goto rjt_logerr;
index 39f0fd000d2cf0ede29b7bd1d866a7206694ac6b..822654322e67896b68a6fd2e023ebfbc7546ca04 100644 (file)
@@ -346,7 +346,7 @@ struct csp {
        uint8_t fcphHigh;       /* FC Word 0, byte 0 */
        uint8_t fcphLow;
        uint8_t bbCreditMsb;
-       uint8_t bbCreditlsb;    /* FC Word 0, byte 3 */
+       uint8_t bbCreditLsb;    /* FC Word 0, byte 3 */
 
 /*
  * Word 1 Bit 31 in common service parameter is overloaded.
@@ -1206,6 +1206,12 @@ struct fc_rdp_bbc_desc {
        struct fc_rdp_bbc_info  bbc_info;
 };
 
+/* Optical Element Type Transgression Flags */
+#define RDP_OET_LOW_WARNING  0x1
+#define RDP_OET_HIGH_WARNING 0x2
+#define RDP_OET_LOW_ALARM    0x4
+#define RDP_OET_HIGH_ALARM   0x8
+
 #define RDP_OED_TEMPERATURE  0x1
 #define RDP_OED_VOLTAGE      0x2
 #define RDP_OED_TXBIAS       0x3
@@ -1233,8 +1239,8 @@ struct fc_rdp_opd_sfp_info {
        uint8_t            vendor_name[16];
        uint8_t            model_number[16];
        uint8_t            serial_number[16];
-       uint8_t            reserved[2];
        uint8_t            revision[2];
+       uint8_t            reserved[2];
        uint8_t            date[8];
 };
 
@@ -1261,27 +1267,17 @@ struct fc_rdp_res_frame {
        struct fc_rdp_link_error_status_desc link_error_desc; /* Word 13-21 */
        struct fc_rdp_port_name_desc diag_port_names_desc;    /* Word 22-27 */
        struct fc_rdp_port_name_desc attached_port_names_desc;/* Word 28-33 */
-       struct fc_rdp_bbc_desc bbc_desc;                      /* FC Word 34-38*/
-       struct fc_rdp_oed_sfp_desc oed_temp_desc;             /* FC Word 39-43*/
-       struct fc_rdp_oed_sfp_desc oed_voltage_desc;          /* FC word 44-48*/
-       struct fc_rdp_oed_sfp_desc oed_txbias_desc;           /* FC word 49-53*/
-       struct fc_rdp_oed_sfp_desc oed_txpower_desc;          /* FC word 54-58*/
-       struct fc_rdp_oed_sfp_desc oed_rxpower_desc;          /* FC word 59-63*/
-       struct fc_rdp_opd_sfp_desc opd_desc;                  /* FC word 64-80*/
-       struct fc_fec_rdp_desc fec_desc;                      /* FC word 81-84*/
+       struct fc_fec_rdp_desc fec_desc;                      /* FC word 34-37*/
+       struct fc_rdp_bbc_desc bbc_desc;                      /* FC Word 38-42*/
+       struct fc_rdp_oed_sfp_desc oed_temp_desc;             /* FC Word 43-47*/
+       struct fc_rdp_oed_sfp_desc oed_voltage_desc;          /* FC word 48-52*/
+       struct fc_rdp_oed_sfp_desc oed_txbias_desc;           /* FC word 53-57*/
+       struct fc_rdp_oed_sfp_desc oed_txpower_desc;          /* FC word 58-62*/
+       struct fc_rdp_oed_sfp_desc oed_rxpower_desc;          /* FC word 63-67*/
+       struct fc_rdp_opd_sfp_desc opd_desc;                  /* FC word 68-84*/
 };
 
 
-#define RDP_DESC_PAYLOAD_SIZE (sizeof(struct fc_rdp_link_service_desc) \
-                               + sizeof(struct fc_rdp_sfp_desc) \
-                               + sizeof(struct fc_rdp_port_speed_desc) \
-                               + sizeof(struct fc_rdp_link_error_status_desc) \
-                               + (sizeof(struct fc_rdp_port_name_desc) * 2) \
-                               + sizeof(struct fc_rdp_bbc_desc) \
-                               + (sizeof(struct fc_rdp_oed_sfp_desc) * 5) \
-                               + sizeof(struct fc_rdp_opd_sfp_desc))
-
-
 /******** FDMI ********/
 
 /* lpfc_sli_ct_request defines the CT_IU preamble for FDMI commands */
index 0c7070bf28132f5e76cd877c380bc5712c34bfa6..ee80227375915677fb1f89c8c74bd678c84a92eb 100644 (file)
@@ -544,6 +544,8 @@ struct lpfc_register {
        uint32_t word0;
 };
 
+#define LPFC_PORT_SEM_UE_RECOVERABLE    0xE000
+#define LPFC_PORT_SEM_MASK             0xF000
 /* The following BAR0 Registers apply to SLI4 if_type 0 UCNAs. */
 #define LPFC_UERR_STATUS_HI            0x00A4
 #define LPFC_UERR_STATUS_LO            0x00A0
@@ -937,6 +939,7 @@ struct mbox_header {
 #define LPFC_MBOX_OPCODE_READ_OBJECT_LIST              0xAD
 #define LPFC_MBOX_OPCODE_DELETE_OBJECT                 0xAE
 #define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS           0xB5
+#define LPFC_MBOX_OPCODE_SET_FEATURES                   0xBF
 
 /* FCoE Opcodes */
 #define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE                        0x01
@@ -2590,10 +2593,8 @@ struct lpfc_mbx_memory_dump_type3 {
 #define SFF_RXPOWER_B1                 104
 #define SFF_RXPOWER_B0                 105
 #define SSF_STATUS_CONTROL             110
-#define SSF_ALARM_FLAGS_B1             112
-#define SSF_ALARM_FLAGS_B0             113
-#define SSF_WARNING_FLAGS_B1           116
-#define SSF_WARNING_FLAGS_B0           117
+#define SSF_ALARM_FLAGS                        112
+#define SSF_WARNING_FLAGS              116
 #define SSF_EXT_TATUS_CONTROL_B1       118
 #define SSF_EXT_TATUS_CONTROL_B0       119
 #define SSF_A2_VENDOR_SPECIFIC         120
@@ -2887,8 +2888,37 @@ struct lpfc_sli4_parameters {
 #define cfg_ext_embed_cb_SHIFT                 0
 #define cfg_ext_embed_cb_MASK                  0x00000001
 #define cfg_ext_embed_cb_WORD                  word19
+#define cfg_mds_diags_SHIFT                    1
+#define cfg_mds_diags_MASK                     0x00000001
+#define cfg_mds_diags_WORD                     word19
 };
 
+#define LPFC_SET_UE_RECOVERY           0x10
+#define LPFC_SET_MDS_DIAGS             0x11
+struct lpfc_mbx_set_feature {
+       struct mbox_header header;
+       uint32_t feature;
+       uint32_t param_len;
+       uint32_t word6;
+#define lpfc_mbx_set_feature_UER_SHIFT  0
+#define lpfc_mbx_set_feature_UER_MASK   0x00000001
+#define lpfc_mbx_set_feature_UER_WORD   word6
+#define lpfc_mbx_set_feature_mds_SHIFT  0
+#define lpfc_mbx_set_feature_mds_MASK   0x00000001
+#define lpfc_mbx_set_feature_mds_WORD   word6
+#define lpfc_mbx_set_feature_mds_deep_loopbk_SHIFT  1
+#define lpfc_mbx_set_feature_mds_deep_loopbk_MASK   0x00000001
+#define lpfc_mbx_set_feature_mds_deep_loopbk_WORD   word6
+       uint32_t word7;
+#define lpfc_mbx_set_feature_UERP_SHIFT 0
+#define lpfc_mbx_set_feature_UERP_MASK  0x0000ffff
+#define lpfc_mbx_set_feature_UERP_WORD  word7
+#define lpfc_mbx_set_feature_UESR_SHIFT 16
+#define lpfc_mbx_set_feature_UESR_MASK  0x0000ffff
+#define lpfc_mbx_set_feature_UESR_WORD  word7
+};
+
+
 struct lpfc_mbx_get_sli4_parameters {
        struct mbox_header header;
        struct lpfc_sli4_parameters sli4_parameters;
@@ -3281,6 +3311,7 @@ struct lpfc_mqe {
                struct lpfc_mbx_get_prof_cfg get_prof_cfg;
                struct lpfc_mbx_wr_object wr_object;
                struct lpfc_mbx_get_port_name get_port_name;
+               struct lpfc_mbx_set_feature  set_feature;
                struct lpfc_mbx_memory_dump_type3 mem_dump_type3;
                struct lpfc_mbx_nop nop;
        } un;
@@ -3443,6 +3474,8 @@ struct lpfc_acqe_fc_la {
 #define LPFC_FC_LA_TYPE_LINK_UP                0x1
 #define LPFC_FC_LA_TYPE_LINK_DOWN      0x2
 #define LPFC_FC_LA_TYPE_NO_HARD_ALPA   0x3
+#define LPFC_FC_LA_TYPE_MDS_LINK_DOWN  0x4
+#define LPFC_FC_LA_TYPE_MDS_LOOPBACK   0x5
 #define lpfc_acqe_fc_la_port_type_SHIFT                6
 #define lpfc_acqe_fc_la_port_type_MASK         0x00000003
 #define lpfc_acqe_fc_la_port_type_WORD         word0
diff --git a/drivers/scsi/lpfc/lpfc_ids.h b/drivers/scsi/lpfc/lpfc_ids.h
new file mode 100644 (file)
index 0000000..5733fea
--- /dev/null
@@ -0,0 +1,122 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+#include <linux/pci.h>
+
+const struct pci_device_id lpfc_id_table[] = {
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FIREFLY,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_THOR,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PEGASUS,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_CENTAUR,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_DRAGONFLY,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SUPERFLY,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_RFLY,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PFLY,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BMID,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BSMB,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HORNET,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZMID,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZSMB,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_TFLY,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP101,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP10000S,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP11000S,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_VF,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_PF,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TOMCAT,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC_VF,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       { 0 }
+};
index b43f7ac9812c3473b0bb04c227bfc7c38e09175e..adf61b43eb70716f5b00d2c019fec6e4099376e1 100644 (file)
@@ -52,6 +52,7 @@
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
 #include "lpfc_version.h"
+#include "lpfc_ids.h"
 
 char *_dump_buf_data;
 unsigned long _dump_buf_data_order;
@@ -568,7 +569,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
        phba->last_completion_time = jiffies;
        /* Set up error attention (ERATT) polling timer */
        mod_timer(&phba->eratt_poll,
-                 jiffies + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL));
+                 jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval));
 
        if (phba->hba_flag & LINK_DISABLED) {
                lpfc_printf_log(phba,
@@ -1587,35 +1588,39 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action,
        int rc;
        uint32_t intr_mode;
 
-       /*
-        * On error status condition, driver need to wait for port
-        * ready before performing reset.
-        */
-       rc = lpfc_sli4_pdev_status_reg_wait(phba);
-       if (!rc) {
-               /* need reset: attempt for port recovery */
-               if (en_rn_msg)
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                       "2887 Reset Needed: Attempting Port "
-                                       "Recovery...\n");
-               lpfc_offline_prep(phba, mbx_action);
-               lpfc_offline(phba);
-               /* release interrupt for possible resource change */
-               lpfc_sli4_disable_intr(phba);
-               lpfc_sli_brdrestart(phba);
-               /* request and enable interrupt */
-               intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
-               if (intr_mode == LPFC_INTR_ERROR) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                                       "3175 Failed to enable interrupt\n");
-                       return -EIO;
-               } else {
-                       phba->intr_mode = intr_mode;
-               }
-               rc = lpfc_online(phba);
-               if (rc == 0)
-                       lpfc_unblock_mgmt_io(phba);
+       if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+           LPFC_SLI_INTF_IF_TYPE_2) {
+               /*
+                * On error status condition, driver need to wait for port
+                * ready before performing reset.
+                */
+               rc = lpfc_sli4_pdev_status_reg_wait(phba);
+               if (rc)
+                       return rc;
        }
+
+       /* need reset: attempt for port recovery */
+       if (en_rn_msg)
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2887 Reset Needed: Attempting Port "
+                               "Recovery...\n");
+       lpfc_offline_prep(phba, mbx_action);
+       lpfc_offline(phba);
+       /* release interrupt for possible resource change */
+       lpfc_sli4_disable_intr(phba);
+       lpfc_sli_brdrestart(phba);
+       /* request and enable interrupt */
+       intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
+       if (intr_mode == LPFC_INTR_ERROR) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3175 Failed to enable interrupt\n");
+               return -EIO;
+       }
+       phba->intr_mode = intr_mode;
+       rc = lpfc_online(phba);
+       if (rc == 0)
+               lpfc_unblock_mgmt_io(phba);
+
        return rc;
 }
 
@@ -1636,10 +1641,11 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
        struct lpfc_register portstat_reg = {0};
        uint32_t reg_err1, reg_err2;
        uint32_t uerrlo_reg, uemasklo_reg;
-       uint32_t pci_rd_rc1, pci_rd_rc2;
+       uint32_t smphr_port_status = 0, pci_rd_rc1, pci_rd_rc2;
        bool en_rn_msg = true;
        struct temp_event temp_event_data;
-       int rc;
+       struct lpfc_register portsmphr_reg;
+       int rc, i;
 
        /* If the pci channel is offline, ignore possible errors, since
         * we cannot communicate with the pci card anyway.
@@ -1647,6 +1653,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
        if (pci_channel_offline(phba->pcidev))
                return;
 
+       memset(&portsmphr_reg, 0, sizeof(portsmphr_reg));
        if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
        switch (if_type) {
        case LPFC_SLI_INTF_IF_TYPE_0:
@@ -1659,6 +1666,55 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
                /* consider PCI bus read error as pci_channel_offline */
                if (pci_rd_rc1 == -EIO && pci_rd_rc2 == -EIO)
                        return;
+               if (!(phba->hba_flag & HBA_RECOVERABLE_UE)) {
+                       lpfc_sli4_offline_eratt(phba);
+                       return;
+               }
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "7623 Checking UE recoverable");
+
+               for (i = 0; i < phba->sli4_hba.ue_to_sr / 1000; i++) {
+                       if (lpfc_readl(phba->sli4_hba.PSMPHRregaddr,
+                                      &portsmphr_reg.word0))
+                               continue;
+
+                       smphr_port_status = bf_get(lpfc_port_smphr_port_status,
+                                                  &portsmphr_reg);
+                       if ((smphr_port_status & LPFC_PORT_SEM_MASK) ==
+                           LPFC_PORT_SEM_UE_RECOVERABLE)
+                               break;
+                       /*Sleep for 1Sec, before checking SEMAPHORE */
+                       msleep(1000);
+               }
+
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "4827 smphr_port_status x%x : Waited %dSec",
+                               smphr_port_status, i);
+
+               /* Recoverable UE, reset the HBA device */
+               if ((smphr_port_status & LPFC_PORT_SEM_MASK) ==
+                   LPFC_PORT_SEM_UE_RECOVERABLE) {
+                       for (i = 0; i < 20; i++) {
+                               msleep(1000);
+                               if (!lpfc_readl(phba->sli4_hba.PSMPHRregaddr,
+                                   &portsmphr_reg.word0) &&
+                                   (LPFC_POST_STAGE_PORT_READY ==
+                                    bf_get(lpfc_port_smphr_port_status,
+                                    &portsmphr_reg))) {
+                                       rc = lpfc_sli4_port_sta_fn_reset(phba,
+                                               LPFC_MBX_NO_WAIT, en_rn_msg);
+                                       if (rc == 0)
+                                               return;
+                                       lpfc_printf_log(phba,
+                                               KERN_ERR, LOG_INIT,
+                                               "4215 Failed to recover UE");
+                                       break;
+                               }
+                       }
+               }
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "7624 Firmware not ready: Failing UE recovery,"
+                               " waited %dSec", i);
                lpfc_sli4_offline_eratt(phba);
                break;
 
@@ -1681,6 +1737,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
                                "taking port offline Data: x%x x%x\n",
                                reg_err1, reg_err2);
 
+                       phba->sfp_alarm |= LPFC_TRANSGRESSION_HIGH_TEMPERATURE;
                        temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
                        temp_event_data.event_code = LPFC_CRIT_TEMP;
                        temp_event_data.data = 0xFFFFFFFF;
@@ -3985,6 +4042,8 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
 {
        struct lpfc_dmabuf *mp;
        LPFC_MBOXQ_t *pmb;
+       MAILBOX_t *mb;
+       struct lpfc_mbx_read_top *la;
        int rc;
 
        if (bf_get(lpfc_trailer_type, acqe_fc) !=
@@ -4055,6 +4114,24 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
        pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
        pmb->vport = phba->pport;
 
+       if (phba->sli4_hba.link_state.status != LPFC_FC_LA_TYPE_LINK_UP) {
+               /* Parse and translate status field */
+               mb = &pmb->u.mb;
+               mb->mbxStatus = lpfc_sli4_parse_latt_fault(phba,
+                                                          (void *)acqe_fc);
+
+               /* Parse and translate link attention fields */
+               la = (struct lpfc_mbx_read_top *)&pmb->u.mb.un.varReadTop;
+               la->eventTag = acqe_fc->event_tag;
+               bf_set(lpfc_mbx_read_top_att_type, la,
+                      LPFC_FC_LA_TYPE_LINK_DOWN);
+
+               /* Invoke the mailbox command callback function */
+               lpfc_mbx_cmpl_read_topology(phba, pmb);
+
+               return;
+       }
+
        rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
        if (rc == MBX_NOT_FINISHED)
                goto out_free_dmabuf;
@@ -4107,6 +4184,7 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
                                "3190 Over Temperature:%d Celsius- Port Name %c\n",
                                acqe_sli->event_data1, port_name);
 
+               phba->sfp_warning |= LPFC_TRANSGRESSION_HIGH_TEMPERATURE;
                shost = lpfc_shost_from_vport(phba->pport);
                fc_host_post_vendor_event(shost, fc_get_event_number(),
                                          sizeof(temp_event_data),
@@ -4408,7 +4486,8 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
                 * the corresponding FCF bit in the roundrobin bitmap.
                 */
                spin_lock_irq(&phba->hbalock);
-               if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
+               if ((phba->fcf.fcf_flag & FCF_DISCOVERY) &&
+                   (phba->fcf.current_rec.fcf_indx != acqe_fip->index)) {
                        spin_unlock_irq(&phba->hbalock);
                        /* Update FLOGI FCF failover eligible FCF bmask */
                        lpfc_sli4_fcf_rr_index_clear(phba, acqe_fip->index);
@@ -5363,6 +5442,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                        goto out_free_bsmbx;
                }
        }
+
        /*
         * Get sli4 parameters that override parameters from Port capabilities.
         * If this call fails, it isn't critical unless the SLI4 parameters come
@@ -6091,6 +6171,7 @@ lpfc_hba_alloc(struct pci_dev *pdev)
                kfree(phba);
                return NULL;
        }
+       phba->eratt_poll_interval = LPFC_ERATT_POLL_INTERVAL;
 
        spin_lock_init(&phba->ct_ev_lock);
        INIT_LIST_HEAD(&phba->ct_ev_waiters);
@@ -9527,6 +9608,14 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                phba->fcp_embed_io = 1;
        else
                phba->fcp_embed_io = 0;
+
+       /*
+        * Check if the SLI port supports MDS Diagnostics
+        */
+       if (bf_get(cfg_mds_diags, mbx_sli4_parameters))
+               phba->mds_diags_support = 1;
+       else
+               phba->mds_diags_support = 0;
        return 0;
 }
 
@@ -11298,106 +11387,6 @@ lpfc_fof_queue_destroy(struct lpfc_hba *phba)
        return 0;
 }
 
-static struct pci_device_id lpfc_id_table[] = {
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FIREFLY,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_THOR,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PEGASUS,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_CENTAUR,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_DRAGONFLY,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SUPERFLY,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_RFLY,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PFLY,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_SCSP,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_DCSP,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_SCSP,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_DCSP,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BMID,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BSMB,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HORNET,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_SCSP,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_DCSP,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZMID,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZSMB,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_TFLY,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP101,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP10000S,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP11000S,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_VF,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_PF,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TOMCAT,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC_VF,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF,
-               PCI_ANY_ID, PCI_ANY_ID, },
-       { 0 }
-};
-
 MODULE_DEVICE_TABLE(pci, lpfc_id_table);
 
 static const struct pci_error_handlers lpfc_err_handler = {
@@ -11452,21 +11441,17 @@ lpfc_init(void)
                printk(KERN_ERR "Could not register lpfcmgmt device, "
                        "misc_register returned with status %d", error);
 
-       if (lpfc_enable_npiv) {
-               lpfc_transport_functions.vport_create = lpfc_vport_create;
-               lpfc_transport_functions.vport_delete = lpfc_vport_delete;
-       }
+       lpfc_transport_functions.vport_create = lpfc_vport_create;
+       lpfc_transport_functions.vport_delete = lpfc_vport_delete;
        lpfc_transport_template =
                                fc_attach_transport(&lpfc_transport_functions);
        if (lpfc_transport_template == NULL)
                return -ENOMEM;
-       if (lpfc_enable_npiv) {
-               lpfc_vport_transport_template =
-                       fc_attach_transport(&lpfc_vport_transport_functions);
-               if (lpfc_vport_transport_template == NULL) {
-                       fc_release_transport(lpfc_transport_template);
-                       return -ENOMEM;
-               }
+       lpfc_vport_transport_template =
+               fc_attach_transport(&lpfc_vport_transport_functions);
+       if (lpfc_vport_transport_template == NULL) {
+               fc_release_transport(lpfc_transport_template);
+               return -ENOMEM;
        }
 
        /* Initialize in case vector mapping is needed */
@@ -11478,8 +11463,7 @@ lpfc_init(void)
        error = pci_register_driver(&lpfc_driver);
        if (error) {
                fc_release_transport(lpfc_transport_template);
-               if (lpfc_enable_npiv)
-                       fc_release_transport(lpfc_vport_transport_template);
+               fc_release_transport(lpfc_vport_transport_template);
        }
 
        return error;
@@ -11498,8 +11482,7 @@ lpfc_exit(void)
        misc_deregister(&lpfc_mgmt_dev);
        pci_unregister_driver(&lpfc_driver);
        fc_release_transport(lpfc_transport_template);
-       if (lpfc_enable_npiv)
-               fc_release_transport(lpfc_vport_transport_template);
+       fc_release_transport(lpfc_vport_transport_template);
        if (_dump_buf_data) {
                printk(KERN_ERR "9062 BLKGRD: freeing %lu pages for "
                                "_dump_buf_data at 0x%p\n",
index 3bd0be6277b3e0223177b5320ab6352ffd88d649..a5655d571906807784e38daec342d2eefe9e663c 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2015 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -3335,8 +3335,11 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
         * OAS, set the oas iocb related flags.
         */
        if ((phba->cfg_fof) && ((struct lpfc_device_data *)
-               scsi_cmnd->device->hostdata)->oas_enabled)
+               scsi_cmnd->device->hostdata)->oas_enabled) {
                lpfc_cmd->cur_iocbq.iocb_flag |= (LPFC_IO_OAS | LPFC_IO_FOF);
+               lpfc_cmd->cur_iocbq.priority = ((struct lpfc_device_data *)
+                       scsi_cmnd->device->hostdata)->priority;
+       }
        return 0;
 }
 
@@ -5607,6 +5610,7 @@ lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
               sizeof(struct lpfc_name));
        lun_info->device_id.lun = lun;
        lun_info->oas_enabled = false;
+       lun_info->priority = phba->cfg_XLanePriority;
        lun_info->available = false;
        return lun_info;
 }
@@ -5798,7 +5802,7 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
  **/
 bool
 lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
-                   struct lpfc_name *target_wwpn, uint64_t lun)
+                   struct lpfc_name *target_wwpn, uint64_t lun, uint8_t pri)
 {
 
        struct lpfc_device_data *lun_info;
@@ -5825,6 +5829,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
                                           false);
        if (lun_info) {
                lun_info->oas_enabled = true;
+               lun_info->priority = pri;
                lun_info->available = false;
                list_add_tail(&lun_info->listentry, &phba->luns);
                spin_unlock_irqrestore(&phba->devicelock, flags);
@@ -5886,6 +5891,7 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
 struct scsi_host_template lpfc_template_s3 = {
        .module                 = THIS_MODULE,
        .name                   = LPFC_DRIVER_NAME,
+       .proc_name              = LPFC_DRIVER_NAME,
        .info                   = lpfc_info,
        .queuecommand           = lpfc_queuecommand,
        .eh_abort_handler       = lpfc_abort_handler,
@@ -5910,6 +5916,7 @@ struct scsi_host_template lpfc_template_s3 = {
 struct scsi_host_template lpfc_template = {
        .module                 = THIS_MODULE,
        .name                   = LPFC_DRIVER_NAME,
+       .proc_name              = LPFC_DRIVER_NAME,
        .info                   = lpfc_info,
        .queuecommand           = lpfc_queuecommand,
        .eh_abort_handler       = lpfc_abort_handler,
@@ -5935,6 +5942,7 @@ struct scsi_host_template lpfc_template = {
 struct scsi_host_template lpfc_vport_template = {
        .module                 = THIS_MODULE,
        .name                   = LPFC_DRIVER_NAME,
+       .proc_name              = LPFC_DRIVER_NAME,
        .info                   = lpfc_info,
        .queuecommand           = lpfc_queuecommand,
        .eh_abort_handler       = lpfc_abort_handler,
index 18b9260ccfac2f19e0eccaac866dffc785d37195..8cb80dabada849612c9a50b391790aa1d378d4e4 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2015 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -51,6 +51,7 @@ struct lpfc_device_data {
        struct list_head listentry;
        struct lpfc_rport_data *rport_data;
        struct lpfc_device_id device_id;
+       uint8_t priority;
        bool oas_enabled;
        bool available;
 };
index 70edf21ae1b944124093933e3378581ac32f7ca6..351d08ace24a31a2a447ae0e02f095b6aeefd8d6 100644 (file)
@@ -2947,8 +2947,8 @@ void lpfc_poll_eratt(unsigned long ptr)
        else
                cnt = (sli_intr - phba->sli.slistat.sli_prev_intr);
 
-       /* 64-bit integer division not supporte on 32-bit x86 - use do_div */
-       do_div(cnt, LPFC_ERATT_POLL_INTERVAL);
+       /* 64-bit integer division not supported on 32-bit x86 - use do_div */
+       do_div(cnt, phba->eratt_poll_interval);
        phba->sli.slistat.sli_ips = cnt;
 
        phba->sli.slistat.sli_prev_intr = sli_intr;
@@ -2963,7 +2963,7 @@ void lpfc_poll_eratt(unsigned long ptr)
                /* Restart the timer for next eratt poll */
                mod_timer(&phba->eratt_poll,
                          jiffies +
-                         msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL));
+                         msecs_to_jiffies(1000 * phba->eratt_poll_interval));
        return;
 }
 
@@ -4665,13 +4665,13 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
        int  mode = 3, i;
        int longs;
 
-       switch (lpfc_sli_mode) {
+       switch (phba->cfg_sli_mode) {
        case 2:
                if (phba->cfg_enable_npiv) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
-                               "1824 NPIV enabled: Override lpfc_sli_mode "
+                               "1824 NPIV enabled: Override sli_mode "
                                "parameter (%d) to auto (0).\n",
-                               lpfc_sli_mode);
+                               phba->cfg_sli_mode);
                        break;
                }
                mode = 2;
@@ -4681,8 +4681,8 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
                break;
        default:
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
-                               "1819 Unrecognized lpfc_sli_mode "
-                               "parameter: %d.\n", lpfc_sli_mode);
+                               "1819 Unrecognized sli_mode parameter: %d.\n",
+                               phba->cfg_sli_mode);
 
                break;
        }
@@ -4690,12 +4690,14 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
 
        rc = lpfc_sli_config_port(phba, mode);
 
-       if (rc && lpfc_sli_mode == 3)
+       if (rc && phba->cfg_sli_mode == 3)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
                                "1820 Unable to select SLI-3.  "
                                "Not supported by adapter.\n");
        if (rc && mode != 2)
                rc = lpfc_sli_config_port(phba, 2);
+       else if (rc && mode == 2)
+               rc = lpfc_sli_config_port(phba, 3);
        if (rc)
                goto lpfc_sli_hba_setup_error;
 
@@ -5690,6 +5692,38 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type)
        return rc;
 }
 
+void
+lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox,
+                 uint32_t feature)
+{
+       uint32_t len;
+
+       len = sizeof(struct lpfc_mbx_set_feature) -
+               sizeof(struct lpfc_sli4_cfg_mhdr);
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_SET_FEATURES, len,
+                        LPFC_SLI4_MBX_EMBED);
+
+       switch (feature) {
+       case LPFC_SET_UE_RECOVERY:
+               bf_set(lpfc_mbx_set_feature_UER,
+                      &mbox->u.mqe.un.set_feature, 1);
+               mbox->u.mqe.un.set_feature.feature = LPFC_SET_UE_RECOVERY;
+               mbox->u.mqe.un.set_feature.param_len = 8;
+               break;
+       case LPFC_SET_MDS_DIAGS:
+               bf_set(lpfc_mbx_set_feature_mds,
+                      &mbox->u.mqe.un.set_feature, 1);
+               bf_set(lpfc_mbx_set_feature_mds_deep_loopbk,
+                      &mbox->u.mqe.un.set_feature, 0);
+               mbox->u.mqe.un.set_feature.feature = LPFC_SET_MDS_DIAGS;
+               mbox->u.mqe.un.set_feature.param_len = 8;
+               break;
+       }
+
+       return;
+}
+
 /**
  * lpfc_sli4_alloc_resource_identifiers - Allocate all SLI4 resource extents.
  * @phba: Pointer to HBA context object.
@@ -6414,6 +6448,30 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
                phba->pport->cfg_lun_queue_depth = rc;
        }
 
+       if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+           LPFC_SLI_INTF_IF_TYPE_0) {
+               lpfc_set_features(phba, mboxq, LPFC_SET_UE_RECOVERY);
+               rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+               if (rc == MBX_SUCCESS) {
+                       phba->hba_flag |= HBA_RECOVERABLE_UE;
+                       /* Set 1Sec interval to detect UE */
+                       phba->eratt_poll_interval = 1;
+                       phba->sli4_hba.ue_to_sr = bf_get(
+                                       lpfc_mbx_set_feature_UESR,
+                                       &mboxq->u.mqe.un.set_feature);
+                       phba->sli4_hba.ue_to_rp = bf_get(
+                                       lpfc_mbx_set_feature_UERP,
+                                       &mboxq->u.mqe.un.set_feature);
+               }
+       }
+
+       if (phba->cfg_enable_mds_diags && phba->mds_diags_support) {
+               /* Enable MDS Diagnostics only if the SLI Port supports it */
+               lpfc_set_features(phba, mboxq, LPFC_SET_MDS_DIAGS);
+               rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+               if (rc != MBX_SUCCESS)
+                       phba->mds_diags_support = 0;
+       }
 
        /*
         * Discover the port's supported feature set and match it against the
@@ -6612,7 +6670,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
 
        /* Start error attention (ERATT) polling timer */
        mod_timer(&phba->eratt_poll,
-                 jiffies + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL));
+                 jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval));
 
        /* Enable PCIe device Advanced Error Reporting (AER) if configured */
        if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) {
@@ -8383,8 +8441,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
                if (iocbq->iocb_flag & LPFC_IO_OAS) {
                        bf_set(wqe_oas, &wqe->fcp_iwrite.wqe_com, 1);
-                       if (phba->cfg_XLanePriority) {
-                               bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1);
+                       bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1);
+                       if (iocbq->priority) {
+                               bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com,
+                                      (iocbq->priority << 1));
+                       } else {
                                bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com,
                                       (phba->cfg_XLanePriority << 1));
                        }
@@ -8439,8 +8500,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
                if (iocbq->iocb_flag & LPFC_IO_OAS) {
                        bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1);
-                       if (phba->cfg_XLanePriority) {
-                               bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1);
+                       bf_set(wqe_ccpe, &wqe->fcp_iread.wqe_com, 1);
+                       if (iocbq->priority) {
+                               bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com,
+                                      (iocbq->priority << 1));
+                       } else {
                                bf_set(wqe_ccp, &wqe->fcp_iread.wqe_com,
                                       (phba->cfg_XLanePriority << 1));
                        }
@@ -8494,8 +8558,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                       iocbq->iocb.ulpFCP2Rcvy);
                if (iocbq->iocb_flag & LPFC_IO_OAS) {
                        bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1);
-                       if (phba->cfg_XLanePriority) {
-                               bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1);
+                       bf_set(wqe_ccpe, &wqe->fcp_icmd.wqe_com, 1);
+                       if (iocbq->priority) {
+                               bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com,
+                                      (iocbq->priority << 1));
+                       } else {
                                bf_set(wqe_ccp, &wqe->fcp_icmd.wqe_com,
                                       (phba->cfg_XLanePriority << 1));
                        }
@@ -10136,6 +10203,7 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id,
        struct lpfc_iocbq *iocbq;
        int sum, i;
 
+       spin_lock_irq(&phba->hbalock);
        for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) {
                iocbq = phba->sli.iocbq_lookup[i];
 
@@ -10143,6 +10211,7 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id,
                                                ctx_cmd) == 0)
                        sum++;
        }
+       spin_unlock_irq(&phba->hbalock);
 
        return sum;
 }
index 7fe99ff8084686757e39aa0ceae172cf69850d49..74227a28bd569ec5bf4bb012a87fb46af838b17a 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2015 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -57,6 +57,7 @@ struct lpfc_iocbq {
        struct lpfc_cq_event cq_event;
 
        IOCB_t iocb;            /* IOCB cmd */
+       uint8_t priority;       /* OAS priority */
        uint8_t retry;          /* retry counter for IOCB cmd - if needed */
        uint32_t iocb_flag;
 #define LPFC_IO_LIBDFC         1       /* libdfc iocb */
index cd780c29495aa6eddedafa34367c315fa9813e84..0b88b5703e0f10b835e79981594cc6a606e401f4 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2009-2015 Emulex.  All rights reserved.           *
+ * Copyright (C) 2009-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -511,6 +511,8 @@ struct lpfc_sli4_hba {
 
        uint32_t ue_mask_lo;
        uint32_t ue_mask_hi;
+       uint32_t ue_to_sr;
+       uint32_t ue_to_rp;
        struct lpfc_register sli_intf;
        struct lpfc_pc_sli4_params pc_sli4_params;
        struct msix_entry *msix_entries;
index fa0d531bf351008e9e2aff60af5a6412177b2918..c9bf20eb7223286df3fe5959ba76b98e4b0d43af 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "11.1.0.0."
+#define LPFC_DRIVER_VERSION "11.2.0.0."
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
index f4b0690450d2402dd8978aea51bed78d1aa48d96..2dab3dc2aa69bf44c4f92a3cd539314711964081 100644 (file)
@@ -4079,6 +4079,12 @@ megasas_get_pd_list(struct megasas_instance *instance)
        struct MR_PD_ADDRESS *pd_addr;
        dma_addr_t ci_h = 0;
 
+       if (instance->pd_list_not_supported) {
+               dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
+               "not supported by firmware\n");
+               return ret;
+       }
+
        cmd = megasas_get_cmd(instance);
 
        if (!cmd) {
index 6bff13e7afc7b706a69ab8c99562e5f0e5ce9ddf..cd91a684c945a2c62e8c3626f6e1001c96935d35 100644 (file)
@@ -4903,13 +4903,22 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc)
        u16 ioc_status;
        u16 sz;
        u8 device_missing_delay;
+       u8 num_phys;
 
-       mpt3sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
-       if (!ioc->sas_hba.num_phys) {
+       mpt3sas_config_get_number_hba_phys(ioc, &num_phys);
+       if (!num_phys) {
                pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
                    ioc->name, __FILE__, __LINE__, __func__);
                return;
        }
+       ioc->sas_hba.phy = kcalloc(num_phys,
+           sizeof(struct _sas_phy), GFP_KERNEL);
+       if (!ioc->sas_hba.phy) {
+               pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out;
+       }
+       ioc->sas_hba.num_phys = num_phys;
 
        /* sas_iounit page 0 */
        sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
@@ -4969,13 +4978,6 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc)
                    MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
 
        ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
-       ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
-           sizeof(struct _sas_phy), GFP_KERNEL);
-       if (!ioc->sas_hba.phy) {
-               pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
-                   ioc->name, __FILE__, __LINE__, __func__);
-               goto out;
-       }
        for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
                if ((mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
                    i))) {
@@ -9033,8 +9035,11 @@ scsih_pci_mmio_enabled(struct pci_dev *pdev)
 
        /* TODO - dump whatever for debugging purposes */
 
-       /* Request a slot reset. */
-       return PCI_ERS_RESULT_NEED_RESET;
+       /* This called only if scsih_pci_error_detected returns
+        * PCI_ERS_RESULT_CAN_RECOVER. Read/write to the device still
+        * works, no need to reset slot.
+        */
+       return PCI_ERS_RESULT_RECOVERED;
 }
 
 /*
index 6a84b82d71bb333999e1fee8cc87e40a9dc80217..ff93286bc32f0ada8e034cf69d8c0d505e3640f1 100644 (file)
@@ -705,6 +705,11 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
                goto out_fail;
        }
 
+       if (!sas_node->parent_dev) {
+               pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
+                   ioc->name, __FILE__, __LINE__, __func__);
+               goto out_fail;
+       }
        port = sas_port_alloc_num(sas_node->parent_dev);
        if ((sas_port_add(port))) {
                pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
index 6bd7bf4f4a81776b01ff25652dfd4bc26014ee8d..9fc675f57e3361a3dc371e973f1d0c2ceeff065e 100644 (file)
@@ -1249,7 +1249,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
 
        /* Chip documentation for the 8070 and 8072 SPCv    */
        /* states that a 500ms minimum delay is required    */
-       /* before issuing commands.  Otherwise, the firmare */
+       /* before issuing commands. Otherwise, the firmware */
        /* will enter an unrecoverable state.               */
 
        if (pm8001_ha->chip_id == chip_8070 ||
index 4dc06a13cab879255d7f7b58dde4643ed25f5c52..fe7469c901f76ac2d46006eeb208f3c9398d3ee1 100644 (file)
@@ -146,92 +146,6 @@ static struct bin_attribute sysfs_fw_dump_attr = {
        .write = qla2x00_sysfs_write_fw_dump,
 };
 
-static ssize_t
-qla2x00_sysfs_read_fw_dump_template(struct file *filp, struct kobject *kobj,
-                          struct bin_attribute *bin_attr,
-                          char *buf, loff_t off, size_t count)
-{
-       struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
-           struct device, kobj)));
-       struct qla_hw_data *ha = vha->hw;
-
-       if (!ha->fw_dump_template || !ha->fw_dump_template_len)
-               return 0;
-
-       ql_dbg(ql_dbg_user, vha, 0x70e2,
-           "chunk <- off=%llx count=%zx\n", off, count);
-       return memory_read_from_buffer(buf, count, &off,
-           ha->fw_dump_template, ha->fw_dump_template_len);
-}
-
-static ssize_t
-qla2x00_sysfs_write_fw_dump_template(struct file *filp, struct kobject *kobj,
-                           struct bin_attribute *bin_attr,
-                           char *buf, loff_t off, size_t count)
-{
-       struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
-           struct device, kobj)));
-       struct qla_hw_data *ha = vha->hw;
-       uint32_t size;
-
-       if (off == 0) {
-               if (ha->fw_dump)
-                       vfree(ha->fw_dump);
-               if (ha->fw_dump_template)
-                       vfree(ha->fw_dump_template);
-
-               ha->fw_dump = NULL;
-               ha->fw_dump_len = 0;
-               ha->fw_dump_template = NULL;
-               ha->fw_dump_template_len = 0;
-
-               size = qla27xx_fwdt_template_size(buf);
-               ql_dbg(ql_dbg_user, vha, 0x70d1,
-                   "-> allocating fwdt (%x bytes)...\n", size);
-               ha->fw_dump_template = vmalloc(size);
-               if (!ha->fw_dump_template) {
-                       ql_log(ql_log_warn, vha, 0x70d2,
-                           "Failed allocate fwdt (%x bytes).\n", size);
-                       return -ENOMEM;
-               }
-               ha->fw_dump_template_len = size;
-       }
-
-       if (off + count > ha->fw_dump_template_len) {
-               count = ha->fw_dump_template_len - off;
-               ql_dbg(ql_dbg_user, vha, 0x70d3,
-                   "chunk -> truncating to %zx bytes.\n", count);
-       }
-
-       ql_dbg(ql_dbg_user, vha, 0x70d4,
-           "chunk -> off=%llx count=%zx\n", off, count);
-       memcpy(ha->fw_dump_template + off, buf, count);
-
-       if (off + count == ha->fw_dump_template_len) {
-               size = qla27xx_fwdt_calculate_dump_size(vha);
-               ql_dbg(ql_dbg_user, vha, 0x70d5,
-                   "-> allocating fwdump (%x bytes)...\n", size);
-               ha->fw_dump = vmalloc(size);
-               if (!ha->fw_dump) {
-                       ql_log(ql_log_warn, vha, 0x70d6,
-                           "Failed allocate fwdump (%x bytes).\n", size);
-                       return -ENOMEM;
-               }
-               ha->fw_dump_len = size;
-       }
-
-       return count;
-}
-static struct bin_attribute sysfs_fw_dump_template_attr = {
-       .attr = {
-               .name = "fw_dump_template",
-               .mode = S_IRUSR | S_IWUSR,
-       },
-       .size = 0,
-       .read = qla2x00_sysfs_read_fw_dump_template,
-       .write = qla2x00_sysfs_write_fw_dump_template,
-};
-
 static ssize_t
 qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj,
                         struct bin_attribute *bin_attr,
@@ -973,7 +887,6 @@ static struct sysfs_entry {
        int is4GBp_only;
 } bin_file_entries[] = {
        { "fw_dump", &sysfs_fw_dump_attr, },
-       { "fw_dump_template", &sysfs_fw_dump_template_attr, 0x27 },
        { "nvram", &sysfs_nvram_attr, },
        { "optrom", &sysfs_optrom_attr, },
        { "optrom_ctl", &sysfs_optrom_ctl_attr, },
@@ -1000,8 +913,6 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
                        continue;
                if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw)))
                        continue;
-               if (iter->is4GBp_only == 0x27 && !IS_QLA27XX(vha->hw))
-                       continue;
 
                ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
                    iter->attr);
@@ -1858,6 +1769,9 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
        if (!fcport)
                return;
 
+       if (test_bit(UNLOADING, &fcport->vha->dpc_flags))
+               return;
+
        if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
                return;
 
@@ -1900,10 +1814,9 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
        int rval;
        struct link_statistics *stats;
        dma_addr_t stats_dma;
-       struct fc_host_statistics *pfc_host_stat;
+       struct fc_host_statistics *p = &vha->fc_host_stat;
 
-       pfc_host_stat = &vha->fc_host_stat;
-       memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
+       memset(p, -1, sizeof(*p));
 
        if (IS_QLAFX00(vha->hw))
                goto done;
@@ -1918,17 +1831,17 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
                goto done;
 
        stats = dma_alloc_coherent(&ha->pdev->dev,
-           sizeof(struct link_statistics), &stats_dma, GFP_KERNEL);
-       if (stats == NULL) {
+           sizeof(*stats), &stats_dma, GFP_KERNEL);
+       if (!stats) {
                ql_log(ql_log_warn, vha, 0x707d,
                    "Failed to allocate memory for stats.\n");
                goto done;
        }
-       memset(stats, 0, DMA_POOL_SIZE);
+       memset(stats, 0, sizeof(*stats));
 
        rval = QLA_FUNCTION_FAILED;
        if (IS_FWI2_CAPABLE(ha)) {
-               rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma);
+               rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, 0);
        } else if (atomic_read(&base_vha->loop_state) == LOOP_READY &&
            !ha->dpc_active) {
                /* Must be in a 'READY' state for statistics retrieval. */
@@ -1939,47 +1852,68 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
        if (rval != QLA_SUCCESS)
                goto done_free;
 
-       pfc_host_stat->link_failure_count = stats->link_fail_cnt;
-       pfc_host_stat->loss_of_sync_count = stats->loss_sync_cnt;
-       pfc_host_stat->loss_of_signal_count = stats->loss_sig_cnt;
-       pfc_host_stat->prim_seq_protocol_err_count = stats->prim_seq_err_cnt;
-       pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
-       pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
+       p->link_failure_count = stats->link_fail_cnt;
+       p->loss_of_sync_count = stats->loss_sync_cnt;
+       p->loss_of_signal_count = stats->loss_sig_cnt;
+       p->prim_seq_protocol_err_count = stats->prim_seq_err_cnt;
+       p->invalid_tx_word_count = stats->inval_xmit_word_cnt;
+       p->invalid_crc_count = stats->inval_crc_cnt;
        if (IS_FWI2_CAPABLE(ha)) {
-               pfc_host_stat->lip_count = stats->lip_cnt;
-               pfc_host_stat->tx_frames = stats->tx_frames;
-               pfc_host_stat->rx_frames = stats->rx_frames;
-               pfc_host_stat->dumped_frames = stats->discarded_frames;
-               pfc_host_stat->nos_count = stats->nos_rcvd;
-               pfc_host_stat->error_frames =
+               p->lip_count = stats->lip_cnt;
+               p->tx_frames = stats->tx_frames;
+               p->rx_frames = stats->rx_frames;
+               p->dumped_frames = stats->discarded_frames;
+               p->nos_count = stats->nos_rcvd;
+               p->error_frames =
                        stats->dropped_frames + stats->discarded_frames;
-               pfc_host_stat->rx_words = vha->qla_stats.input_bytes;
-               pfc_host_stat->tx_words = vha->qla_stats.output_bytes;
+               p->rx_words = vha->qla_stats.input_bytes;
+               p->tx_words = vha->qla_stats.output_bytes;
        }
-       pfc_host_stat->fcp_control_requests = vha->qla_stats.control_requests;
-       pfc_host_stat->fcp_input_requests = vha->qla_stats.input_requests;
-       pfc_host_stat->fcp_output_requests = vha->qla_stats.output_requests;
-       pfc_host_stat->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20;
-       pfc_host_stat->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20;
-       pfc_host_stat->seconds_since_last_reset =
+       p->fcp_control_requests = vha->qla_stats.control_requests;
+       p->fcp_input_requests = vha->qla_stats.input_requests;
+       p->fcp_output_requests = vha->qla_stats.output_requests;
+       p->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20;
+       p->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20;
+       p->seconds_since_last_reset =
                get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset;
-       do_div(pfc_host_stat->seconds_since_last_reset, HZ);
+       do_div(p->seconds_since_last_reset, HZ);
 
 done_free:
        dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics),
            stats, stats_dma);
 done:
-       return pfc_host_stat;
+       return p;
 }
 
 static void
 qla2x00_reset_host_stats(struct Scsi_Host *shost)
 {
        scsi_qla_host_t *vha = shost_priv(shost);
+       struct qla_hw_data *ha = vha->hw;
+       struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
+       struct link_statistics *stats;
+       dma_addr_t stats_dma;
 
+       memset(&vha->qla_stats, 0, sizeof(vha->qla_stats));
        memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
 
        vha->qla_stats.jiffies_at_last_reset = get_jiffies_64();
+
+       if (IS_FWI2_CAPABLE(ha)) {
+               stats = dma_alloc_coherent(&ha->pdev->dev,
+                   sizeof(*stats), &stats_dma, GFP_KERNEL);
+               if (!stats) {
+                       ql_log(ql_log_warn, vha, 0x70d7,
+                           "Failed to allocate memory for stats.\n");
+                       return;
+               }
+
+               /* reset firmware statistics */
+               qla24xx_get_isp_stats(base_vha, stats, stats_dma, BIT_0);
+
+               dma_free_coherent(&ha->pdev->dev, sizeof(*stats),
+                   stats, stats_dma);
+       }
 }
 
 static void
index 392c147d5793e4345d06b78c698b63cc9251282f..643014f82f7d82d0a314581e4a9ef10d6a56eea6 100644 (file)
@@ -2246,53 +2246,94 @@ qla2x00_get_priv_stats(struct fc_bsg_job *bsg_job)
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
        struct link_statistics *stats = NULL;
        dma_addr_t stats_dma;
-       int rval = QLA_FUNCTION_FAILED;
+       int rval;
+       uint32_t *cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd;
+       uint options = cmd[0] == QL_VND_GET_PRIV_STATS_EX ? cmd[1] : 0;
 
        if (test_bit(UNLOADING, &vha->dpc_flags))
-               goto done;
+               return -ENODEV;
 
        if (unlikely(pci_channel_offline(ha->pdev)))
-               goto done;
+               return -ENODEV;
 
        if (qla2x00_reset_active(vha))
-               goto done;
+               return -EBUSY;
 
        if (!IS_FWI2_CAPABLE(ha))
-               goto done;
+               return -EPERM;
 
        stats = dma_alloc_coherent(&ha->pdev->dev,
-               sizeof(struct link_statistics), &stats_dma, GFP_KERNEL);
+               sizeof(*stats), &stats_dma, GFP_KERNEL);
        if (!stats) {
                ql_log(ql_log_warn, vha, 0x70e2,
-               "Failed to allocate memory for stats.\n");
-               goto done;
+                   "Failed to allocate memory for stats.\n");
+               return -ENOMEM;
        }
 
-       memset(stats, 0, sizeof(struct link_statistics));
+       memset(stats, 0, sizeof(*stats));
 
-       rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma);
+       rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, options);
 
-       if (rval != QLA_SUCCESS)
-               goto done_free;
+       if (rval == QLA_SUCCESS) {
+               ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3,
+                   (uint8_t *)stats, sizeof(*stats));
+               sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+                       bsg_job->reply_payload.sg_cnt, stats, sizeof(*stats));
+       }
 
-       ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3,
-           (uint8_t *)stats, sizeof(struct link_statistics));
+       bsg_job->reply->reply_payload_rcv_len = sizeof(*stats);
+       bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+           rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK;
 
-       sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
-       bsg_job->reply_payload.sg_cnt, stats, sizeof(struct link_statistics));
-       bsg_job->reply->reply_payload_rcv_len = sizeof(struct link_statistics);
+       bsg_job->reply_len = sizeof(*bsg_job->reply);
+       bsg_job->reply->result = DID_OK << 16;
+       bsg_job->job_done(bsg_job);
 
-       bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+       dma_free_coherent(&ha->pdev->dev, sizeof(*stats),
+               stats, stats_dma);
 
-       bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+       return 0;
+}
+
+static int
+qla2x00_do_dport_diagnostics(struct fc_bsg_job *bsg_job)
+{
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       int rval;
+       struct qla_dport_diag *dd;
+
+       if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw))
+               return -EPERM;
+
+       dd = kmalloc(sizeof(*dd), GFP_KERNEL);
+       if (!dd) {
+               ql_log(ql_log_warn, vha, 0x70db,
+                   "Failed to allocate memory for dport.\n");
+               return -ENOMEM;
+       }
+
+       sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+           bsg_job->request_payload.sg_cnt, dd, sizeof(*dd));
+
+       rval = qla26xx_dport_diagnostics(
+           vha, dd->buf, sizeof(dd->buf), dd->options);
+       if (rval == QLA_SUCCESS) {
+               sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+                   bsg_job->reply_payload.sg_cnt, dd, sizeof(*dd));
+       }
+
+       bsg_job->reply->reply_payload_rcv_len = sizeof(*dd);
+       bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] =
+           rval ? EXT_STATUS_MAILBOX : EXT_STATUS_OK;
+
+       bsg_job->reply_len = sizeof(*bsg_job->reply);
        bsg_job->reply->result = DID_OK << 16;
        bsg_job->job_done(bsg_job);
 
-done_free:
-       dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics),
-               stats, stats_dma);
-done:
-       return rval;
+       kfree(dd);
+
+       return 0;
 }
 
 static int
@@ -2360,8 +2401,12 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
                return qla27xx_get_bbcr_data(bsg_job);
 
        case QL_VND_GET_PRIV_STATS:
+       case QL_VND_GET_PRIV_STATS_EX:
                return qla2x00_get_priv_stats(bsg_job);
 
+       case QL_VND_DPORT_DIAGNOSTICS:
+               return qla2x00_do_dport_diagnostics(bsg_job);
+
        default:
                return -ENOSYS;
        }
index c80192d45536286b695fe067fb41351461c138ce..d97dfd52135637679a4a04f58c95bd83ff3dd90e 100644 (file)
@@ -29,6 +29,8 @@
 #define QL_VND_SET_FLASH_UPDATE_CAPS    0x16
 #define QL_VND_GET_BBCR_DATA    0x17
 #define QL_VND_GET_PRIV_STATS  0x18
+#define QL_VND_DPORT_DIAGNOSTICS       0x19
+#define QL_VND_GET_PRIV_STATS_EX       0x1A
 
 /* BSG Vendor specific subcode returns */
 #define EXT_STATUS_OK                  0
@@ -266,4 +268,15 @@ struct  qla_bbcr_data {
        uint16_t  mbx1;                 /* Port state */
        uint8_t   reserved[9];
 } __packed;
+
+struct qla_dport_diag {
+       uint16_t options;
+       uint32_t buf[16];
+       uint8_t  unused[62];
+} __packed;
+
+/* D_Port options */
+#define QLA_DPORT_RESULT       0x0
+#define QLA_DPORT_START                0x2
+
 #endif
index b64c504ff12fa2dc5657ce68297cb59dda0f27e8..45af34ddc43297d06c8c7cf44425a1a7cee4cc7f 100644 (file)
  * ----------------------------------------------------------------------
  * |             Level            |   Last Value Used  |     Holes     |
  * ----------------------------------------------------------------------
- * | Module Init and Probe        |       0x018f       | 0x0146         |
+ * | Module Init and Probe        |       0x0191       | 0x0146         |
  * |                              |                    | 0x015b-0x0160 |
- * |                              |                    | 0x016e-0x0170  |
- * | Mailbox commands             |       0x1192       |               |
- * |                              |                    |               |
- * | Device Discovery             |       0x2016       | 0x2020-0x2022, |
+ * |                              |                    | 0x016e                |
+ * | Mailbox commands             |       0x1199       | 0x1193                |
+ * | Device Discovery             |       0x2004       | 0x2016                |
  * |                              |                    | 0x2011-0x2012, |
  * |                              |                    | 0x2099-0x20a4  |
  * | Queue Command and IO tracing |       0x3074       | 0x300b         |
  * |                              |                    | 0x3036,0x3038  |
  * |                              |                    | 0x303a                |
  * | DPC Thread                   |       0x4023       | 0x4002,0x4013  |
- * | Async Events                 |       0x5089       | 0x502b-0x502f  |
- * |                              |                    | 0x505e         |
+ * | Async Events                 |       0x5090       | 0x502b-0x502f  |
+ * |                             |                    | 0x5047         |
  * |                              |                    | 0x5084,0x5075 |
  * |                              |                    | 0x503d,0x5044  |
- * |                              |                    | 0x507b,0x505f |
+ * |                              |                    | 0x505f                |
  * | Timer Routines               |       0x6012       |                |
  * | User Space Interactions      |       0x70e3       | 0x7018,0x702e  |
  * |                             |                    | 0x7020,0x7024  |
@@ -39,9 +38,9 @@
  * |                              |                    | 0x70a5-0x70a6  |
  * |                              |                    | 0x70a8,0x70ab  |
  * |                              |                    | 0x70ad-0x70ae  |
+ * |                              |                    | 0x70d0-0x70d6 |
  * |                              |                    | 0x70d7-0x70db  |
- * |                              |                    | 0x70de-0x70df  |
- * | Task Management              |       0x803d       | 0x8000,0x800b  |
+ * | Task Management              |       0x8042       | 0x8000,0x800b  |
  * |                              |                    | 0x8019         |
  * |                              |                    | 0x8025,0x8026  |
  * |                              |                    | 0x8031,0x8032  |
@@ -2697,29 +2696,24 @@ ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id)
 
 void
 ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id,
-       uint8_t *b, uint32_t size)
+       uint8_t *buf, uint size)
 {
-       uint32_t cnt;
-       uint8_t c;
+       uint cnt;
 
        if (!ql_mask_match(level))
                return;
 
-       ql_dbg(level, vha, id, " 0   1   2   3   4   5   6   7   8   "
-           "9  Ah  Bh  Ch  Dh  Eh  Fh\n");
-       ql_dbg(level, vha, id, "----------------------------------"
-           "----------------------------\n");
-
-       ql_dbg(level, vha, id, " ");
-       for (cnt = 0; cnt < size;) {
-               c = *b++;
-               printk("%02x", (uint32_t) c);
-               cnt++;
-               if (!(cnt % 16))
+       ql_dbg(level, vha, id,
+           "%-+5d  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F\n", size);
+       ql_dbg(level, vha, id,
+           "----- -----------------------------------------------\n");
+       for (cnt = 0; cnt < size; cnt++, buf++) {
+               if (cnt % 16 == 0)
+                       ql_dbg(level, vha, id, "%04x:", cnt & ~0xFU);
+               printk(" %02x", *buf);
+               if (cnt % 16 == 15)
                        printk("\n");
-               else
-                       printk("  ");
        }
-       if (cnt % 16)
-               ql_dbg(level, vha, id, "\n");
+       if (cnt % 16 != 0)
+               printk("\n");
 }
index 47f8b9b49bac310335eb9ab9deebbf6997394873..ae4a747561282e9e6045995afb7024002d72670c 100644 (file)
@@ -829,6 +829,7 @@ struct mbx_cmd_32 {
 #define MBA_FW_RESTART_CMPLT   0x8060  /* Firmware restart complete */
 #define MBA_INIT_REQUIRED      0x8061  /* Initialization required */
 #define MBA_SHUTDOWN_REQUESTED 0x8062  /* Shutdown Requested */
+#define MBA_TEMPERATURE_ALERT  0x8070  /* Temperature Alert */
 #define MBA_DPORT_DIAGNOSTICS  0x8080  /* D-port Diagnostics */
 #define MBA_FW_INIT_FAILURE    0x8401  /* Firmware initialization failure */
 #define MBA_MIRROR_LUN_CHANGE  0x8402  /* Mirror LUN State Change
@@ -3028,6 +3029,7 @@ struct qla_hw_data {
                uint32_t        mr_reset_hdlr_active:1;
                uint32_t        mr_intr_valid:1;
 
+               uint32_t        dport_enabled:1;
                uint32_t        fawwpn_enabled:1;
                uint32_t        exlogins_enabled:1;
                uint32_t        exchoffld_enabled:1;
@@ -3128,7 +3130,7 @@ struct qla_hw_data {
 #define PCI_DEVICE_ID_QLOGIC_ISP2271   0x2271
 #define PCI_DEVICE_ID_QLOGIC_ISP2261   0x2261
 
-       uint32_t        device_type;
+       uint32_t        isp_type;
 #define DT_ISP2100                      BIT_0
 #define DT_ISP2200                      BIT_1
 #define DT_ISP2300                      BIT_2
@@ -3153,6 +3155,7 @@ struct qla_hw_data {
 #define DT_ISP2261                     BIT_21
 #define DT_ISP_LAST                    (DT_ISP2261 << 1)
 
+       uint32_t        device_type;
 #define DT_T10_PI                       BIT_25
 #define DT_IIDMA                        BIT_26
 #define DT_FWI2                         BIT_27
@@ -3160,7 +3163,8 @@ struct qla_hw_data {
 #define DT_OEM_001                      BIT_29
 #define DT_ISP2200A                     BIT_30
 #define DT_EXTENDED_IDS                 BIT_31
-#define DT_MASK(ha)     ((ha)->device_type & (DT_ISP_LAST - 1))
+
+#define DT_MASK(ha)     ((ha)->isp_type & (DT_ISP_LAST - 1))
 #define IS_QLA2100(ha)  (DT_MASK(ha) & DT_ISP2100)
 #define IS_QLA2200(ha)  (DT_MASK(ha) & DT_ISP2200)
 #define IS_QLA2300(ha)  (DT_MASK(ha) & DT_ISP2300)
@@ -3370,6 +3374,8 @@ struct qla_hw_data {
 
        uint32_t        fw_shared_ram_start;
        uint32_t        fw_shared_ram_end;
+       uint32_t        fw_ddr_ram_start;
+       uint32_t        fw_ddr_ram_end;
 
        uint16_t        fw_options[16];         /* slots: 1,2,3,10,11 */
        uint8_t         fw_seriallink_options[4];
@@ -3505,7 +3511,6 @@ struct qla_hw_data {
        int             cur_vport_count;
 
        struct qla_chip_state_84xx *cs84xx;
-       struct qla_statistics qla_stats;
        struct isp_operations *isp_ops;
        struct workqueue_struct *wq;
        struct qlfc_fw fw_buf;
@@ -3656,6 +3661,7 @@ typedef struct scsi_qla_host {
 #define PFLG_DISCONNECTED      0       /* PCI device removed */
 #define PFLG_DRIVER_REMOVING   1       /* PCI driver .remove */
 #define PFLG_DRIVER_PROBING    2       /* PCI driver .probe */
+#define PCI_ERR                        30
 
        uint32_t        device_flags;
 #define SWITCH_FOUND           BIT_0
index 4c0f3a774799d1f4da454975c5eb92bb6b116282..8a2368b32dece20d048ca2e90115306642f7f755 100644 (file)
@@ -1288,7 +1288,7 @@ struct vp_rpt_id_entry_24xx {
 
        uint8_t vp_idx_map[16];
 
-       uint8_t reserved_4[28];
+       uint8_t reserved_4[24];
        uint16_t bbcr;
        uint8_t reserved_5[6];
 };
index fe943772fe7beed0cd49f19a742e11a04f6d91df..6ca00813c71f0702a49965d97c6240c6b3657307 100644 (file)
@@ -344,7 +344,7 @@ qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, struct link_statistics *,
 
 extern int
 qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
-    dma_addr_t);
+    dma_addr_t, uint);
 
 extern int qla24xx_abort_command(srb_t *);
 extern int qla24xx_async_abort_command(srb_t *);
@@ -445,6 +445,9 @@ qla2x00_port_logout(scsi_qla_host_t *, struct fc_port *);
 extern int
 qla2x00_dump_mctp_data(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
 
+extern int
+qla26xx_dport_diagnostics(scsi_qla_host_t *, void *, uint, uint);
+
 /*
  * Global Function Prototypes in qla_isr.c source file.
  */
index c56cdb35f3edb8b7b33b38061ae2c40af0a8b2ea..5b09296b46a3058f9c938990274d158b508af884 100644 (file)
@@ -624,6 +624,9 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
 
+       memset(&vha->qla_stats, 0, sizeof(vha->qla_stats));
+       memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
+
        /* Clear adapter flags. */
        vha->flags.online = 0;
        ha->flags.chip_reset_done = 0;
@@ -2053,6 +2056,14 @@ qla2x00_update_fw_options(scsi_qla_host_t *vha)
        if (IS_QLA6312(ha))
                ha->fw_options[2] |= BIT_13;
 
+       /* Set Retry FLOGI in case of P2P connection */
+       if (ha->operating_mode == P2P) {
+               ha->fw_options[2] |= BIT_3;
+               ql_dbg(ql_dbg_disc, vha, 0x2100,
+                   "(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n",
+                       __func__, ha->fw_options[2]);
+       }
+
        /* Update firmware options. */
        qla2x00_set_fw_options(vha, ha->fw_options);
 }
@@ -2070,6 +2081,14 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
        if (ql2xfwholdabts)
                ha->fw_options[3] |= BIT_12;
 
+       /* Set Retry FLOGI in case of P2P connection */
+       if (ha->operating_mode == P2P) {
+               ha->fw_options[2] |= BIT_3;
+               ql_dbg(ql_dbg_disc, vha, 0x2101,
+                   "(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n",
+                       __func__, ha->fw_options[2]);
+       }
+
        /* Update Serial Link options. */
        if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
                return;
@@ -2269,13 +2288,13 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
                mid_init_cb->options = cpu_to_le16(BIT_1);
                mid_init_cb->init_cb.execution_throttle =
                    cpu_to_le16(ha->cur_fw_xcb_count);
-               /* D-Port Status */
-               if (IS_DPORT_CAPABLE(ha))
-                       mid_init_cb->init_cb.firmware_options_1 |=
-                           cpu_to_le16(BIT_7);
-               /* Enable FA-WWPN */
+               ha->flags.dport_enabled =
+                   (mid_init_cb->init_cb.firmware_options_1 & BIT_7) != 0;
+               ql_dbg(ql_dbg_init, vha, 0x0191, "DPORT Support: %s.\n",
+                   (ha->flags.dport_enabled) ? "enabled" : "disabled");
+               /* FA-WWPN Status */
                ha->flags.fawwpn_enabled =
-                   (mid_init_cb->init_cb.firmware_options_1 & BIT_6) ? 1 : 0;
+                   (mid_init_cb->init_cb.firmware_options_1 & BIT_6) != 0;
                ql_dbg(ql_dbg_init, vha, 0x0141, "FA-WWPN Support: %s.\n",
                    (ha->flags.fawwpn_enabled) ? "enabled" : "disabled");
        }
@@ -6513,6 +6532,14 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha)
        if (ql2xfwholdabts)
                ha->fw_options[3] |= BIT_12;
 
+       /* Set Retry FLOGI in case of P2P connection */
+       if (ha->operating_mode == P2P) {
+               ha->fw_options[2] |= BIT_3;
+               ql_dbg(ql_dbg_disc, vha, 0x2103,
+                   "(%s): Setting FLOGI retry BIT in fw_options[2]: 0x%x\n",
+                       __func__, ha->fw_options[2]);
+       }
+
        if (!ql2xetsenable)
                goto out;
 
index a92a62dea7934429e48c252f77405a8dd70b6400..987f1c729e9cd588c13219269b11d84d2ca6f183 100644 (file)
@@ -710,16 +710,23 @@ skip_rio:
 
        case MBA_RSP_TRANSFER_ERR:      /* Response Transfer Error */
                ql_log(ql_log_warn, vha, 0x5007,
-                   "ISP Response Transfer Error.\n");
+                   "ISP Response Transfer Error (%x).\n", mb[1]);
 
                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_WAKEUP_THRES:          /* Request Queue Wake-up */
                ql_dbg(ql_dbg_async, vha, 0x5008,
-                   "Asynchronous WAKEUP_THRES.\n");
+                   "Asynchronous WAKEUP_THRES (%x).\n", mb[1]);
+               break;
 
+       case MBA_LOOP_INIT_ERR:
+               ql_log(ql_log_warn, vha, 0x5090,
+                   "LOOP INIT ERROR (%x).\n", mb[1]);
+               ha->isp_ops->fw_dump(vha, 1);
+               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
+
        case MBA_LIP_OCCURRED:          /* Loop Initialization Procedure */
                ql_dbg(ql_dbg_async, vha, 0x5009,
                    "LIP occurred (%x).\n", mb[1]);
@@ -1152,12 +1159,20 @@ global_port_update:
 
        case MBA_DPORT_DIAGNOSTICS:
                ql_dbg(ql_dbg_async, vha, 0x5052,
-                   "D-Port Diagnostics: %04x %04x=%s\n", mb[0], mb[1],
+                   "D-Port Diagnostics: %04x result=%s\n",
+                   mb[0],
                    mb[1] == 0 ? "start" :
-                   mb[1] == 1 ? "done (ok)" :
+                   mb[1] == 1 ? "done (pass)" :
                    mb[1] == 2 ? "done (error)" : "other");
                break;
 
+       case MBA_TEMPERATURE_ALERT:
+               ql_dbg(ql_dbg_async, vha, 0x505e,
+                   "TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]);
+               if (mb[1] == 0x12)
+                       schedule_work(&ha->board_disable);
+               break;
+
        default:
                ql_dbg(ql_dbg_async, vha, 0x5057,
                    "Unknown AEN:%04x %04x %04x %04x\n",
@@ -3086,6 +3101,8 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
        /* Enable MSI-X vectors for the base queue */
        for (i = 0; i < 2; i++) {
                qentry = &ha->msix_entries[i];
+               qentry->rsp = rsp;
+               rsp->msix = qentry;
                if (IS_P3P_TYPE(ha))
                        ret = request_irq(qentry->vector,
                                qla82xx_msix_entries[i].handler,
@@ -3097,8 +3114,6 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
                if (ret)
                        goto msix_register_fail;
                qentry->have_irq = 1;
-               qentry->rsp = rsp;
-               rsp->msix = qentry;
 
                /* Register for CPU affinity notification. */
                irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify);
@@ -3119,12 +3134,12 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
         */
        if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
                qentry = &ha->msix_entries[ATIO_VECTOR];
+               qentry->rsp = rsp;
+               rsp->msix = qentry;
                ret = request_irq(qentry->vector,
                        qla83xx_msix_entries[ATIO_VECTOR].handler,
                        0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp);
                qentry->have_irq = 1;
-               qentry->rsp = rsp;
-               rsp->msix = qentry;
        }
 
 msix_register_fail:
index 968b846130965a5ba77522c6d048988f0a4c291e..23698c9986998a0a7279e6e256d4c377f6fceab9 100644 (file)
@@ -64,6 +64,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                return QLA_FUNCTION_TIMEOUT;
        }
 
+        /* if PCI error, then avoid mbx processing.*/
+        if (test_bit(PCI_ERR, &base_vha->dpc_flags)) {
+               ql_log(ql_log_warn, vha, 0x1191,
+                   "PCI error, exiting.\n");
+               return QLA_FUNCTION_TIMEOUT;
+        }
+
        reg = ha->iobase;
        io_lock_on = base_vha->flags.init_done;
 
@@ -266,6 +273,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 
                uint16_t mb0;
                uint32_t ictrl;
+               uint16_t        w;
 
                if (IS_FWI2_CAPABLE(ha)) {
                        mb0 = RD_REG_WORD(&reg->isp24.mailbox0);
@@ -279,15 +287,32 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                    "mb[0]=0x%x\n", command, ictrl, jiffies, mb0);
                ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019);
 
-               /*
-                * Attempt to capture a firmware dump for further analysis
-                * of the current firmware state.  We do not need to do this
-                * if we are intentionally generating a dump.
-                */
-               if (mcp->mb[0] != MBC_GEN_SYSTEM_ERROR)
-                       ha->isp_ops->fw_dump(vha, 0);
+               /* Capture FW dump only, if PCI device active */
+               if (!pci_channel_offline(vha->hw->pdev)) {
+                       pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
+                       if (w == 0xffff || ictrl == 0xffffffff) {
+                               /* This is special case if there is unload
+                                * of driver happening and if PCI device go
+                                * into bad state due to PCI error condition
+                                * then only PCI ERR flag would be set.
+                                * we will do premature exit for above case.
+                                */
+                               if (test_bit(UNLOADING, &base_vha->dpc_flags))
+                                       set_bit(PCI_ERR, &base_vha->dpc_flags);
+                               ha->flags.mbox_busy = 0;
+                               rval = QLA_FUNCTION_TIMEOUT;
+                               goto premature_exit;
+                       }
 
-               rval = QLA_FUNCTION_TIMEOUT;
+                       /* Attempt to capture firmware dump for further
+                        * anallysis of the current formware state. we do not
+                        * need to do this if we are intentionally generating
+                        * a dump
+                        */
+                       if (mcp->mb[0] != MBC_GEN_SYSTEM_ERROR)
+                               ha->isp_ops->fw_dump(vha, 0);
+                       rval = QLA_FUNCTION_TIMEOUT;
+                }
        }
 
        ha->flags.mbox_busy = 0;
@@ -379,7 +404,7 @@ mbx_done:
                    "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n",
                    mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], command);
 
-               ql_dbg(ql_dbg_disc, vha, 0x1115,
+               ql_dbg(ql_dbg_mbx, vha, 0x1198,
                    "host status: 0x%x, flags:0x%lx, intr ctrl reg:0x%x, intr status:0x%x\n",
                    RD_REG_DWORD(&reg->isp24.host_status),
                    ha->fw_dump_cap_flags,
@@ -388,7 +413,7 @@ mbx_done:
 
                mbx_reg = &reg->isp24.mailbox0;
                for (i = 0; i < 6; i++)
-                       ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x1116,
+                       ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1199,
                            "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++));
        } else {
                ql_dbg(ql_dbg_mbx, base_vha, 0x1021, "Done %s.\n", __func__);
@@ -782,8 +807,9 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
        if (IS_FWI2_CAPABLE(ha))
                mcp->in_mb |= MBX_17|MBX_16|MBX_15;
        if (IS_QLA27XX(ha))
-               mcp->in_mb |= MBX_23 | MBX_22 | MBX_21 | MBX_20 | MBX_19 |
-                   MBX_18 | MBX_14 | MBX_13 | MBX_11 | MBX_10 | MBX_9 | MBX_8;
+               mcp->in_mb |=
+                   MBX_25|MBX_24|MBX_23|MBX_22|MBX_21|MBX_20|MBX_19|MBX_18|
+                   MBX_14|MBX_13|MBX_11|MBX_10|MBX_9|MBX_8;
 
        mcp->flags = 0;
        mcp->tov = MBX_TOV_SECONDS;
@@ -842,6 +868,8 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
                ha->pep_version[2] = mcp->mb[14] & 0xff;
                ha->fw_shared_ram_start = (mcp->mb[19] << 16) | mcp->mb[18];
                ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20];
+               ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22];
+               ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24];
        }
 
 failed:
@@ -1844,7 +1872,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
        states[0] = mcp->mb[1];
        if (IS_FWI2_CAPABLE(vha->hw)) {
                states[1] = mcp->mb[2];
-               states[2] = mcp->mb[3];
+               states[2] = mcp->mb[3];  /* SFP info */
                states[3] = mcp->mb[4];
                states[4] = mcp->mb[5];
                states[5] = mcp->mb[6];  /* DPORT status */
@@ -2759,15 +2787,16 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
-       uint32_t *iter, dwords;
+       uint32_t *iter = (void *)stats;
+       ushort dwords = offsetof(typeof(*stats), link_up_cnt)/sizeof(*iter);
        struct qla_hw_data *ha = vha->hw;
 
        ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1084,
            "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_LINK_STATUS;
-       mcp->mb[2] = MSW(stats_dma);
-       mcp->mb[3] = LSW(stats_dma);
+       mcp->mb[2] = MSW(LSD(stats_dma));
+       mcp->mb[3] = LSW(LSD(stats_dma));
        mcp->mb[6] = MSW(MSD(stats_dma));
        mcp->mb[7] = LSW(MSD(stats_dma));
        mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
@@ -2796,12 +2825,9 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
                            "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
                        rval = QLA_FUNCTION_FAILED;
                } else {
-                       /* Copy over data -- firmware data is LE. */
+                       /* Re-endianize - firmware data is le32. */
                        ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1086,
                            "Done %s.\n", __func__);
-                       dwords = offsetof(struct link_statistics,
-                                       link_up_cnt) / 4;
-                       iter = &stats->link_fail_cnt;
                        for ( ; dwords--; iter++)
                                le32_to_cpus(iter);
                }
@@ -2815,7 +2841,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
 
 int
 qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
-    dma_addr_t stats_dma)
+    dma_addr_t stats_dma, uint options)
 {
        int rval;
        mbx_cmd_t mc;
@@ -2832,7 +2858,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
        mcp->mb[7] = LSW(MSD(stats_dma));
        mcp->mb[8] = sizeof(struct link_statistics) / 4;
        mcp->mb[9] = vha->vp_idx;
-       mcp->mb[10] = 0;
+       mcp->mb[10] = options;
        mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
        mcp->in_mb = MBX_2|MBX_1|MBX_0;
        mcp->tov = MBX_TOV_SECONDS;
@@ -2847,7 +2873,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
                } else {
                        ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108a,
                            "Done %s.\n", __func__);
-                       /* Copy over data -- firmware data is LE. */
+                       /* Re-endianize - firmware data is le32. */
                        dwords = sizeof(struct link_statistics) / 4;
                        iter = &stats->link_fail_cnt;
                        for ( ; dwords--; iter++)
@@ -5722,3 +5748,54 @@ qla2x00_dump_mctp_data(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr,
 
        return rval;
 }
+
+int
+qla26xx_dport_diagnostics(scsi_qla_host_t *vha,
+       void *dd_buf, uint size, uint options)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+       dma_addr_t dd_dma;
+
+       if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw))
+               return QLA_FUNCTION_FAILED;
+
+       ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1192,
+           "Entered %s.\n", __func__);
+
+       dd_dma = dma_map_single(&vha->hw->pdev->dev,
+           dd_buf, size, DMA_FROM_DEVICE);
+       if (!dd_dma) {
+               ql_log(ql_log_warn, vha, 0x1194, "Failed to map dma buffer.\n");
+               return QLA_MEMORY_ALLOC_FAILED;
+       }
+
+       memset(dd_buf, 0, size);
+
+       mcp->mb[0] = MBC_DPORT_DIAGNOSTICS;
+       mcp->mb[1] = options;
+       mcp->mb[2] = MSW(LSD(dd_dma));
+       mcp->mb[3] = LSW(LSD(dd_dma));
+       mcp->mb[6] = MSW(MSD(dd_dma));
+       mcp->mb[7] = LSW(MSD(dd_dma));
+       mcp->mb[8] = size;
+       mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->buf_size = size;
+       mcp->flags = MBX_DMA_IN;
+       mcp->tov = MBX_TOV_SECONDS * 4;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_mbx, vha, 0x1195, "Failed=%x.\n", rval);
+       } else {
+               ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1196,
+                   "Done %s.\n", __func__);
+       }
+
+       dma_unmap_single(&vha->hw->pdev->dev, dd_dma,
+           size, DMA_FROM_DEVICE);
+
+       return rval;
+}
index 7c0b60ca158f82724c4809a2e986f174df75fc36..2674f4c16bc319da17b016783aa5ef10d7c914bb 100644 (file)
@@ -80,6 +80,7 @@ MODULE_PARM_DESC(ql2xallocfwdump,
 
 int ql2xextended_error_logging;
 module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
+module_param_named(logging, ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xextended_error_logging,
                "Option to enable extended error logging,\n"
                "\t\tDefault is 0 - no logging.  0x40000000 - Module Init & Probe.\n"
@@ -106,6 +107,7 @@ MODULE_PARM_DESC(ql2xshiftctondsd,
 
 int ql2xfdmienable=1;
 module_param(ql2xfdmienable, int, S_IRUGO|S_IWUSR);
+module_param_named(fdmi, ql2xfdmienable, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xfdmienable,
                "Enables FDMI registrations. "
                "0 - no FDMI. Default is 1 - perform FDMI.");
@@ -157,6 +159,7 @@ MODULE_PARM_DESC(ql2xmultique_tag,
 
 int ql2xfwloadbin;
 module_param(ql2xfwloadbin, int, S_IRUGO|S_IWUSR);
+module_param_named(fwload, ql2xfwloadbin, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xfwloadbin,
                "Option to specify location from which to load ISP firmware:.\n"
                " 2 -- load firmware via the request_firmware() (hotplug).\n"
@@ -894,12 +897,16 @@ static void
 qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha)
 {
        struct qla_hw_data *ha = vha->hw;
+       scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
        while (((qla2x00_reset_active(vha)) || ha->dpc_active ||
            ha->flags.mbox_busy) ||
                test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) ||
-               test_bit(FX00_TARGET_SCAN, &vha->dpc_flags))
+               test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) {
+                       if (test_bit(UNLOADING, &base_vha->dpc_flags))
+                               break;
                msleep(1000);
+       }
 }
 
 int
@@ -936,6 +943,30 @@ sp_get(struct srb *sp)
        atomic_inc(&sp->ref_count);
 }
 
+#define ISP_REG_DISCONNECT 0xffffffffU
+/**************************************************************************
+* qla2x00_isp_reg_stat
+*
+* Description:
+*      Read the host status register of ISP before aborting the command.
+*
+* Input:
+*      ha = pointer to host adapter structure.
+*
+*
+* Returns:
+*      Either true or false.
+*
+* Note:        Return true if there is register disconnect.
+**************************************************************************/
+static inline
+uint32_t qla2x00_isp_reg_stat(struct qla_hw_data *ha)
+{
+       struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+       return ((RD_REG_DWORD(&reg->host_status)) == ISP_REG_DISCONNECT);
+}
+
 /**************************************************************************
 * qla2xxx_eh_abort
 *
@@ -963,6 +994,11 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        int rval, wait = 0;
        struct qla_hw_data *ha = vha->hw;
 
+       if (qla2x00_isp_reg_stat(ha)) {
+               ql_log(ql_log_info, vha, 0x8042,
+                   "PCI/Register disconnect, exiting.\n");
+               return FAILED;
+       }
        if (!CMD_SP(cmd))
                return SUCCESS;
 
@@ -1146,6 +1182,12 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
        scsi_qla_host_t *vha = shost_priv(cmd->device->host);
        struct qla_hw_data *ha = vha->hw;
 
+       if (qla2x00_isp_reg_stat(ha)) {
+               ql_log(ql_log_info, vha, 0x803e,
+                   "PCI/Register disconnect, exiting.\n");
+               return FAILED;
+       }
+
        return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd,
            ha->isp_ops->lun_reset);
 }
@@ -1156,6 +1198,12 @@ qla2xxx_eh_target_reset(struct scsi_cmnd *cmd)
        scsi_qla_host_t *vha = shost_priv(cmd->device->host);
        struct qla_hw_data *ha = vha->hw;
 
+       if (qla2x00_isp_reg_stat(ha)) {
+               ql_log(ql_log_info, vha, 0x803f,
+                   "PCI/Register disconnect, exiting.\n");
+               return FAILED;
+       }
+
        return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd,
            ha->isp_ops->target_reset);
 }
@@ -1183,6 +1231,13 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
        int ret = FAILED;
        unsigned int id;
        uint64_t lun;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (qla2x00_isp_reg_stat(ha)) {
+               ql_log(ql_log_info, vha, 0x8040,
+                   "PCI/Register disconnect, exiting.\n");
+               return FAILED;
+       }
 
        id = cmd->device->id;
        lun = cmd->device->lun;
@@ -1252,6 +1307,13 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
        uint64_t lun;
        scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
+       if (qla2x00_isp_reg_stat(ha)) {
+               ql_log(ql_log_info, vha, 0x8041,
+                   "PCI/Register disconnect, exiting.\n");
+               schedule_work(&ha->board_disable);
+               return SUCCESS;
+       }
+
        id = cmd->device->id;
        lun = cmd->device->lun;
 
@@ -2103,27 +2165,27 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
        ha->device_type = DT_EXTENDED_IDS;
        switch (ha->pdev->device) {
        case PCI_DEVICE_ID_QLOGIC_ISP2100:
-               ha->device_type |= DT_ISP2100;
+               ha->isp_type |= DT_ISP2100;
                ha->device_type &= ~DT_EXTENDED_IDS;
                ha->fw_srisc_address = RISC_START_ADDRESS_2100;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2200:
-               ha->device_type |= DT_ISP2200;
+               ha->isp_type |= DT_ISP2200;
                ha->device_type &= ~DT_EXTENDED_IDS;
                ha->fw_srisc_address = RISC_START_ADDRESS_2100;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2300:
-               ha->device_type |= DT_ISP2300;
+               ha->isp_type |= DT_ISP2300;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->fw_srisc_address = RISC_START_ADDRESS_2300;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2312:
-               ha->device_type |= DT_ISP2312;
+               ha->isp_type |= DT_ISP2312;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->fw_srisc_address = RISC_START_ADDRESS_2300;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2322:
-               ha->device_type |= DT_ISP2322;
+               ha->isp_type |= DT_ISP2322;
                ha->device_type |= DT_ZIO_SUPPORTED;
                if (ha->pdev->subsystem_vendor == 0x1028 &&
                    ha->pdev->subsystem_device == 0x0170)
@@ -2131,60 +2193,60 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                ha->fw_srisc_address = RISC_START_ADDRESS_2300;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP6312:
-               ha->device_type |= DT_ISP6312;
+               ha->isp_type |= DT_ISP6312;
                ha->fw_srisc_address = RISC_START_ADDRESS_2300;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP6322:
-               ha->device_type |= DT_ISP6322;
+               ha->isp_type |= DT_ISP6322;
                ha->fw_srisc_address = RISC_START_ADDRESS_2300;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2422:
-               ha->device_type |= DT_ISP2422;
+               ha->isp_type |= DT_ISP2422;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2432:
-               ha->device_type |= DT_ISP2432;
+               ha->isp_type |= DT_ISP2432;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP8432:
-               ha->device_type |= DT_ISP8432;
+               ha->isp_type |= DT_ISP8432;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP5422:
-               ha->device_type |= DT_ISP5422;
+               ha->isp_type |= DT_ISP5422;
                ha->device_type |= DT_FWI2;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP5432:
-               ha->device_type |= DT_ISP5432;
+               ha->isp_type |= DT_ISP5432;
                ha->device_type |= DT_FWI2;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2532:
-               ha->device_type |= DT_ISP2532;
+               ha->isp_type |= DT_ISP2532;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP8001:
-               ha->device_type |= DT_ISP8001;
+               ha->isp_type |= DT_ISP8001;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP8021:
-               ha->device_type |= DT_ISP8021;
+               ha->isp_type |= DT_ISP8021;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
@@ -2192,7 +2254,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                qla82xx_init_flags(ha);
                break;
         case PCI_DEVICE_ID_QLOGIC_ISP8044:
-               ha->device_type |= DT_ISP8044;
+               ha->isp_type |= DT_ISP8044;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
@@ -2200,7 +2262,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                qla82xx_init_flags(ha);
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2031:
-               ha->device_type |= DT_ISP2031;
+               ha->isp_type |= DT_ISP2031;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
@@ -2208,7 +2270,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP8031:
-               ha->device_type |= DT_ISP8031;
+               ha->isp_type |= DT_ISP8031;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
@@ -2216,10 +2278,10 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISPF001:
-               ha->device_type |= DT_ISPFX00;
+               ha->isp_type |= DT_ISPFX00;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2071:
-               ha->device_type |= DT_ISP2071;
+               ha->isp_type |= DT_ISP2071;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
@@ -2227,7 +2289,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2271:
-               ha->device_type |= DT_ISP2271;
+               ha->isp_type |= DT_ISP2271;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
@@ -2235,7 +2297,7 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
        case PCI_DEVICE_ID_QLOGIC_ISP2261:
-               ha->device_type |= DT_ISP2261;
+               ha->isp_type |= DT_ISP2261;
                ha->device_type |= DT_ZIO_SUPPORTED;
                ha->device_type |= DT_FWI2;
                ha->device_type |= DT_IIDMA;
@@ -2901,6 +2963,10 @@ skip_dpc:
        qlt_add_target(ha, base_vha);
 
        clear_bit(PFLG_DRIVER_PROBING, &base_vha->pci_flags);
+
+       if (test_bit(UNLOADING, &base_vha->dpc_flags))
+               return -ENODEV;
+
        return 0;
 
 probe_init_failed:
@@ -3128,6 +3194,12 @@ qla2x00_remove_one(struct pci_dev *pdev)
 
        qla2x00_wait_for_hba_ready(base_vha);
 
+       /* if UNLOAD flag is already set, then continue unload,
+        * where it was set first.
+        */
+       if (test_bit(UNLOADING, &base_vha->dpc_flags))
+               return;
+
        set_bit(UNLOADING, &base_vha->dpc_flags);
 
        if (IS_QLAFX00(ha))
@@ -4907,6 +4979,12 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)
        struct pci_dev *pdev = ha->pdev;
        scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
+       /* if UNLOAD flag is already set, then continue unload,
+        * where it was set first.
+        */
+       if (test_bit(UNLOADING, &base_vha->dpc_flags))
+               return;
+
        ql_log(ql_log_warn, base_vha, 0x015b,
            "Disabling adapter.\n");
 
@@ -5002,6 +5080,9 @@ qla2x00_do_dpc(void *data)
                    "DPC handler waking up, dpc_flags=0x%lx.\n",
                    base_vha->dpc_flags);
 
+               if (test_bit(UNLOADING, &base_vha->dpc_flags))
+                       break;
+
                qla2x00_do_work(base_vha);
 
                if (IS_P3P_TYPE(ha)) {
index ca39deb4ff5ba3d141b301283289a5ed8250a17d..bff9689f5ca94f56be0a9739af6bf769885f73bf 100644 (file)
@@ -215,8 +215,8 @@ static inline void qlt_incr_num_pend_cmds(struct scsi_qla_host *vha)
        spin_lock_irqsave(&vha->hw->tgt.q_full_lock, flags);
 
        vha->hw->tgt.num_pend_cmds++;
-       if (vha->hw->tgt.num_pend_cmds > vha->hw->qla_stats.stat_max_pend_cmds)
-               vha->hw->qla_stats.stat_max_pend_cmds =
+       if (vha->hw->tgt.num_pend_cmds > vha->qla_stats.stat_max_pend_cmds)
+               vha->qla_stats.stat_max_pend_cmds =
                        vha->hw->tgt.num_pend_cmds;
        spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags);
 }
@@ -5231,8 +5231,8 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
        if ((vha->hw->tgt.num_qfull_cmds_alloc + 1) > MAX_QFULL_CMDS_ALLOC) {
                vha->hw->tgt.num_qfull_cmds_dropped++;
                if (vha->hw->tgt.num_qfull_cmds_dropped >
-                       vha->hw->qla_stats.stat_max_qfull_cmds_dropped)
-                       vha->hw->qla_stats.stat_max_qfull_cmds_dropped =
+                       vha->qla_stats.stat_max_qfull_cmds_dropped)
+                       vha->qla_stats.stat_max_qfull_cmds_dropped =
                                vha->hw->tgt.num_qfull_cmds_dropped;
 
                ql_dbg(ql_dbg_io, vha, 0x3068,
@@ -5263,8 +5263,8 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
 
                vha->hw->tgt.num_qfull_cmds_dropped++;
                if (vha->hw->tgt.num_qfull_cmds_dropped >
-                       vha->hw->qla_stats.stat_max_qfull_cmds_dropped)
-                       vha->hw->qla_stats.stat_max_qfull_cmds_dropped =
+                       vha->qla_stats.stat_max_qfull_cmds_dropped)
+                       vha->qla_stats.stat_max_qfull_cmds_dropped =
                                vha->hw->tgt.num_qfull_cmds_dropped;
 
                qlt_chk_exch_leak_thresh_hold(vha);
@@ -5293,8 +5293,8 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
 
        vha->hw->tgt.num_qfull_cmds_alloc++;
        if (vha->hw->tgt.num_qfull_cmds_alloc >
-               vha->hw->qla_stats.stat_max_qfull_cmds_alloc)
-               vha->hw->qla_stats.stat_max_qfull_cmds_alloc =
+               vha->qla_stats.stat_max_qfull_cmds_alloc)
+               vha->qla_stats.stat_max_qfull_cmds_alloc =
                        vha->hw->tgt.num_qfull_cmds_alloc;
 }
 
index c3e62252460452aac6507db5ddc7ad576f969ffa..36935c9ed669513195a01ba26fd1e302773b593f 100644 (file)
@@ -357,6 +357,13 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
                        ent->t262.start_addr = start;
                        ent->t262.end_addr = end;
                }
+       } else if (ent->t262.ram_area == T262_RAM_AREA_DDR_RAM) {
+               start = vha->hw->fw_ddr_ram_start;
+               end = vha->hw->fw_ddr_ram_end;
+               if (buf) {
+                       ent->t262.start_addr = start;
+                       ent->t262.end_addr = end;
+               }
        } else {
                ql_dbg(ql_dbg_misc, vha, 0xd022,
                    "%s: unknown area %x\n", __func__, ent->t262.ram_area);
@@ -364,7 +371,7 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
                goto done;
        }
 
-       if (end < start || end == 0) {
+       if (end <= start || start == 0 || end == 0) {
                ql_dbg(ql_dbg_misc, vha, 0xd023,
                    "%s: unusable range (start=%x end=%x)\n", __func__,
                    ent->t262.end_addr, ent->t262.start_addr);
index 0bc93fa46dae4222646f17402d06eb1dc69e1f07..3cb1964b7786e4e2add64d7c8f5788fd73b90134 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.07.00.33-k"
+#define QLA2XXX_VERSION      "8.07.00.38-k"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   7
index 1deb6adc411f795833a444a84b1e80e9f9629c4d..1f36aca44394eaf49a8edc0ce78d6db371288cc8 100644 (file)
@@ -1160,6 +1160,7 @@ bool scsi_use_blk_mq = true;
 bool scsi_use_blk_mq = false;
 #endif
 module_param_named(use_blk_mq, scsi_use_blk_mq, bool, S_IWUSR | S_IRUGO);
+EXPORT_SYMBOL_GPL(scsi_use_blk_mq);
 
 static int __init init_scsi(void)
 {
index 0f9ba41e27d8befd4c053fbe5fdf2febeca8f5dd..6a219a0844d347225576689d6290b7d287293356 100644 (file)
@@ -890,7 +890,7 @@ static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        return 0;
 }
 
-/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
+/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
 static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
                                int arr_len)
 {
@@ -909,7 +909,35 @@ static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
        return 0;
 }
 
-/* Returns number of bytes fetched into 'arr' or -1 if error. */
+/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
+ * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
+ * calls, not required to write in ascending offset order. Assumes resid
+ * set to scsi_bufflen() prior to any calls.
+ */
+static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
+                                 int arr_len, unsigned int off_dst)
+{
+       int act_len, n;
+       struct scsi_data_buffer *sdb = scsi_in(scp);
+       off_t skip = off_dst;
+
+       if (sdb->length <= off_dst)
+               return 0;
+       if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
+               return DID_ERROR << 16;
+
+       act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
+                                      arr, arr_len, skip);
+       pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
+                __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
+       n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
+       sdb->resid = min(sdb->resid, n);
+       return 0;
+}
+
+/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
+ * 'arr' or -1 if error.
+ */
 static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
                               int arr_len)
 {
@@ -3269,6 +3297,8 @@ static int resp_get_lba_status(struct scsi_cmnd *scp,
        return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
 }
 
+#define RL_BUCKET_ELEMS 8
+
 /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
  * (W-LUN), the normal Linux scanning logic does not associate it with a
  * device (e.g. /dev/sg7). The following magic will make that association:
@@ -3285,12 +3315,14 @@ static int resp_report_luns(struct scsi_cmnd *scp,
        unsigned char select_report;
        u64 lun;
        struct scsi_lun *lun_p;
-       u8 *arr;
+       u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
        unsigned int lun_cnt;   /* normal LUN count (max: 256) */
        unsigned int wlun_cnt;  /* report luns W-LUN count */
        unsigned int tlun_cnt;  /* total LUN count */
        unsigned int rlen;      /* response length (in bytes) */
-       int i, res;
+       int k, j, n, res;
+       unsigned int off_rsp = 0;
+       const int sz_lun = sizeof(struct scsi_lun);
 
        clear_luns_changed_on_target(devip);
 
@@ -3329,33 +3361,40 @@ static int resp_report_luns(struct scsi_cmnd *scp,
                --lun_cnt;
 
        tlun_cnt = lun_cnt + wlun_cnt;
-
-       rlen = (tlun_cnt * sizeof(struct scsi_lun)) + 8;
-       arr = vmalloc(rlen);
-       if (!arr) {
-               mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
-                               INSUFF_RES_ASCQ);
-               return check_condition_result;
-       }
-       memset(arr, 0, rlen);
+       rlen = tlun_cnt * sz_lun;       /* excluding 8 byte header */
+       scsi_set_resid(scp, scsi_bufflen(scp));
        pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
                 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
 
-       /* luns start at byte 8 in response following the header */
-       lun_p = (struct scsi_lun *)&arr[8];
-
-       /* LUNs use single level peripheral device addressing method */
+       /* loops rely on sizeof response header same as sizeof lun (both 8) */
        lun = sdebug_no_lun_0 ? 1 : 0;
-       for (i = 0; i < lun_cnt; i++)
-               int_to_scsilun(lun++, lun_p++);
-
-       if (wlun_cnt)
-               int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++);
-
-       put_unaligned_be32(rlen - 8, &arr[0]);
-
-       res = fill_from_dev_buffer(scp, arr, rlen);
-       vfree(arr);
+       for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
+               memset(arr, 0, sizeof(arr));
+               lun_p = (struct scsi_lun *)&arr[0];
+               if (k == 0) {
+                       put_unaligned_be32(rlen, &arr[0]);
+                       ++lun_p;
+                       j = 1;
+               }
+               for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
+                       if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
+                               break;
+                       int_to_scsilun(lun++, lun_p);
+               }
+               if (j < RL_BUCKET_ELEMS)
+                       break;
+               n = j * sz_lun;
+               res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
+               if (res)
+                       return res;
+               off_rsp += n;
+       }
+       if (wlun_cnt) {
+               int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
+               ++j;
+       }
+       if (j > 0)
+               res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
        return res;
 }
 
index b0fefd67cac35d9f1746587d2d93ecd9084fdba3..b106596cc0cf5b8e92c92c955f0db6517a30cb93 100644 (file)
@@ -113,11 +113,11 @@ snic_queue_report_tgt_req(struct snic *snic)
 
        pa = pci_map_single(snic->pdev, buf, buf_len, PCI_DMA_FROMDEVICE);
        if (pci_dma_mapping_error(snic->pdev, pa)) {
-               kfree(buf);
-               snic_req_free(snic, rqi);
                SNIC_HOST_ERR(snic->shost,
                              "Rpt-tgt rspbuf %p: PCI DMA Mapping Failed\n",
                              buf);
+               kfree(buf);
+               snic_req_free(snic, rqi);
                ret = -EINVAL;
 
                goto error;
index c5f9e1917a8e58deff695b5b969954bf8580bfc3..2a045a57e3651099d6692c635d52821a41f39b47 100644 (file)
@@ -92,7 +92,7 @@ enum snic_io_status {
 }; /* end of enum snic_io_status */
 
 /*
- * snic_io_hdr : host <--> firmare
+ * snic_io_hdr : host <--> firmware
  *
  * for any other message that will be queued to firmware should
  *  have the following request header
index 3ddcabb790a892f5383379f985b8b26ff7bd76c0..8ccfc9ea874bc2eb1b6197fdcfec72ca2c876d9a 100644 (file)
@@ -966,6 +966,8 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
        if (scmnd->result) {
                if (scsi_normalize_sense(scmnd->sense_buffer,
                                SCSI_SENSE_BUFFERSIZE, &sense_hdr) &&
+                   !(sense_hdr.sense_key == NOT_READY &&
+                                sense_hdr.asc == 0x03A) &&
                    do_logging(STORVSC_LOGGING_ERROR))
                        scsi_print_sense_hdr(scmnd->device, "storvsc",
                                             &sense_hdr);
index 097894a1fab5f6e2a326d75cf2a2bf27694fd291..47966909286dcbd19f8837d1e25d5bcab928737a 100644 (file)
@@ -61,6 +61,14 @@ config SCSI_UFSHCD_PCI
 
          If unsure, say N.
 
+config SCSI_UFS_DWC_TC_PCI
+       tristate "DesignWare pci support using a G210 Test Chip"
+       depends on SCSI_UFSHCD && PCI
+       ---help---
+         Synopsys Test Chip is a PHY for prototyping purposes.
+
+         If unsure, say N.
+
 config SCSI_UFSHCD_PLATFORM
        tristate "Platform bus based UFS Controller support"
        depends on SCSI_UFSHCD
@@ -72,6 +80,14 @@ config SCSI_UFSHCD_PLATFORM
 
          If unsure, say N.
 
+config SCSI_UFS_DWC_TC_PLATFORM
+       tristate "DesignWare platform support using a G210 Test Chip"
+       depends on SCSI_UFSHCD_PLATFORM
+       ---help---
+         Synopsys Test Chip is a PHY for prototyping purposes.
+
+         If unsure, say N.
+
 config SCSI_UFS_QCOM
        tristate "QCOM specific hooks to UFS controller platform driver"
        depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM
index 8303bcce7a2326e54c42db494242bdab995ca730..6e77cb0bfee914ae02190de030e87a2aa7cc70bf 100644 (file)
@@ -1,4 +1,6 @@
 # UFSHCD makefile
+obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.o
+obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o
 obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
 obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
 obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c
new file mode 100644 (file)
index 0000000..c09a0fe
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Synopsys G210 Test Chip driver
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Joao Pinto <jpinto@synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "ufshcd.h"
+#include "ufshcd-dwc.h"
+#include "tc-dwc-g210.h"
+
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+
+/* Test Chip type expected values */
+#define TC_G210_20BIT 20
+#define TC_G210_40BIT 40
+#define TC_G210_INV 0
+
+static int tc_type = TC_G210_INV;
+module_param(tc_type, int, 0);
+MODULE_PARM_DESC(tc_type, "Test Chip Type (20 = 20-bit, 40 = 40-bit)");
+
+static int tc_dwc_g210_pci_suspend(struct device *dev)
+{
+       return ufshcd_system_suspend(dev_get_drvdata(dev));
+}
+
+static int tc_dwc_g210_pci_resume(struct device *dev)
+{
+       return ufshcd_system_resume(dev_get_drvdata(dev));
+}
+
+static int tc_dwc_g210_pci_runtime_suspend(struct device *dev)
+{
+       return ufshcd_runtime_suspend(dev_get_drvdata(dev));
+}
+
+static int tc_dwc_g210_pci_runtime_resume(struct device *dev)
+{
+       return ufshcd_runtime_resume(dev_get_drvdata(dev));
+}
+
+static int tc_dwc_g210_pci_runtime_idle(struct device *dev)
+{
+       return ufshcd_runtime_idle(dev_get_drvdata(dev));
+}
+
+/**
+ * struct ufs_hba_dwc_vops - UFS DWC specific variant operations
+ */
+static struct ufs_hba_variant_ops tc_dwc_g210_pci_hba_vops = {
+       .name                   = "tc-dwc-g210-pci",
+       .link_startup_notify    = ufshcd_dwc_link_startup_notify,
+};
+
+/**
+ * tc_dwc_g210_pci_shutdown - main function to put the controller in reset state
+ * @pdev: pointer to PCI device handle
+ */
+static void tc_dwc_g210_pci_shutdown(struct pci_dev *pdev)
+{
+       ufshcd_shutdown((struct ufs_hba *)pci_get_drvdata(pdev));
+}
+
+/**
+ * tc_dwc_g210_pci_remove - de-allocate PCI/SCSI host and host memory space
+ *             data structure memory
+ * @pdev - pointer to PCI handle
+ */
+static void tc_dwc_g210_pci_remove(struct pci_dev *pdev)
+{
+       struct ufs_hba *hba = pci_get_drvdata(pdev);
+
+       pm_runtime_forbid(&pdev->dev);
+       pm_runtime_get_noresume(&pdev->dev);
+       ufshcd_remove(hba);
+}
+
+/**
+ * tc_dwc_g210_pci_probe - probe routine of the driver
+ * @pdev: pointer to PCI device handle
+ * @id: PCI device id
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int
+tc_dwc_g210_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct ufs_hba *hba;
+       void __iomem *mmio_base;
+       int err;
+
+       /* Check Test Chip type and set the specific setup routine */
+       if (tc_type == TC_G210_20BIT) {
+               tc_dwc_g210_pci_hba_vops.phy_initialization =
+                                               tc_dwc_g210_config_20_bit;
+       } else if (tc_type == TC_G210_40BIT) {
+               tc_dwc_g210_pci_hba_vops.phy_initialization =
+                                               tc_dwc_g210_config_40_bit;
+       } else {
+               dev_err(&pdev->dev, "test chip version not specified\n");
+               return -EPERM;
+       }
+
+       err = pcim_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "pcim_enable_device failed\n");
+               return err;
+       }
+
+       pci_set_master(pdev);
+
+       err = pcim_iomap_regions(pdev, 1 << 0, UFSHCD);
+       if (err < 0) {
+               dev_err(&pdev->dev, "request and iomap failed\n");
+               return err;
+       }
+
+       mmio_base = pcim_iomap_table(pdev)[0];
+
+       err = ufshcd_alloc_host(&pdev->dev, &hba);
+       if (err) {
+               dev_err(&pdev->dev, "Allocation failed\n");
+               return err;
+       }
+
+       INIT_LIST_HEAD(&hba->clk_list_head);
+
+       hba->vops = &tc_dwc_g210_pci_hba_vops;
+
+       err = ufshcd_init(hba, mmio_base, pdev->irq);
+       if (err) {
+               dev_err(&pdev->dev, "Initialization failed\n");
+               return err;
+       }
+
+       pci_set_drvdata(pdev, hba);
+       pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_allow(&pdev->dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
+       .suspend        = tc_dwc_g210_pci_suspend,
+       .resume         = tc_dwc_g210_pci_resume,
+       .runtime_suspend = tc_dwc_g210_pci_runtime_suspend,
+       .runtime_resume  = tc_dwc_g210_pci_runtime_resume,
+       .runtime_idle    = tc_dwc_g210_pci_runtime_idle,
+};
+
+static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
+       { PCI_VENDOR_ID_SYNOPSYS, 0xB101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_SYNOPSYS, 0xB102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { }     /* terminate list */
+};
+
+MODULE_DEVICE_TABLE(pci, tc_dwc_g210_pci_tbl);
+
+static struct pci_driver tc_dwc_g210_pci_driver = {
+       .name = "tc-dwc-g210-pci",
+       .id_table = tc_dwc_g210_pci_tbl,
+       .probe = tc_dwc_g210_pci_probe,
+       .remove = tc_dwc_g210_pci_remove,
+       .shutdown = tc_dwc_g210_pci_shutdown,
+       .driver = {
+               .pm = &tc_dwc_g210_pci_pm_ops
+       },
+};
+
+module_pci_driver(tc_dwc_g210_pci_driver);
+
+MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
+MODULE_DESCRIPTION("Synopsys Test Chip G210 PCI glue driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
new file mode 100644 (file)
index 0000000..2d3f527
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Synopsys G210 Test Chip driver
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Joao Pinto <jpinto@synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+
+#include "ufshcd-pltfrm.h"
+#include "ufshcd-dwc.h"
+#include "tc-dwc-g210.h"
+
+/**
+ * UFS DWC specific variant operations
+ */
+static struct ufs_hba_variant_ops tc_dwc_g210_20bit_pltfm_hba_vops = {
+       .name                   = "tc-dwc-g210-pltfm",
+       .link_startup_notify    = ufshcd_dwc_link_startup_notify,
+       .phy_initialization = tc_dwc_g210_config_20_bit,
+};
+
+static struct ufs_hba_variant_ops tc_dwc_g210_40bit_pltfm_hba_vops = {
+       .name                   = "tc-dwc-g210-pltfm",
+       .link_startup_notify    = ufshcd_dwc_link_startup_notify,
+       .phy_initialization = tc_dwc_g210_config_40_bit,
+};
+
+static const struct of_device_id tc_dwc_g210_pltfm_match[] = {
+       {
+               .compatible = "snps,g210-tc-6.00-20bit",
+               .data = &tc_dwc_g210_20bit_pltfm_hba_vops,
+       },
+       {
+               .compatible = "snps,g210-tc-6.00-40bit",
+               .data = &tc_dwc_g210_40bit_pltfm_hba_vops,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, tc_dwc_g210_pltfm_match);
+
+/**
+ * tc_dwc_g210_pltfm_probe()
+ * @pdev: pointer to platform device structure
+ *
+ */
+static int tc_dwc_g210_pltfm_probe(struct platform_device *pdev)
+{
+       int err;
+       const struct of_device_id *of_id;
+       struct ufs_hba_variant_ops *vops;
+       struct device *dev = &pdev->dev;
+
+       of_id = of_match_node(tc_dwc_g210_pltfm_match, dev->of_node);
+       vops = (struct ufs_hba_variant_ops *)of_id->data;
+
+       /* Perform generic probe */
+       err = ufshcd_pltfrm_init(pdev, vops);
+       if (err)
+               dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
+
+       return err;
+}
+
+/**
+ * tc_dwc_g210_pltfm_remove()
+ * @pdev: pointer to platform device structure
+ *
+ */
+static int tc_dwc_g210_pltfm_remove(struct platform_device *pdev)
+{
+       struct ufs_hba *hba =  platform_get_drvdata(pdev);
+
+       pm_runtime_get_sync(&(pdev)->dev);
+       ufshcd_remove(hba);
+
+       return 0;
+}
+
+static const struct dev_pm_ops tc_dwc_g210_pltfm_pm_ops = {
+       .suspend        = ufshcd_pltfrm_suspend,
+       .resume         = ufshcd_pltfrm_resume,
+       .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
+       .runtime_resume  = ufshcd_pltfrm_runtime_resume,
+       .runtime_idle    = ufshcd_pltfrm_runtime_idle,
+};
+
+static struct platform_driver tc_dwc_g210_pltfm_driver = {
+       .probe          = tc_dwc_g210_pltfm_probe,
+       .remove         = tc_dwc_g210_pltfm_remove,
+       .shutdown = ufshcd_pltfrm_shutdown,
+       .driver         = {
+               .name   = "tc-dwc-g210-pltfm",
+               .pm     = &tc_dwc_g210_pltfm_pm_ops,
+               .of_match_table = of_match_ptr(tc_dwc_g210_pltfm_match),
+       },
+};
+
+module_platform_driver(tc_dwc_g210_pltfm_driver);
+
+MODULE_ALIAS("platform:tc-dwc-g210-pltfm");
+MODULE_DESCRIPTION("Synopsys Test Chip G210 platform glue driver");
+MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c
new file mode 100644 (file)
index 0000000..70db6d9
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Synopsys G210 Test Chip driver
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Joao Pinto <jpinto@synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "ufshcd.h"
+#include "unipro.h"
+
+#include "ufshcd-dwc.h"
+#include "ufshci-dwc.h"
+
+/**
+ * tc_dwc_g210_setup_40bit_rmmi()
+ * This function configures Synopsys TC specific atributes (40-bit RMMI)
+ * @hba: Pointer to drivers structure
+ *
+ * Returns 0 on success or non-zero value on failure
+ */
+static int tc_dwc_g210_setup_40bit_rmmi(struct ufs_hba *hba)
+{
+       const struct ufshcd_dme_attr_val setup_attrs[] = {
+               { UIC_ARG_MIB(TX_GLOBALHIBERNATE), 0x00, DME_LOCAL },
+               { UIC_ARG_MIB(REFCLKMODE), 0x01, DME_LOCAL },
+               { UIC_ARG_MIB(CDIRECTCTRL6), 0x80, DME_LOCAL },
+               { UIC_ARG_MIB(CBDIVFACTOR), 0x08, DME_LOCAL },
+               { UIC_ARG_MIB(CBDCOCTRL5), 0x64, DME_LOCAL },
+               { UIC_ARG_MIB(CBPRGTUNING), 0x09, DME_LOCAL },
+               { UIC_ARG_MIB(RTOBSERVESELECT), 0x00, DME_LOCAL },
+               { UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN0_TX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN0_TX), 0x19,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN0_TX), 0x14,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN0_RX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN0_RX), 0x19,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN0_RX), 4,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB(DIRECTCTRL10), 0x04, DME_LOCAL },
+               { UIC_ARG_MIB(DIRECTCTRL19), 0x02, DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN0_RX), 0x03,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN0_RX), 0x16,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN0_RX), 0x42,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN0_RX), 0xa4,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN0_RX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN0_RX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN0_RX), 0x28,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN0_RX), 0x1E,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB(CBPRGPLL2), 0x00, DME_LOCAL },
+       };
+
+       return ufshcd_dwc_dme_set_attrs(hba, setup_attrs,
+                                               ARRAY_SIZE(setup_attrs));
+}
+
+/**
+ * tc_dwc_g210_setup_20bit_rmmi_lane0()
+ * This function configures Synopsys TC 20-bit RMMI Lane 0
+ * @hba: Pointer to drivers structure
+ *
+ * Returns 0 on success or non-zero value on failure
+ */
+static int tc_dwc_g210_setup_20bit_rmmi_lane0(struct ufs_hba *hba)
+{
+       const struct ufshcd_dme_attr_val setup_attrs[] = {
+               { UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN0_TX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN0_TX), 0x19,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN0_RX), 0x19,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN0_TX), 0x12,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN0_RX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN0_RX), 2,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN0_RX), 0x80,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB(DIRECTCTRL10), 0x04, DME_LOCAL },
+               { UIC_ARG_MIB(DIRECTCTRL19), 0x02, DME_LOCAL },
+               { UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN0_RX), 0x03,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN0_RX), 0x16,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN0_RX), 0x42,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN0_RX), 0xa4,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN0_RX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN0_RX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN0_RX), 0x28,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN0_RX), 0x1E,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN0_RX), 0x2f,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB(CBPRGPLL2), 0x00, DME_LOCAL },
+       };
+
+       return ufshcd_dwc_dme_set_attrs(hba, setup_attrs,
+                                               ARRAY_SIZE(setup_attrs));
+}
+
+/**
+ * tc_dwc_g210_setup_20bit_rmmi_lane1()
+ * This function configures Synopsys TC 20-bit RMMI Lane 1
+ * @hba: Pointer to drivers structure
+ *
+ * Returns 0 on success or non-zero value on failure
+ */
+static int tc_dwc_g210_setup_20bit_rmmi_lane1(struct ufs_hba *hba)
+{
+       int connected_rx_lanes = 0;
+       int connected_tx_lanes = 0;
+       int ret = 0;
+
+       const struct ufshcd_dme_attr_val setup_tx_attrs[] = {
+               { UIC_ARG_MIB_SEL(TX_REFCLKFREQ, SELIND_LN1_TX), 0x0d,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(TX_CFGCLKFREQVAL, SELIND_LN1_TX), 0x19,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGEXTRATTR, SELIND_LN1_TX), 0x12,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(DITHERCTRL2, SELIND_LN0_TX), 0xd6,
+                                                               DME_LOCAL },
+       };
+
+       const struct ufshcd_dme_attr_val setup_rx_attrs[] = {
+               { UIC_ARG_MIB_SEL(RX_REFCLKFREQ, SELIND_LN1_RX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RX_CFGCLKFREQVAL, SELIND_LN1_RX), 0x19,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGWIDEINLN, SELIND_LN1_RX), 2,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXCDR8, SELIND_LN1_RX), 0x80,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(ENARXDIRECTCFG4, SELIND_LN1_RX), 0x03,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR8, SELIND_LN1_RX), 0x16,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RXDIRECTCTRL2, SELIND_LN1_RX), 0x42,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(ENARXDIRECTCFG3, SELIND_LN1_RX), 0xa4,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RXCALCTRL, SELIND_LN1_RX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(ENARXDIRECTCFG2, SELIND_LN1_RX), 0x01,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR4, SELIND_LN1_RX), 0x28,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(RXSQCTRL, SELIND_LN1_RX), 0x1E,
+                                                               DME_LOCAL },
+               { UIC_ARG_MIB_SEL(CFGRXOVR6, SELIND_LN1_RX), 0x2f,
+                                                               DME_LOCAL },
+       };
+
+       /* Get the available lane count */
+       ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILRXDATALANES),
+                       &connected_rx_lanes);
+       ufshcd_dme_get(hba, UIC_ARG_MIB(PA_AVAILTXDATALANES),
+                       &connected_tx_lanes);
+
+       if (connected_tx_lanes == 2) {
+
+               ret = ufshcd_dwc_dme_set_attrs(hba, setup_tx_attrs,
+                                               ARRAY_SIZE(setup_tx_attrs));
+
+               if (ret)
+                       goto out;
+       }
+
+       if (connected_rx_lanes == 2) {
+               ret = ufshcd_dwc_dme_set_attrs(hba, setup_rx_attrs,
+                                               ARRAY_SIZE(setup_rx_attrs));
+       }
+
+out:
+       return ret;
+}
+
+/**
+ * tc_dwc_g210_setup_20bit_rmmi()
+ * This function configures Synopsys TC specific atributes (20-bit RMMI)
+ * @hba: Pointer to drivers structure
+ *
+ * Returns 0 on success or non-zero value on failure
+ */
+static int tc_dwc_g210_setup_20bit_rmmi(struct ufs_hba *hba)
+{
+       int ret = 0;
+
+       const struct ufshcd_dme_attr_val setup_attrs[] = {
+               { UIC_ARG_MIB(TX_GLOBALHIBERNATE), 0x00, DME_LOCAL },
+               { UIC_ARG_MIB(REFCLKMODE), 0x01, DME_LOCAL },
+               { UIC_ARG_MIB(CDIRECTCTRL6), 0xc0, DME_LOCAL },
+               { UIC_ARG_MIB(CBDIVFACTOR), 0x44, DME_LOCAL },
+               { UIC_ARG_MIB(CBDCOCTRL5), 0x64, DME_LOCAL },
+               { UIC_ARG_MIB(CBPRGTUNING), 0x09, DME_LOCAL },
+               { UIC_ARG_MIB(RTOBSERVESELECT), 0x00, DME_LOCAL },
+       };
+
+       ret = ufshcd_dwc_dme_set_attrs(hba, setup_attrs,
+                                               ARRAY_SIZE(setup_attrs));
+       if (ret)
+               goto out;
+
+       /* Lane 0 configuration*/
+       ret = tc_dwc_g210_setup_20bit_rmmi_lane0(hba);
+       if (ret)
+               goto out;
+
+       /* Lane 1 configuration*/
+       ret = tc_dwc_g210_setup_20bit_rmmi_lane1(hba);
+       if (ret)
+               goto out;
+
+out:
+       return ret;
+}
+
+/**
+ * tc_dwc_g210_config_40_bit()
+ * This function configures Local (host) Synopsys 40-bit TC specific attributes
+ *
+ * @hba: Pointer to drivers structure
+ *
+ * Returns 0 on success non-zero value on failure
+ */
+int tc_dwc_g210_config_40_bit(struct ufs_hba *hba)
+{
+       int ret = 0;
+
+       dev_info(hba->dev, "Configuring Test Chip 40-bit RMMI\n");
+       ret = tc_dwc_g210_setup_40bit_rmmi(hba);
+       if (ret) {
+               dev_err(hba->dev, "Configuration failed\n");
+               goto out;
+       }
+
+       /* To write Shadow register bank to effective configuration block */
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
+       if (ret)
+               goto out;
+
+       /* To configure Debug OMC */
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), 0x01);
+
+out:
+       return ret;
+}
+EXPORT_SYMBOL(tc_dwc_g210_config_40_bit);
+
+/**
+ * tc_dwc_g210_config_20_bit()
+ * This function configures Local (host) Synopsys 20-bit TC specific attributes
+ *
+ * @hba: Pointer to drivers structure
+ *
+ * Returns 0 on success non-zero value on failure
+ */
+int tc_dwc_g210_config_20_bit(struct ufs_hba *hba)
+{
+       int ret = 0;
+
+       dev_info(hba->dev, "Configuring Test Chip 20-bit RMMI\n");
+       ret = tc_dwc_g210_setup_20bit_rmmi(hba);
+       if (ret) {
+               dev_err(hba->dev, "Configuration failed\n");
+               goto out;
+       }
+
+       /* To write Shadow register bank to effective configuration block */
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
+       if (ret)
+               goto out;
+
+       /* To configure Debug OMC */
+       ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_DEBUGOMC), 0x01);
+
+out:
+       return ret;
+}
+EXPORT_SYMBOL(tc_dwc_g210_config_20_bit);
+
+MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
+MODULE_DESCRIPTION("Synopsys G210 Test Chip driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/scsi/ufs/tc-dwc-g210.h b/drivers/scsi/ufs/tc-dwc-g210.h
new file mode 100644 (file)
index 0000000..fb177db
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Synopsys G210 Test Chip driver
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Joao Pinto <jpinto@synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _TC_DWC_G210_H
+#define _TC_DWC_G210_H
+
+int tc_dwc_g210_config_40_bit(struct ufs_hba *hba);
+int tc_dwc_g210_config_20_bit(struct ufs_hba *hba);
+
+#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c
new file mode 100644 (file)
index 0000000..5fd16c7
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * UFS Host driver for Synopsys Designware Core
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Joao Pinto <jpinto@synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "ufshcd.h"
+#include "unipro.h"
+
+#include "ufshcd-dwc.h"
+#include "ufshci-dwc.h"
+
+int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba,
+                               const struct ufshcd_dme_attr_val *v, int n)
+{
+       int ret = 0;
+       int attr_node = 0;
+
+       for (attr_node = 0; attr_node < n; attr_node++) {
+               ret = ufshcd_dme_set_attr(hba, v[attr_node].attr_sel,
+                       ATTR_SET_NOR, v[attr_node].mib_val, v[attr_node].peer);
+
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(ufshcd_dwc_dme_set_attrs);
+
+/**
+ * ufshcd_dwc_program_clk_div()
+ * This function programs the clk divider value. This value is needed to
+ * provide 1 microsecond tick to unipro layer.
+ * @hba: Private Structure pointer
+ * @divider_val: clock divider value to be programmed
+ *
+ */
+static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val)
+{
+       ufshcd_writel(hba, divider_val, DWC_UFS_REG_HCLKDIV);
+}
+
+/**
+ * ufshcd_dwc_link_is_up()
+ * Check if link is up
+ * @hba: private structure poitner
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_dwc_link_is_up(struct ufs_hba *hba)
+{
+       int dme_result = 0;
+
+       ufshcd_dme_get(hba, UIC_ARG_MIB(VS_POWERSTATE), &dme_result);
+
+       if (dme_result == UFSHCD_LINK_IS_UP) {
+               ufshcd_set_link_active(hba);
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ * ufshcd_dwc_connection_setup()
+ * This function configures both the local side (host) and the peer side
+ * (device) unipro attributes to establish the connection to application/
+ * cport.
+ * This function is not required if the hardware is properly configured to
+ * have this connection setup on reset. But invoking this function does no
+ * harm and should be fine even working with any ufs device.
+ *
+ * @hba: pointer to drivers private data
+ *
+ * Returns 0 on success non-zero value on failure
+ */
+static int ufshcd_dwc_connection_setup(struct ufs_hba *hba)
+{
+       const struct ufshcd_dme_attr_val setup_attrs[] = {
+               { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_LOCAL },
+               { UIC_ARG_MIB(N_DEVICEID), 0, DME_LOCAL },
+               { UIC_ARG_MIB(N_DEVICEID_VALID), 0, DME_LOCAL },
+               { UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_LOCAL },
+               { UIC_ARG_MIB(T_PEERCPORTID), 0, DME_LOCAL },
+               { UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_LOCAL },
+               { UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_LOCAL },
+               { UIC_ARG_MIB(T_CPORTMODE), 1, DME_LOCAL },
+               { UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_LOCAL },
+               { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_PEER },
+               { UIC_ARG_MIB(N_DEVICEID), 1, DME_PEER },
+               { UIC_ARG_MIB(N_DEVICEID_VALID), 1, DME_PEER },
+               { UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_PEER },
+               { UIC_ARG_MIB(T_PEERCPORTID), 0, DME_PEER },
+               { UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_PEER },
+               { UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_PEER },
+               { UIC_ARG_MIB(T_CPORTMODE), 1, DME_PEER },
+               { UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_PEER }
+       };
+
+       return ufshcd_dwc_dme_set_attrs(hba, setup_attrs, ARRAY_SIZE(setup_attrs));
+}
+
+/**
+ * ufshcd_dwc_link_startup_notify()
+ * UFS Host DWC specific link startup sequence
+ * @hba: private structure poitner
+ * @status: Callback notify status
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba,
+                                       enum ufs_notify_change_status status)
+{
+       int err = 0;
+
+       if (status == PRE_CHANGE) {
+               ufshcd_dwc_program_clk_div(hba, DWC_UFS_REG_HCLKDIV_DIV_125);
+
+               if (hba->vops->phy_initialization) {
+                       err = hba->vops->phy_initialization(hba);
+                       if (err) {
+                               dev_err(hba->dev, "Phy setup failed (%d)\n",
+                                                                       err);
+                               goto out;
+                       }
+               }
+       } else { /* POST_CHANGE */
+               err = ufshcd_dwc_link_is_up(hba);
+               if (err) {
+                       dev_err(hba->dev, "Link is not up\n");
+                       goto out;
+               }
+
+               err = ufshcd_dwc_connection_setup(hba);
+               if (err)
+                       dev_err(hba->dev, "Connection setup failed (%d)\n",
+                                                                       err);
+       }
+
+out:
+       return err;
+}
+EXPORT_SYMBOL(ufshcd_dwc_link_startup_notify);
+
+MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
+MODULE_DESCRIPTION("UFS Host driver for Synopsys Designware Core");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/scsi/ufs/ufshcd-dwc.h b/drivers/scsi/ufs/ufshcd-dwc.h
new file mode 100644 (file)
index 0000000..c8be295
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * UFS Host driver for Synopsys Designware Core
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Joao Pinto <jpinto@synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _UFSHCD_DWC_H
+#define _UFSHCD_DWC_H
+
+struct ufshcd_dme_attr_val {
+       u32 attr_sel;
+       u32 mib_val;
+       u8 peer;
+};
+
+int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba,
+                                       enum ufs_notify_change_status status);
+int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba,
+                               const struct ufshcd_dme_attr_val *v, int n);
+#endif /* End of Header */
index 718f12e0988535fa14b517c1288626fa5d5da99f..db53f38da864f76baa3c5f697b1673d109539c32 100644 (file)
@@ -372,6 +372,6 @@ EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
 
 MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
 MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
-MODULE_DESCRIPTION("UFS host controller Pltform bus based glue driver");
+MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(UFSHCD_DRIVER_VERSION);
index f8fa72c31a9dd3fad5eda09c4381ee88c17a1381..f08d41a2d70b73bd8be1f505807af26270528335 100644 (file)
@@ -1173,7 +1173,7 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
  * @cmd_dir: requests data direction
  */
 static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
-               u32 *upiu_flags, enum dma_data_direction cmd_dir)
+                       u32 *upiu_flags, enum dma_data_direction cmd_dir)
 {
        struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
        u32 data_direction;
@@ -1299,47 +1299,55 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
 }
 
 /**
- * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
+ * ufshcd_comp_devman_upiu - UFS Protocol Information Unit(UPIU)
+ *                          for Device Management Purposes
  * @hba - per adapter instance
  * @lrb - pointer to local reference block
  */
-static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 {
        u32 upiu_flags;
        int ret = 0;
 
-       switch (lrbp->command_type) {
-       case UTP_CMD_TYPE_SCSI:
-               if (likely(lrbp->cmd)) {
-                       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags,
-                                       lrbp->cmd->sc_data_direction);
-                       ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
-               } else {
-                       ret = -EINVAL;
-               }
-               break;
-       case UTP_CMD_TYPE_DEV_MANAGE:
-               ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
-               if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
-                       ufshcd_prepare_utp_query_req_upiu(
-                                       hba, lrbp, upiu_flags);
-               else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP)
-                       ufshcd_prepare_utp_nop_upiu(lrbp);
-               else
-                       ret = -EINVAL;
-               break;
-       case UTP_CMD_TYPE_UFS:
-               /* For UFS native command implementation */
-               ret = -ENOTSUPP;
-               dev_err(hba->dev, "%s: UFS native command are not supported\n",
-                       __func__);
-               break;
-       default:
-               ret = -ENOTSUPP;
-               dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
-                               __func__, lrbp->command_type);
-               break;
-       } /* end of switch */
+       if (hba->ufs_version == UFSHCI_VERSION_20)
+               lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
+       else
+               lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+
+       ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+       if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
+               ufshcd_prepare_utp_query_req_upiu(hba, lrbp, upiu_flags);
+       else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP)
+               ufshcd_prepare_utp_nop_upiu(lrbp);
+       else
+               ret = -EINVAL;
+
+       return ret;
+}
+
+/**
+ * ufshcd_comp_scsi_upiu - UFS Protocol Information Unit(UPIU)
+ *                        for SCSI Purposes
+ * @hba - per adapter instance
+ * @lrb - pointer to local reference block
+ */
+static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+       u32 upiu_flags;
+       int ret = 0;
+
+       if (hba->ufs_version == UFSHCI_VERSION_20)
+               lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
+       else
+               lrbp->command_type = UTP_CMD_TYPE_SCSI;
+
+       if (likely(lrbp->cmd)) {
+               ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags,
+                                               lrbp->cmd->sc_data_direction);
+               ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
+       } else {
+               ret = -EINVAL;
+       }
 
        return ret;
 }
@@ -1451,10 +1459,9 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        lrbp->task_tag = tag;
        lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
        lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
-       lrbp->command_type = UTP_CMD_TYPE_SCSI;
 
-       /* form UPIU before issuing the command */
-       ufshcd_compose_upiu(hba, lrbp);
+       ufshcd_comp_scsi_upiu(hba, lrbp);
+
        err = ufshcd_map_sg(lrbp);
        if (err) {
                lrbp->cmd = NULL;
@@ -1479,11 +1486,10 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
        lrbp->sense_buffer = NULL;
        lrbp->task_tag = tag;
        lrbp->lun = 0; /* device management cmd is not specific to any LUN */
-       lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
        lrbp->intr_cmd = true; /* No interrupt aggregation */
        hba->dev_cmd.type = cmd_type;
 
-       return ufshcd_compose_upiu(hba, lrbp);
+       return ufshcd_comp_devman_upiu(hba, lrbp);
 }
 
 static int
@@ -2131,7 +2137,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
                buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
                if (!buff_ascii) {
                        err = -ENOMEM;
-                       goto out_free_buff;
+                       goto out;
                }
 
                /*
@@ -2150,7 +2156,6 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
                                size - QUERY_DESC_HDR_SIZE);
                memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len);
                buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE;
-out_free_buff:
                kfree(buff_ascii);
        }
 out:
@@ -3539,7 +3544,8 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
                        /* Do not touch lrbp after scsi done */
                        cmd->scsi_done(cmd);
                        __ufshcd_release(hba);
-               } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) {
+               } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE ||
+                       lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
                        if (hba->dev_cmd.complete)
                                complete(hba->dev_cmd.complete);
                }
index 4bb65669f052949e7262ceb8df83e54290fafdc4..430bef11129324a49b131460b9dfa4f0d7b97022 100644 (file)
@@ -264,6 +264,7 @@ struct ufs_pwr_mode_info {
  * @suspend: called during host controller PM callback
  * @resume: called during host controller PM callback
  * @dbg_register_dump: used to dump controller debug information
+ * @phy_initialization: used to initialize phys
  */
 struct ufs_hba_variant_ops {
        const char *name;
@@ -285,6 +286,7 @@ struct ufs_hba_variant_ops {
        int     (*suspend)(struct ufs_hba *, enum ufs_pm_op);
        int     (*resume)(struct ufs_hba *, enum ufs_pm_op);
        void    (*dbg_register_dump)(struct ufs_hba *hba);
+       int     (*phy_initialization)(struct ufs_hba *);
 };
 
 /* clock gating state  */
@@ -567,11 +569,16 @@ static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba)
 
 static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba)
 {
+/* DWC UFS Core has the Interrupt aggregation feature but is not detectable*/
+#ifndef CONFIG_SCSI_UFS_DWC
        if ((hba->caps & UFSHCD_CAP_INTR_AGGR) &&
            !(hba->quirks & UFSHCD_QUIRK_BROKEN_INTR_AGGR))
                return true;
        else
                return false;
+#else
+return true;
+#endif
 }
 
 #define ufshcd_writel(hba, val, reg)   \
diff --git a/drivers/scsi/ufs/ufshci-dwc.h b/drivers/scsi/ufs/ufshci-dwc.h
new file mode 100644 (file)
index 0000000..ca341fe
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * UFS Host driver for Synopsys Designware Core
+ *
+ * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Authors: Joao Pinto <jpinto@synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _UFSHCI_DWC_H
+#define _UFSHCI_DWC_H
+
+/* DWC HC UFSHCI specific Registers */
+enum dwc_specific_registers {
+       DWC_UFS_REG_HCLKDIV     = 0xFC,
+};
+
+/* Clock Divider Values: Hex equivalent of frequency in MHz */
+enum clk_div_values {
+       DWC_UFS_REG_HCLKDIV_DIV_62_5    = 0x3e,
+       DWC_UFS_REG_HCLKDIV_DIV_125     = 0x7d,
+       DWC_UFS_REG_HCLKDIV_DIV_200     = 0xc8,
+};
+
+/* Selector Index */
+enum selector_index {
+       SELIND_LN0_TX           = 0x00,
+       SELIND_LN1_TX           = 0x01,
+       SELIND_LN0_RX           = 0x04,
+       SELIND_LN1_RX           = 0x05,
+};
+
+#endif /* End of Header */
index 4cb1cc63f1a1bd834fb22a972de9803c47891f24..9599741ff606cfad3eb037a2b0bc4da1227134cf 100644 (file)
@@ -220,6 +220,12 @@ enum {
 #define UIC_ARG_ATTR_TYPE(t)           (((t) & 0xFF) << 16)
 #define UIC_GET_ATTR_ID(v)             (((v) >> 16) & 0xFFFF)
 
+/* Link Status*/
+enum link_status {
+       UFSHCD_LINK_IS_DOWN     = 1,
+       UFSHCD_LINK_IS_UP       = 2,
+};
+
 /* UIC Commands */
 enum uic_cmd_dme {
        UIC_CMD_DME_GET                 = 0x01,
@@ -279,6 +285,11 @@ enum {
        UTP_CMD_TYPE_DEV_MANAGE         = 0x2,
 };
 
+/* To accommodate UFS2.0 required Command type */
+enum {
+       UTP_CMD_TYPE_UFS_STORAGE        = 0x1,
+};
+
 enum {
        UTP_SCSI_COMMAND                = 0x00000000,
        UTP_NATIVE_UFS_COMMAND          = 0x10000000,
index e2854e45f8d3e225127dce8f0af13bed2fa47283..eff8b567557532090f745779ce92f89d2171b94b 100644 (file)
 #define TX_LCC_SEQUENCER                       0x0032
 #define TX_MIN_ACTIVATETIME                    0x0033
 #define TX_PWM_G6_G7_SYNC_LENGTH               0x0034
+#define TX_REFCLKFREQ                          0x00EB
+#define TX_CFGCLKFREQVAL                       0x00EC
+#define        CFGEXTRATTR                             0x00F0
+#define DITHERCTRL2                            0x00F1
 
 /*
  * M-RX Configuration Attributes
 #define RX_TERMINATION_FORCE_ENABLE            0x0089
 #define RX_MIN_ACTIVATETIME_CAPABILITY         0x008F
 #define RX_HIBERN8TIME_CAPABILITY              0x0092
+#define RX_REFCLKFREQ                          0x00EB
+#define        RX_CFGCLKFREQVAL                        0x00EC
+#define CFGWIDEINLN                            0x00F0
+#define CFGRXCDR8                              0x00BA
+#define ENARXDIRECTCFG4                                0x00F2
+#define CFGRXOVR8                              0x00BD
+#define RXDIRECTCTRL2                          0x00C7
+#define ENARXDIRECTCFG3                                0x00F3
+#define RXCALCTRL                              0x00B4
+#define ENARXDIRECTCFG2                                0x00F4
+#define CFGRXOVR4                              0x00E9
+#define RXSQCTRL                               0x00B5
+#define CFGRXOVR6                              0x00BF
 
 #define is_mphy_tx_attr(attr)                  (attr < RX_MODE)
 #define RX_MIN_ACTIVATETIME_UNIT_US            100
 #define HIBERN8TIME_UNIT_US                    100
+
+/*
+ * Common Block Attributes
+ */
+#define TX_GLOBALHIBERNATE                     UNIPRO_CB_OFFSET(0x002B)
+#define REFCLKMODE                             UNIPRO_CB_OFFSET(0x00BF)
+#define DIRECTCTRL19                           UNIPRO_CB_OFFSET(0x00CD)
+#define DIRECTCTRL10                           UNIPRO_CB_OFFSET(0x00E6)
+#define CDIRECTCTRL6                           UNIPRO_CB_OFFSET(0x00EA)
+#define RTOBSERVESELECT                                UNIPRO_CB_OFFSET(0x00F0)
+#define CBDIVFACTOR                            UNIPRO_CB_OFFSET(0x00F1)
+#define CBDCOCTRL5                             UNIPRO_CB_OFFSET(0x00F3)
+#define CBPRGPLL2                              UNIPRO_CB_OFFSET(0x00F8)
+#define CBPRGTUNING                            UNIPRO_CB_OFFSET(0x00FB)
+
+#define UNIPRO_CB_OFFSET(x)                    (0x8000 | x)
+
 /*
  * PHY Adpater attributes
  */
 #define PA_TACTIVATE_TIME_UNIT_US      10
 #define PA_HIBERN8_TIME_UNIT_US                100
 
+/*Other attributes*/
+#define VS_MPHYCFGUPDT         0xD085
+#define VS_DEBUGOMC            0xD09E
+#define VS_POWERSTATE          0xD083
+
 /* PHY Adapter Protocol Constants */
 #define PA_MAXDATALANES        4
 
index 6164634aff1895b208e919ffd47b6aaf59ca5e91..4a0d3cdc607cd5d8bfdb28867187fd7d12df0919 100644 (file)
@@ -17,7 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Maintained by: Arvind Kumar <arvindkumar@vmware.com>
+ * Maintained by: Jim Gill <jgill@vmware.com>
  *
  */
 
index 12712c92f37ac27d30796231862de2121c54f4b0..c097d2ccbde3163eaa9d1ab0a20f402446c79002 100644 (file)
@@ -17,7 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Maintained by: Arvind Kumar <arvindkumar@vmware.com>
+ * Maintained by: Jim Gill <jgill@vmware.com>
  *
  */
 
index 0c0f17b9a3ebfd27917c9799a453a0efa9a2273b..409f959845c41b3770fca50e7e97665e4f189010 100644 (file)
 #ifdef WD7000_DEBUG
 #define dprintk printk
 #else
-#define dprintk(format,args...)
+#define dprintk        no_printk
 #endif
 
 /*
@@ -1591,8 +1591,8 @@ static int wd7000_biosparam(struct scsi_device *sdev,
 {
        char b[BDEVNAME_SIZE];
 
-       dprintk("wd7000_biosparam: dev=%s, size=%d, ",
-               bdevname(bdev, b), capacity);
+       dprintk("wd7000_biosparam: dev=%s, size=%llu, ",
+               bdevname(bdev, b), (u64)capacity);
        (void)b;        /* unused var warning? */
 
        /*
index ae25d4ab25486311c59d1954219c4a52eeea0f34..9710254fd98c8aa40303e318e5851693f5e969a9 100644 (file)
@@ -22,7 +22,7 @@
 /*
  * This version is based on:
  * http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf
- * and T11 FC-BB-6 10-019v4.pdf (June 2010 VN2VN proposal)
+ * and T11 FC-BB-6 13-091v5.pdf (December 2013 VN2VN proposal)
  */
 
 #define FIP_DEF_PRI    128     /* default selection priority */
@@ -109,8 +109,9 @@ enum fip_reset_subcode {
  * Subcodes for FIP_OP_VLAN.
  */
 enum fip_vlan_subcode {
-       FIP_SC_VL_REQ = 1,              /* request */
-       FIP_SC_VL_REP = 2,              /* reply */
+       FIP_SC_VL_REQ = 1,              /* vlan request */
+       FIP_SC_VL_NOTE = 2,             /* vlan notification */
+       FIP_SC_VL_VN2VN_NOTE = 3,       /* VN2VN vlan notification */
 };
 
 /*
@@ -130,6 +131,8 @@ enum fip_vn2vn_subcode {
 enum fip_flag {
        FIP_FL_FPMA =   0x8000,         /* supports FPMA fabric-provided MACs */
        FIP_FL_SPMA =   0x4000,         /* supports SPMA server-provided MACs */
+       FIP_FL_FCF =    0x0020,         /* originated from a controlling FCF */
+       FIP_FL_FDF =    0x0010,         /* originated from an FDF */
        FIP_FL_REC_OR_P2P = 0x0008,     /* configured addr or point-to-point */
        FIP_FL_AVAIL =  0x0004,         /* available for FLOGI/ELP */
        FIP_FL_SOL =    0x0002,         /* this is a solicited message */
@@ -161,7 +164,9 @@ enum fip_desc_type {
        FIP_DT_VLAN =   14,             /* vlan number */
        FIP_DT_FC4F =   15,             /* FC-4 features */
        FIP_DT_LIMIT,                   /* max defined desc_type + 1 */
-       FIP_DT_VENDOR_BASE = 128,       /* first vendor-specific desc_type */
+       FIP_DT_NON_CRITICAL = 128,      /* First non-critical descriptor */
+       FIP_DT_CLR_VLINKS = 128,        /* Clear virtual links reason code */
+       FIP_DT_VENDOR_BASE = 241,       /* first vendor-specific desc_type */
 };
 
 /*
@@ -258,6 +263,14 @@ enum fip_fka_flags {
 
 /* FIP_DT_FKA flags */
 
+/*
+ * FIP_DT_VLAN descriptor
+ */
+struct fip_vlan_desc {
+       struct fip_desc fd_desc;
+       __be16          fd_vlan; /* Note: highest 4 bytes are unused */
+} __attribute__((packed));
+
 /*
  * FIP_DT_FC4F - FC-4 features.
  */
index 93d14daf0994725822461a8dbe36e97d52f56e51..7428a53257ca34683d2d9895c79ee46bcb1ea032 100644 (file)
@@ -878,6 +878,7 @@ struct fc_lport {
        struct libfc_function_template tt;
        u8                             link_up;
        u8                             qfull;
+       u16                            vlan;
        enum fc_lport_state            state;
        unsigned long                  boot_time;
        struct fc_host_statistics      host_stats;
index de7e3ee60f0cd845f518a331fbd5bdc35a776457..722d3264d3bf92b42077eafc25aeff6477df12a5 100644 (file)
@@ -78,10 +78,12 @@ enum fip_state {
  * The mode is the state that is to be entered after link up.
  * It must not change after fcoe_ctlr_init() sets it.
  */
-#define FIP_MODE_AUTO          FIP_ST_AUTO
-#define FIP_MODE_NON_FIP       FIP_ST_NON_FIP
-#define FIP_MODE_FABRIC                FIP_ST_ENABLED
-#define FIP_MODE_VN2VN         FIP_ST_VNMP_START
+enum fip_mode {
+       FIP_MODE_AUTO = FIP_ST_AUTO,
+       FIP_MODE_NON_FIP,
+       FIP_MODE_FABRIC,
+       FIP_MODE_VN2VN,
+};
 
 /**
  * struct fcoe_ctlr - FCoE Controller and FIP state
@@ -108,8 +110,10 @@ enum fip_state {
  * @flogi_req_send: send of FLOGI requested
  * @flogi_count:   number of FLOGI attempts in AUTO mode.
  * @map_dest:     use the FC_MAP mode for destination MAC addresses.
+ * @fip_resp:     start FIP VLAN discovery responder
  * @spma:         supports SPMA server-provided MACs mode
  * @probe_tries:   number of FC_IDs probed
+ * @priority:      DCBx FCoE APP priority
  * @dest_addr:    MAC address of the selected FC forwarder.
  * @ctl_src_addr:  the native MAC address of our local port.
  * @send:         LLD-supplied function to handle sending FIP Ethernet frames
@@ -124,7 +128,7 @@ enum fip_state {
  */
 struct fcoe_ctlr {
        enum fip_state state;
-       enum fip_state mode;
+       enum fip_mode mode;
        struct fc_lport *lp;
        struct fcoe_fcf *sel_fcf;
        struct list_head fcfs;
@@ -147,7 +151,8 @@ struct fcoe_ctlr {
        u16 flogi_oxid;
        u8 flogi_req_send;
        u8 flogi_count;
-       u8 map_dest;
+       bool map_dest;
+       bool fip_resp;
        u8 spma;
        u8 probe_tries;
        u8 priority;
@@ -311,7 +316,7 @@ struct fcoe_transport {
        struct list_head list;
        bool (*match) (struct net_device *device);
        int (*alloc) (struct net_device *device);
-       int (*create) (struct net_device *device, enum fip_state fip_mode);
+       int (*create) (struct net_device *device, enum fip_mode fip_mode);
        int (*destroy) (struct net_device *device);
        int (*enable) (struct net_device *device);
        int (*disable) (struct net_device *device);
@@ -319,14 +324,16 @@ struct fcoe_transport {
 
 /**
  * struct fcoe_percpu_s - The context for FCoE receive thread(s)
- * @thread:        The thread context
+ * @kthread:       The thread context (used by bnx2fc)
+ * @work:          The work item (used by fcoe)
  * @fcoe_rx_list:   The queue of pending packets to process
  * @page:          The memory page for calculating frame trailer CRCs
  * @crc_eof_offset: The offset into the CRC page pointing to available
  *                 memory for a new trailer
  */
 struct fcoe_percpu_s {
-       struct task_struct *thread;
+       struct task_struct *kthread;
+       struct work_struct work;
        struct sk_buff_head fcoe_rx_list;
        struct page *crc_eof_page;
        int crc_eof_offset;
index a6c346df290d26fe0be34bdcd5bda2fc6bcff125..8a95631448905022c8ca3ce5df8c6dc09221d390 100644 (file)
@@ -94,7 +94,6 @@ struct scsi_device {
        spinlock_t list_lock;
        struct list_head cmd_list;      /* queue of in use SCSI Command structures */
        struct list_head starved_entry;
-       struct scsi_cmnd *current_cmnd; /* currently active command */
        unsigned short queue_depth;     /* How deep of a queue we want */
        unsigned short max_queue_depth; /* max queue depth */
        unsigned short last_queue_full_depth; /* These two are used by */
index 76e9d278c3341bf95e1399090b1c4e268abab1a0..0dee7afa93d6621881b2f6a4afb6828a4b5f8d63 100644 (file)
@@ -495,9 +495,6 @@ struct scsi_host_template {
         */
        unsigned int cmd_size;
        struct scsi_host_cmd_pool *cmd_pool;
-
-       /* temporary flag to disable blk-mq I/O path */
-       bool disable_blk_mq;
 };
 
 /*
@@ -778,7 +775,8 @@ extern bool scsi_use_blk_mq;
 
 static inline bool shost_use_blk_mq(struct Scsi_Host *shost)
 {
-       return shost->use_blk_mq;
+       return scsi_use_blk_mq;
+
 }
 
 extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);