]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'jejb-scsi' into misc
authorJames Bottomley <James.Bottomley@HansenPartnership.com>
Thu, 7 Jan 2016 23:51:13 +0000 (15:51 -0800)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Thu, 7 Jan 2016 23:51:13 +0000 (15:51 -0800)
107 files changed:
Documentation/devicetree/bindings/scsi/hisilicon-sas.txt [new file with mode: 0644]
MAINTAINERS
drivers/block/cciss.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/aacraid/linit.c
drivers/scsi/aic94xx/aic94xx_sas.h
drivers/scsi/arcmsr/arcmsr.h
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/atp870u.c
drivers/scsi/atp870u.h
drivers/scsi/bfa/bfa.h
drivers/scsi/bfa/bfa_core.c
drivers/scsi/bfa/bfa_cs.h
drivers/scsi/bfa/bfa_defs.h
drivers/scsi/bfa/bfa_defs_fcs.h
drivers/scsi/bfa/bfa_defs_svc.h
drivers/scsi/bfa/bfa_fc.h
drivers/scsi/bfa/bfa_fcbuild.c
drivers/scsi/bfa/bfa_fcbuild.h
drivers/scsi/bfa/bfa_fcpim.c
drivers/scsi/bfa/bfa_fcpim.h
drivers/scsi/bfa/bfa_fcs.c
drivers/scsi/bfa/bfa_fcs.h
drivers/scsi/bfa/bfa_fcs_fcpim.c
drivers/scsi/bfa/bfa_fcs_lport.c
drivers/scsi/bfa/bfa_fcs_rport.c
drivers/scsi/bfa/bfa_hw_cb.c
drivers/scsi/bfa/bfa_hw_ct.c
drivers/scsi/bfa/bfa_ioc.c
drivers/scsi/bfa/bfa_ioc.h
drivers/scsi/bfa/bfa_ioc_cb.c
drivers/scsi/bfa/bfa_ioc_ct.c
drivers/scsi/bfa/bfa_modules.h
drivers/scsi/bfa/bfa_plog.h
drivers/scsi/bfa/bfa_port.c
drivers/scsi/bfa/bfa_port.h
drivers/scsi/bfa/bfa_svc.c
drivers/scsi/bfa/bfa_svc.h
drivers/scsi/bfa/bfad.c
drivers/scsi/bfa/bfad_attr.c
drivers/scsi/bfa/bfad_bsg.c
drivers/scsi/bfa/bfad_bsg.h
drivers/scsi/bfa/bfad_debugfs.c
drivers/scsi/bfa/bfad_drv.h
drivers/scsi/bfa/bfad_im.c
drivers/scsi/bfa/bfad_im.h
drivers/scsi/bfa/bfi.h
drivers/scsi/bfa/bfi_ms.h
drivers/scsi/bfa/bfi_reg.h
drivers/scsi/cxlflash/common.h
drivers/scsi/cxlflash/main.c
drivers/scsi/cxlflash/main.h
drivers/scsi/cxlflash/superpipe.c
drivers/scsi/cxlflash/vlun.c
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/hisi_sas/Kconfig [new file with mode: 0644]
drivers/scsi/hisi_sas/Makefile [new file with mode: 0644]
drivers/scsi/hisi_sas/hisi_sas.h [new file with mode: 0644]
drivers/scsi/hisi_sas/hisi_sas_main.c [new file with mode: 0644]
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c [new file with mode: 0644]
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h
drivers/scsi/hpsa_cmd.h
drivers/scsi/initio.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mem.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/lpfc/lpfc_vport.c
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mvsas/mv_94xx.c
drivers/scsi/mvsas/mv_94xx.h
drivers/scsi/mvsas/mv_init.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h
drivers/scsi/osd/osd_initiator.c
drivers/scsi/qla2xxx/Kconfig
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_dh.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/st.h
drivers/scsi/storvsc_drv.c
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/scsi/vmw_pvscsi.c
drivers/scsi/vmw_pvscsi.h
include/scsi/sas.h
include/scsi/scsi_dbg.h
include/scsi/scsi_device.h
include/uapi/scsi/cxlflash_ioctl.h

diff --git a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
new file mode 100644 (file)
index 0000000..f67e761
--- /dev/null
@@ -0,0 +1,69 @@
+* HiSilicon SAS controller
+
+The HiSilicon SAS controller supports SAS/SATA.
+
+Main node required properties:
+  - compatible : value should be as follows:
+       (a) "hisilicon,hip05-sas-v1" for v1 hw in hip05 chipset
+  - sas-addr : array of 8 bytes for host SAS address
+  - reg : Address and length of the SAS register
+  - hisilicon,sas-syscon: phandle of syscon used for sas control
+  - ctrl-reset-reg : offset to controller reset register in ctrl reg
+  - ctrl-reset-sts-reg : offset to controller reset status register in ctrl reg
+  - ctrl-clock-ena-reg : offset to controller clock enable register in ctrl reg
+  - queue-count : number of delivery and completion queues in the controller
+  - phy-count : number of phys accessible by the controller
+  - interrupts : Interrupts for phys, completion queues, and fatal
+               sources; the interrupts are ordered in 3 groups, as follows:
+                       - Phy interrupts
+                       - Completion queue interrupts
+                       - Fatal interrupts
+               Phy interrupts : Each phy has 3 interrupt sources:
+                       - broadcast
+                       - phyup
+                       - abnormal
+               The phy interrupts are ordered into groups of 3 per phy
+               (broadcast, phyup, and abnormal) in increasing order.
+               Completion queue interrupts : each completion queue has 1
+                       interrupt source.
+                       The interrupts are ordered in increasing order.
+               Fatal interrupts : the fatal interrupts are ordered as follows:
+                       - ECC
+                       - AXI bus
+
+Example:
+       sas0: sas@c1000000 {
+               compatible = "hisilicon,hip05-sas-v1";
+               sas-addr = [50 01 88 20 16 00 00 0a];
+               reg = <0x0 0xc1000000 0x0 0x10000>;
+               hisilicon,sas-syscon = <&pcie_sas>;
+               ctrl-reset-reg = <0xa60>;
+               ctrl-reset-sts-reg = <0x5a30>;
+               ctrl-clock-ena-reg = <0x338>;
+               queue-count = <32>;
+               phy-count = <8>;
+               dma-coherent;
+               interrupt-parent = <&mbigen_dsa>;
+               interrupts =    <259 4>,<263 4>,<264 4>,/* phy0 */
+                               <269 4>,<273 4>,<274 4>,/* phy1 */
+                               <279 4>,<283 4>,<284 4>,/* phy2 */
+                               <289 4>,<293 4>,<294 4>,/* phy3 */
+                               <299 4>,<303 4>,<304 4>,/* phy4 */
+                               <309 4>,<313 4>,<314 4>,/* phy5 */
+                               <319 4>,<323 4>,<324 4>,/* phy6 */
+                               <329 4>,<333 4>,<334 4>,/* phy7 */
+                               <336 1>,<337 1>,<338 1>,/* cq0-2 */
+                               <339 1>,<340 1>,<341 1>,/* cq3-5 */
+                               <342 1>,<343 1>,<344 1>,/* cq6-8 */
+                               <345 1>,<346 1>,<347 1>,/* cq9-11 */
+                               <348 1>,<349 1>,<350 1>,/* cq12-14 */
+                               <351 1>,<352 1>,<353 1>,/* cq15-17 */
+                               <354 1>,<355 1>,<356 1>,/* cq18-20 */
+                               <357 1>,<358 1>,<359 1>,/* cq21-23 */
+                               <360 1>,<361 1>,<362 1>,/* cq24-26 */
+                               <363 1>,<364 1>,<365 1>,/* cq27-29 */
+                               <366 1>,<367 1>/* cq30-31 */
+                               <376 4>,/* fatal ecc */
+                               <381 4>;/* fatal axi */
+               status = "disabled";
+       };
index 69c8a9c3289adbe64a7e68e134372515d1fd2e0f..6769e771ea67383b2e322743177afddbf80a4e65 100644 (file)
@@ -5038,6 +5038,13 @@ F:       include/uapi/linux/if_hippi.h
 F:     net/802/hippi.c
 F:     drivers/net/hippi/
 
+HISILICON SAS Controller
+M:     John Garry <john.garry@huawei.com>
+W:     http://www.hisilicon.com
+S:     Supported
+F:     drivers/scsi/hisi_sas/
+F:     Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
+
 HOST AP DRIVER
 M:     Jouni Malinen <j@w1.fi>
 L:     hostap@shmoo.com (subscribers-only)
index 0422c47261c3a06ad7bc6796d09ae5a84603a514..2758982ac19364a54ef6723179d236d9e359d082 100644 (file)
@@ -3854,7 +3854,7 @@ static void print_cfg_table(ctlr_info_t *h)
               readl(&(tb->HostWrite.CoalIntDelay)));
        dev_dbg(&h->pdev->dev, "   Coalesce Interrupt Count = 0x%x\n",
               readl(&(tb->HostWrite.CoalIntCount)));
-       dev_dbg(&h->pdev->dev, "   Max outstanding commands = 0x%d\n",
+       dev_dbg(&h->pdev->dev, "   Max outstanding commands = 0x%x\n",
               readl(&(tb->CmdsOutMax)));
        dev_dbg(&h->pdev->dev, "   Bus Types = 0x%x\n",
                readl(&(tb->BusTypes)));
index 90cd7cd6d130b1d55cd8a068de0165b1488a4726..c1fe0d2f90ca353722cf7e2b16c2bd2c9b47601b 100644 (file)
@@ -475,6 +475,7 @@ config SCSI_AACRAID
 source "drivers/scsi/aic7xxx/Kconfig.aic7xxx"
 source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
 source "drivers/scsi/aic94xx/Kconfig"
+source "drivers/scsi/hisi_sas/Kconfig"
 source "drivers/scsi/mvsas/Kconfig"
 
 config SCSI_MVUMI
index c14bca4a9675c1d1ce29d759354cd8a835bdf98d..862ab4efad61e90de24c506675801ec8d16ecff5 100644 (file)
@@ -157,6 +157,7 @@ obj-$(CONFIG_CHR_DEV_SCH)   += ch.o
 obj-$(CONFIG_SCSI_ENCLOSURE)   += ses.o
 
 obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas/
 
 # This goes last, so that "real" scsi devices probe earlier
 obj-$(CONFIG_SCSI_DEBUG)       += scsi_debug.o
index 3b6e5c67e853d96aeafeee16859d19bfa3731a5b..76eaa38ffd6e5c4a9f40bd66fa4c1205e35ed739 100644 (file)
@@ -1318,7 +1318,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 }
 
 #if (defined(CONFIG_PM))
-void aac_release_resources(struct aac_dev *aac)
+static void aac_release_resources(struct aac_dev *aac)
 {
        int i;
 
index 912e6b755f74971c82a5a867cafbddd217e6f85b..101072cab70fcbc35e9943ab28aabce0dc21c9f4 100644 (file)
@@ -327,46 +327,9 @@ struct scb_header {
 
 #define LUN_SIZE                8
 
-/* See SAS spec, task IU
- */
-struct ssp_task_iu {
-       u8     lun[LUN_SIZE];     /* BE */
-       u16    _r_a;
-       u8     tmf;
-       u8     _r_b;
-       __be16 tag;               /* BE */
-       u8     _r_c[14];
-} __attribute__ ((packed));
-
-/* See SAS spec, command IU
- */
-struct ssp_command_iu {
-       u8     lun[LUN_SIZE];
-       u8     _r_a;
-       u8     efb_prio_attr;     /* enable first burst, task prio & attr */
-#define EFB_MASK        0x80
-#define TASK_PRIO_MASK 0x78
-#define TASK_ATTR_MASK  0x07
-
-       u8    _r_b;
-       u8     add_cdb_len;       /* in dwords, since bit 0,1 are reserved */
-       union {
-               u8     cdb[16];
-               struct {
-                       __le64 long_cdb_addr;     /* bus address, LE */
-                       __le32 long_cdb_size;     /* LE */
-                       u8     _r_c[3];
-                       u8     eol_ds;            /* eol:6,6, ds:5,4 */
-               } long_cdb;       /* sequencer extension */
-       };
-} __attribute__ ((packed));
-
-struct xfer_rdy_iu {
-       __be32 requested_offset;  /* BE */
-       __be32 write_data_len;    /* BE */
-       __be32 _r_a;
-} __attribute__ ((packed));
-
+#define EFB_MASK                0x80
+#define TASK_PRIO_MASK          0x78
+#define TASK_ATTR_MASK          0x07
 /* ---------- SCB tasks ---------- */
 
 /* This is both ssp_task and long_ssp_task
@@ -511,7 +474,7 @@ struct abort_task {
        u8     proto_conn_rate;
        __le32 _r_a;
        struct ssp_frame_hdr ssp_frame;
-       struct ssp_task_iu ssp_task;
+       struct ssp_tmf_iu ssp_task;
        __le16 sister_scb;
        __le16 conn_handle;
        u8     flags;     /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */
@@ -549,7 +512,7 @@ struct clear_nexus {
        u8     _r_b[3];
        u8     conn_mask;
        u8     _r_c[19];
-       struct ssp_task_iu ssp_task; /* LUN and TAG */
+       struct ssp_tmf_iu ssp_task; /* LUN and TAG */
        __le16 _r_d;
        __le16 conn_handle;
        __le64 _r_e;
@@ -562,7 +525,7 @@ struct initiate_ssp_tmf {
        u8     proto_conn_rate;
        __le32 _r_a;
        struct ssp_frame_hdr ssp_frame;
-       struct ssp_task_iu ssp_task;
+       struct ssp_tmf_iu ssp_task;
        __le16 sister_scb;
        __le16 conn_handle;
        u8     flags;     /* itnl override and suspend data tx */
index 3bcaaac0ae4bb5080b0d4c64223e20d7a8754dfa..cf99f8cf4cdd80cf0f27127e7e7ed50e426ee034 100644 (file)
@@ -52,7 +52,7 @@ struct device_attribute;
        #define ARCMSR_MAX_FREECCB_NUM  320
 #define ARCMSR_MAX_OUTSTANDING_CMD     255
 #endif
-#define ARCMSR_DRIVER_VERSION          "v1.30.00.04-20140919"
+#define ARCMSR_DRIVER_VERSION          "v1.30.00.22-20151126"
 #define ARCMSR_SCSI_INITIATOR_ID                                               255
 #define ARCMSR_MAX_XFER_SECTORS                                                        512
 #define ARCMSR_MAX_XFER_SECTORS_B                                              4096
@@ -74,6 +74,9 @@ struct device_attribute;
 #ifndef PCI_DEVICE_ID_ARECA_1214
        #define PCI_DEVICE_ID_ARECA_1214        0x1214
 #endif
+#ifndef PCI_DEVICE_ID_ARECA_1203
+       #define PCI_DEVICE_ID_ARECA_1203        0x1203
+#endif
 /*
 **********************************************************************************
 **
@@ -245,6 +248,12 @@ struct FIRMWARE_INFO
 /* window of "instruction flags" from iop to driver */
 #define ARCMSR_IOP2DRV_DOORBELL                       0x00020408
 #define ARCMSR_IOP2DRV_DOORBELL_MASK                  0x0002040C
+/* window of "instruction flags" from iop to driver */
+#define ARCMSR_IOP2DRV_DOORBELL_1203                  0x00021870
+#define ARCMSR_IOP2DRV_DOORBELL_MASK_1203             0x00021874
+/* window of "instruction flags" from driver to iop */
+#define ARCMSR_DRV2IOP_DOORBELL_1203                  0x00021878
+#define ARCMSR_DRV2IOP_DOORBELL_MASK_1203             0x0002187C
 /* ARECA FLAG LANGUAGE */
 /* ioctl transfer */
 #define ARCMSR_IOP2DRV_DATA_WRITE_OK                  0x00000001
@@ -288,6 +297,9 @@ struct FIRMWARE_INFO
 #define ARCMSR_MESSAGE_RBUFFER                       0x0000ff00
 /* iop message_rwbuffer for message command */
 #define ARCMSR_MESSAGE_RWBUFFER                              0x0000fa00
+
+#define MEM_BASE0(x)   (u32 __iomem *)((unsigned long)acb->mem_base0 + x)
+#define MEM_BASE1(x)   (u32 __iomem *)((unsigned long)acb->mem_base1 + x)
 /* 
 ************************************************************************
 **                SPEC. for Areca HBC adapter
index 333db5953607e49b284f780f1b4532c81fe5ea01..7640498964a5bb1169d676b20056497b6c705e15 100644 (file)
@@ -114,6 +114,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
 static const char *arcmsr_info(struct Scsi_Host *);
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
 static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *);
+static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb);
 static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
 {
        if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
@@ -157,6 +158,8 @@ static struct pci_device_id arcmsr_device_id_table[] = {
                .driver_data = ACB_ADAPTER_TYPE_B},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202),
                .driver_data = ACB_ADAPTER_TYPE_B},
+       {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1203),
+               .driver_data = ACB_ADAPTER_TYPE_B},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210),
                .driver_data = ACB_ADAPTER_TYPE_A},
        {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1214),
@@ -495,6 +498,91 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
        }
 }
 
+static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb)
+{
+       bool rtn = true;
+       void *dma_coherent;
+       dma_addr_t dma_coherent_handle;
+       struct pci_dev *pdev = acb->pdev;
+
+       switch (acb->adapter_type) {
+       case ACB_ADAPTER_TYPE_B: {
+               struct MessageUnit_B *reg;
+               acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
+               dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+                       &dma_coherent_handle, GFP_KERNEL);
+               if (!dma_coherent) {
+                       pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+                       return false;
+               }
+               acb->dma_coherent_handle2 = dma_coherent_handle;
+               acb->dma_coherent2 = dma_coherent;
+               reg = (struct MessageUnit_B *)dma_coherent;
+               acb->pmuB = reg;
+               if (acb->pdev->device == PCI_DEVICE_ID_ARECA_1203) {
+                       reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_1203);
+                       reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK_1203);
+                       reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_1203);
+                       reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK_1203);
+               } else {
+                       reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL);
+                       reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK);
+                       reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL);
+                       reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK);
+               }
+               reg->message_wbuffer = MEM_BASE1(ARCMSR_MESSAGE_WBUFFER);
+               reg->message_rbuffer = MEM_BASE1(ARCMSR_MESSAGE_RBUFFER);
+               reg->message_rwbuffer = MEM_BASE1(ARCMSR_MESSAGE_RWBUFFER);
+               }
+               break;
+       case ACB_ADAPTER_TYPE_D: {
+               struct MessageUnit_D *reg;
+
+               acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
+               dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+                       &dma_coherent_handle, GFP_KERNEL);
+               if (!dma_coherent) {
+                       pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+                       return false;
+               }
+               acb->dma_coherent_handle2 = dma_coherent_handle;
+               acb->dma_coherent2 = dma_coherent;
+               reg = (struct MessageUnit_D *)dma_coherent;
+               acb->pmuD = reg;
+               reg->chip_id = MEM_BASE0(ARCMSR_ARC1214_CHIP_ID);
+               reg->cpu_mem_config = MEM_BASE0(ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION);
+               reg->i2o_host_interrupt_mask = MEM_BASE0(ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK);
+               reg->sample_at_reset = MEM_BASE0(ARCMSR_ARC1214_SAMPLE_RESET);
+               reg->reset_request = MEM_BASE0(ARCMSR_ARC1214_RESET_REQUEST);
+               reg->host_int_status = MEM_BASE0(ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS);
+               reg->pcief0_int_enable = MEM_BASE0(ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE);
+               reg->inbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE0);
+               reg->inbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE1);
+               reg->outbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE0);
+               reg->outbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE1);
+               reg->inbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_INBOUND_DOORBELL);
+               reg->outbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL);
+               reg->outbound_doorbell_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE);
+               reg->inboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW);
+               reg->inboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH);
+               reg->inboundlist_write_pointer = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER);
+               reg->outboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW);
+               reg->outboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH);
+               reg->outboundlist_copy_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER);
+               reg->outboundlist_read_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER);
+               reg->outboundlist_interrupt_cause = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE);
+               reg->outboundlist_interrupt_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE);
+               reg->message_wbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_WBUFFER);
+               reg->message_rbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RBUFFER);
+               reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER);
+               }
+               break;
+       default:
+               break;
+       }
+       return rtn;
+}
+
 static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 {
        struct pci_dev *pdev = acb->pdev;
@@ -739,9 +827,12 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if(!error){
                goto pci_release_regs;
        }
+       error = arcmsr_alloc_io_queue(acb);
+       if (!error)
+               goto unmap_pci_region;
        error = arcmsr_get_firmware_spec(acb);
        if(!error){
-               goto unmap_pci_region;
+               goto free_hbb_mu;
        }
        error = arcmsr_alloc_ccb_pool(acb);
        if(error){
@@ -2622,9 +2713,6 @@ static bool arcmsr_hbaA_get_config(struct AdapterControlBlock *acb)
 static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_B *reg = acb->pmuB;
-       struct pci_dev *pdev = acb->pdev;
-       void *dma_coherent;
-       dma_addr_t dma_coherent_handle;
        char *acb_firm_model = acb->firm_model;
        char *acb_firm_version = acb->firm_version;
        char *acb_device_map = acb->device_map;
@@ -2636,30 +2724,16 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
        /*firm_version,21,84-99*/
        int count;
 
-       acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
-       dma_coherent = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
-                       &dma_coherent_handle, GFP_KERNEL);
-       if (!dma_coherent){
-               printk(KERN_NOTICE
-                       "arcmsr%d: dma_alloc_coherent got error for hbb mu\n",
-                       acb->host->host_no);
-               return false;
-       }
-       acb->dma_coherent_handle2 = dma_coherent_handle;
-       acb->dma_coherent2 = dma_coherent;
-       reg = (struct MessageUnit_B *)dma_coherent;
-       acb->pmuB = reg;
-       reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
-       reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
-       reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
-       reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
-       reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
-       reg->message_rbuffer =  (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
-       reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
        iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);  /*firm_model,15,60-67*/
        iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);        /*firm_version,17,68-83*/
        iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]);  /*firm_version,21,84-99*/
 
+       arcmsr_wait_firmware_ready(acb);
+       writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
+       if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+               printk(KERN_ERR "arcmsr%d: can't set driver mode.\n", acb->host->host_no);
+               return false;
+       }
        writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
        if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
                printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
@@ -2694,15 +2768,15 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
                acb->firm_model,
                acb->firm_version);
 
-       acb->signature = readl(&reg->message_rwbuffer[1]);
+       acb->signature = readl(&reg->message_rwbuffer[0]);
        /*firm_signature,1,00-03*/
-       acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
+       acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
        /*firm_request_len,1,04-07*/
-       acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
+       acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
        /*firm_numbers_queue,2,08-11*/
-       acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
+       acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
        /*firm_sdram_size,3,12-15*/
-       acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
+       acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
        /*firm_ide_channels,4,16-19*/
        acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/
        /*firm_ide_channels,4,16-19*/
@@ -2777,70 +2851,8 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
        char __iomem *iop_firm_version;
        char __iomem *iop_device_map;
        u32 count;
-       struct MessageUnit_D *reg;
-       void *dma_coherent2;
-       dma_addr_t dma_coherent_handle2;
-       struct pci_dev *pdev = acb->pdev;
+       struct MessageUnit_D *reg = acb->pmuD;
 
-       acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
-       dma_coherent2 = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
-               &dma_coherent_handle2, GFP_KERNEL);
-       if (!dma_coherent2) {
-               pr_notice("DMA allocation failed...\n");
-               return false;
-       }
-       memset(dma_coherent2, 0, acb->roundup_ccbsize);
-       acb->dma_coherent_handle2 = dma_coherent_handle2;
-       acb->dma_coherent2 = dma_coherent2;
-       reg = (struct MessageUnit_D *)dma_coherent2;
-       acb->pmuD = reg;
-       reg->chip_id = acb->mem_base0 + ARCMSR_ARC1214_CHIP_ID;
-       reg->cpu_mem_config = acb->mem_base0 +
-               ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION;
-       reg->i2o_host_interrupt_mask = acb->mem_base0 +
-               ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK;
-       reg->sample_at_reset = acb->mem_base0 + ARCMSR_ARC1214_SAMPLE_RESET;
-       reg->reset_request = acb->mem_base0 + ARCMSR_ARC1214_RESET_REQUEST;
-       reg->host_int_status = acb->mem_base0 +
-               ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS;
-       reg->pcief0_int_enable = acb->mem_base0 +
-               ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE;
-       reg->inbound_msgaddr0 = acb->mem_base0 +
-               ARCMSR_ARC1214_INBOUND_MESSAGE0;
-       reg->inbound_msgaddr1 = acb->mem_base0 +
-               ARCMSR_ARC1214_INBOUND_MESSAGE1;
-       reg->outbound_msgaddr0 = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_MESSAGE0;
-       reg->outbound_msgaddr1 = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_MESSAGE1;
-       reg->inbound_doorbell = acb->mem_base0 +
-               ARCMSR_ARC1214_INBOUND_DOORBELL;
-       reg->outbound_doorbell = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_DOORBELL;
-       reg->outbound_doorbell_enable = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE;
-       reg->inboundlist_base_low = acb->mem_base0 +
-               ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW;
-       reg->inboundlist_base_high = acb->mem_base0 +
-               ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH;
-       reg->inboundlist_write_pointer = acb->mem_base0 +
-               ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER;
-       reg->outboundlist_base_low = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW;
-       reg->outboundlist_base_high = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH;
-       reg->outboundlist_copy_pointer = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER;
-       reg->outboundlist_read_pointer = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER;
-       reg->outboundlist_interrupt_cause = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE;
-       reg->outboundlist_interrupt_enable = acb->mem_base0 +
-               ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE;
-       reg->message_wbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_WBUFFER;
-       reg->message_rbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_RBUFFER;
-       reg->msgcode_rwbuffer = acb->mem_base0 +
-               ARCMSR_ARC1214_MESSAGE_RWBUFFER;
        iop_firm_model = (char __iomem *)(&reg->msgcode_rwbuffer[15]);
        iop_firm_version = (char __iomem *)(&reg->msgcode_rwbuffer[17]);
        iop_device_map = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
@@ -2855,8 +2867,6 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
        if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
                pr_notice("arcmsr%d: wait get adapter firmware "
                        "miscellaneous data timeout\n", acb->host->host_no);
-               dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
-                       acb->dma_coherent2, acb->dma_coherent_handle2);
                return false;
        }
        count = 8;
@@ -2880,15 +2890,15 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
                iop_device_map++;
                count--;
        }
-       acb->signature = readl(&reg->msgcode_rwbuffer[1]);
+       acb->signature = readl(&reg->msgcode_rwbuffer[0]);
        /*firm_signature,1,00-03*/
-       acb->firm_request_len = readl(&reg->msgcode_rwbuffer[2]);
+       acb->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);
        /*firm_request_len,1,04-07*/
-       acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[3]);
+       acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]);
        /*firm_numbers_queue,2,08-11*/
-       acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[4]);
+       acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);
        /*firm_sdram_size,3,12-15*/
-       acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[5]);
+       acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);
        /*firm_hd_channels,4,16-19*/
        acb->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
        pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
@@ -3998,6 +4008,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
        case PCI_DEVICE_ID_ARECA_1160:
        case PCI_DEVICE_ID_ARECA_1170:
        case PCI_DEVICE_ID_ARECA_1201:
+       case PCI_DEVICE_ID_ARECA_1203:
        case PCI_DEVICE_ID_ARECA_1220:
        case PCI_DEVICE_ID_ARECA_1230:
        case PCI_DEVICE_ID_ARECA_1260:
index 05301bc752eee7e4bd2580e4ba58717bb9622fb2..8b52a9dbb9cf5a5fd18dd572f9459db57783b074 100644 (file)
 
 static struct scsi_host_template atp870u_template;
 static void send_s870(struct atp_unit *dev,unsigned char c);
-static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
-static void tscam_885(void);
+static void atp_is(struct atp_unit *dev, unsigned char c, bool wide_chip, unsigned char lvdmode);
+
+static inline void atp_writeb_base(struct atp_unit *atp, u8 reg, u8 val)
+{
+       outb(val, atp->baseport + reg);
+}
+
+static inline void atp_writew_base(struct atp_unit *atp, u8 reg, u16 val)
+{
+       outw(val, atp->baseport + reg);
+}
+
+static inline void atp_writeb_io(struct atp_unit *atp, u8 channel, u8 reg, u8 val)
+{
+       outb(val, atp->ioport[channel] + reg);
+}
+
+static inline void atp_writew_io(struct atp_unit *atp, u8 channel, u8 reg, u16 val)
+{
+       outw(val, atp->ioport[channel] + reg);
+}
+
+static inline void atp_writeb_pci(struct atp_unit *atp, u8 channel, u8 reg, u8 val)
+{
+       outb(val, atp->pciport[channel] + reg);
+}
+
+static inline void atp_writel_pci(struct atp_unit *atp, u8 channel, u8 reg, u32 val)
+{
+       outl(val, atp->pciport[channel] + reg);
+}
+
+static inline u8 atp_readb_base(struct atp_unit *atp, u8 reg)
+{
+       return inb(atp->baseport + reg);
+}
+
+static inline u16 atp_readw_base(struct atp_unit *atp, u8 reg)
+{
+       return inw(atp->baseport + reg);
+}
+
+static inline u32 atp_readl_base(struct atp_unit *atp, u8 reg)
+{
+       return inl(atp->baseport + reg);
+}
+
+static inline u8 atp_readb_io(struct atp_unit *atp, u8 channel, u8 reg)
+{
+       return inb(atp->ioport[channel] + reg);
+}
+
+static inline u16 atp_readw_io(struct atp_unit *atp, u8 channel, u8 reg)
+{
+       return inw(atp->ioport[channel] + reg);
+}
+
+static inline u8 atp_readb_pci(struct atp_unit *atp, u8 channel, u8 reg)
+{
+       return inb(atp->pciport[channel] + reg);
+}
+
+static inline bool is880(struct atp_unit *atp)
+{
+       return atp->pdev->device == ATP880_DEVID1 ||
+              atp->pdev->device == ATP880_DEVID2;
+}
+
+static inline bool is885(struct atp_unit *atp)
+{
+       return atp->pdev->device == ATP885_DEVID;
+}
 
 static irqreturn_t atp870u_intr_handle(int irq, void *dev_id)
 {
        unsigned long flags;
-       unsigned short int tmpcip, id;
+       unsigned short int id;
        unsigned char i, j, c, target_id, lun,cmdp;
        unsigned char *prd;
        struct scsi_cmnd *workreq;
-       unsigned int workport, tmport, tmport1;
        unsigned long adrcnt, k;
 #ifdef ED_DBGP
        unsigned long l;
 #endif
-       int errstus;
        struct Scsi_Host *host = dev_id;
        struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
 
        for (c = 0; c < 2; c++) {
-               tmport = dev->ioport[c] + 0x1f;
-               j = inb(tmport);
+               j = atp_readb_io(dev, c, 0x1f);
                if ((j & 0x80) != 0)
-               {                       
-                       goto ch_sel;
-               }
+                       break;
                dev->in_int[c] = 0;
        }
-       return IRQ_NONE;
-ch_sel:
+       if ((j & 0x80) == 0)
+               return IRQ_NONE;
 #ifdef ED_DBGP 
        printk("atp870u_intr_handle enter\n");
 #endif 
        dev->in_int[c] = 1;
-       cmdp = inb(dev->ioport[c] + 0x10);
-       workport = dev->ioport[c];
+       cmdp = atp_readb_io(dev, c, 0x10);
        if (dev->working[c] != 0) {
-               if (dev->dev_id == ATP885_DEVID) {
-                       tmport1 = workport + 0x16;
-                       if ((inb(tmport1) & 0x80) == 0)
-                               outb((inb(tmport1) | 0x80), tmport1);
+               if (is885(dev)) {
+                       if ((atp_readb_io(dev, c, 0x16) & 0x80) == 0)
+                               atp_writeb_io(dev, c, 0x16, (atp_readb_io(dev, c, 0x16) | 0x80));
                }               
-               tmpcip = dev->pciport[c];
-               if ((inb(tmpcip) & 0x08) != 0)
+               if ((atp_readb_pci(dev, c, 0x00) & 0x08) != 0)
                {
-                       tmpcip += 0x2;
                        for (k=0; k < 1000; k++) {
-                               if ((inb(tmpcip) & 0x08) == 0) {
-                                       goto stop_dma;
-                               }
-                               if ((inb(tmpcip) & 0x01) == 0) {
-                                       goto stop_dma;
-                               }
+                               if ((atp_readb_pci(dev, c, 2) & 0x08) == 0)
+                                       break;
+                               if ((atp_readb_pci(dev, c, 2) & 0x01) == 0)
+                                       break;
                        }
                }
-stop_dma:
-               tmpcip = dev->pciport[c];
-               outb(0x00, tmpcip);
-               tmport -= 0x08;
+               atp_writeb_pci(dev, c, 0, 0x00);
                
-               i = inb(tmport);
+               i = atp_readb_io(dev, c, 0x17);
                
-               if (dev->dev_id == ATP885_DEVID) {
-                       tmpcip += 2;
-                       outb(0x06, tmpcip);
-                       tmpcip -= 2;
-               }
+               if (is885(dev))
+                       atp_writeb_pci(dev, c, 2, 0x06);
 
-               tmport -= 0x02;
-               target_id = inb(tmport);
-               tmport += 0x02;
+               target_id = atp_readb_io(dev, c, 0x15);
 
                /*
                 *      Remap wide devices onto id numbers
@@ -129,7 +180,7 @@ stop_dma:
                     }
                     dev->last_cmd[c] |= 0x40;
                }
-               if (dev->dev_id == ATP885_DEVID) 
+               if (is885(dev))
                        dev->r1f[c][target_id] |= j;
 #ifdef ED_DBGP
                printk("atp870u_intr_handle status = %x\n",i);
@@ -138,12 +189,11 @@ stop_dma:
                        if ((dev->last_cmd[c] & 0xf0) != 0x40) {
                           dev->last_cmd[c] = 0xff;
                        }
-                       if (dev->dev_id == ATP885_DEVID) {
-                               tmport -= 0x05;
+                       if (is885(dev)) {
                                adrcnt = 0;
-                               ((unsigned char *) &adrcnt)[2] = inb(tmport++);
-                               ((unsigned char *) &adrcnt)[1] = inb(tmport++);
-                               ((unsigned char *) &adrcnt)[0] = inb(tmport);
+                               ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+                               ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+                               ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
                                if (dev->id[c][target_id].last_len != adrcnt)
                                {
                                        k = dev->id[c][target_id].last_len;
@@ -152,7 +202,7 @@ stop_dma:
                                dev->id[c][target_id].last_len = adrcnt;                           
                                }
 #ifdef ED_DBGP
-                               printk("tmport = %x dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",tmport,dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
+                               printk("dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
 #endif         
                        }
 
@@ -160,11 +210,9 @@ stop_dma:
                         *      Flip wide
                         */                     
                        if (dev->wide_id[c] != 0) {
-                               tmport = workport + 0x1b;
-                               outb(0x01, tmport);
-                               while ((inb(tmport) & 0x01) != 0x01) {
-                                       outb(0x01, tmport);
-                               }
+                               atp_writeb_io(dev, c, 0x1b, 0x01);
+                               while ((atp_readb_io(dev, c, 0x1b) & 0x01) != 0x01)
+                                       atp_writeb_io(dev, c, 0x1b, 0x01);
                        }               
                        /*
                         *      Issue more commands
@@ -185,37 +233,34 @@ stop_dma:
 #ifdef ED_DBGP
                                printk("Status 0x85 return\n");
 #endif                         
-                       goto handled;
+                       return IRQ_HANDLED;
                }
 
                if (i == 0x40) {
                     dev->last_cmd[c] |= 0x40;
                     dev->in_int[c] = 0;
-                    goto handled;
+                    return IRQ_HANDLED;
                }
 
                if (i == 0x21) {
                        if ((dev->last_cmd[c] & 0xf0) != 0x40) {
                           dev->last_cmd[c] = 0xff;
                        }
-                       tmport -= 0x05;
                        adrcnt = 0;
-                       ((unsigned char *) &adrcnt)[2] = inb(tmport++);
-                       ((unsigned char *) &adrcnt)[1] = inb(tmport++);
-                       ((unsigned char *) &adrcnt)[0] = inb(tmport);
+                       ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+                       ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+                       ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
                        k = dev->id[c][target_id].last_len;
                        k -= adrcnt;
                        dev->id[c][target_id].tran_len = k;
                        dev->id[c][target_id].last_len = adrcnt;
-                       tmport -= 0x04;
-                       outb(0x41, tmport);
-                       tmport += 0x08;
-                       outb(0x08, tmport);
+                       atp_writeb_io(dev, c, 0x10, 0x41);
+                       atp_writeb_io(dev, c, 0x18, 0x08);
                        dev->in_int[c] = 0;
-                       goto handled;
+                       return IRQ_HANDLED;
                }
 
-               if (dev->dev_id == ATP885_DEVID) {
+               if (is885(dev)) {
                        if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) {
                                if ((i == 0x4c) || (i == 0x8c)) 
                                        i=0x48;
@@ -229,11 +274,9 @@ stop_dma:
                        printk(KERN_DEBUG "Device reselect\n");
 #endif                 
                        lun = 0;
-                       tmport -= 0x07;
-                       if (cmdp == 0x44 || i==0x80) {
-                               tmport += 0x0d;
-                               lun = inb(tmport) & 0x07;
-                       } else {
+                       if (cmdp == 0x44 || i == 0x80)
+                               lun = atp_readb_io(dev, c, 0x1d) & 0x07;
+                       else {
                                if ((dev->last_cmd[c] & 0xf0) != 0x40) {
                                   dev->last_cmd[c] = 0xff;
                                }
@@ -241,49 +284,41 @@ stop_dma:
 #ifdef ED_DBGP
                                        printk("cmdp = 0x41\n");
 #endif                                         
-                                       tmport += 0x02;
                                        adrcnt = 0;
-                                       ((unsigned char *) &adrcnt)[2] = inb(tmport++);
-                                       ((unsigned char *) &adrcnt)[1] = inb(tmport++);
-                                       ((unsigned char *) &adrcnt)[0] = inb(tmport);
+                                       ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+                                       ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+                                       ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
                                        k = dev->id[c][target_id].last_len;
                                        k -= adrcnt;
                                        dev->id[c][target_id].tran_len = k;
                                        dev->id[c][target_id].last_len = adrcnt;
-                                       tmport += 0x04;
-                                       outb(0x08, tmport);
+                                       atp_writeb_io(dev, c, 0x18, 0x08);
                                        dev->in_int[c] = 0;
-                                       goto handled;
+                                       return IRQ_HANDLED;
                                } else {
 #ifdef ED_DBGP
                                        printk("cmdp != 0x41\n");
 #endif                                         
-                                       outb(0x46, tmport);
+                                       atp_writeb_io(dev, c, 0x10, 0x46);
                                        dev->id[c][target_id].dirct = 0x00;
-                                       tmport += 0x02;
-                                       outb(0x00, tmport++);
-                                       outb(0x00, tmport++);
-                                       outb(0x00, tmport++);
-                                       tmport += 0x03;
-                                       outb(0x08, tmport);
+                                       atp_writeb_io(dev, c, 0x12, 0x00);
+                                       atp_writeb_io(dev, c, 0x13, 0x00);
+                                       atp_writeb_io(dev, c, 0x14, 0x00);
+                                       atp_writeb_io(dev, c, 0x18, 0x08);
                                        dev->in_int[c] = 0;
-                                       goto handled;
+                                       return IRQ_HANDLED;
                                }
                        }
                        if (dev->last_cmd[c] != 0xff) {
                           dev->last_cmd[c] |= 0x40;
                        }
-                       if (dev->dev_id == ATP885_DEVID) {
-                               j = inb(dev->baseport + 0x29) & 0xfe;
-                               outb(j, dev->baseport + 0x29);
-                               tmport = workport + 0x16;
-                       } else {
-                               tmport = workport + 0x10;
-                               outb(0x45, tmport);
-                               tmport += 0x06;                         
-                       }
-                       
-                       target_id = inb(tmport);
+                       if (is885(dev)) {
+                               j = atp_readb_base(dev, 0x29) & 0xfe;
+                               atp_writeb_base(dev, 0x29, j);
+                       } else
+                               atp_writeb_io(dev, c, 0x10, 0x45);
+
+                       target_id = atp_readb_io(dev, c, 0x16);
                        /*
                         *      Remap wide identifiers
                         */
@@ -292,10 +327,8 @@ stop_dma:
                        } else {
                                target_id &= 0x07;
                        }
-                       if (dev->dev_id == ATP885_DEVID) {
-                               tmport = workport + 0x10;
-                               outb(0x45, tmport);
-                       }
+                       if (is885(dev))
+                               atp_writeb_io(dev, c, 0x10, 0x45);
                        workreq = dev->id[c][target_id].curr_req;
 #ifdef ED_DBGP                 
                        scmd_printk(KERN_DEBUG, workreq, "CDB");
@@ -304,18 +337,16 @@ stop_dma:
                        printk("\n");
 #endif 
                        
-                       tmport = workport + 0x0f;
-                       outb(lun, tmport);
-                       tmport += 0x02;
-                       outb(dev->id[c][target_id].devsp, tmport++);
+                       atp_writeb_io(dev, c, 0x0f, lun);
+                       atp_writeb_io(dev, c, 0x11, dev->id[c][target_id].devsp);
                        adrcnt = dev->id[c][target_id].tran_len;
                        k = dev->id[c][target_id].last_len;
 
-                       outb(((unsigned char *) &k)[2], tmport++);
-                       outb(((unsigned char *) &k)[1], tmport++);
-                       outb(((unsigned char *) &k)[0], tmport++);
+                       atp_writeb_io(dev, c, 0x12, ((unsigned char *) &k)[2]);
+                       atp_writeb_io(dev, c, 0x13, ((unsigned char *) &k)[1]);
+                       atp_writeb_io(dev, c, 0x14, ((unsigned char *) &k)[0]);
 #ifdef ED_DBGP                 
-                       printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(tmport-1), inb(tmport-2), inb(tmport-3));
+                       printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, atp_readb_io(dev, c, 0x14), atp_readb_io(dev, c, 0x13), atp_readb_io(dev, c, 0x12));
 #endif                 
                        /* Remap wide */
                        j = target_id;
@@ -324,35 +355,28 @@ stop_dma:
                        }
                        /* Add direction */
                        j |= dev->id[c][target_id].dirct;
-                       outb(j, tmport++);
-                       outb(0x80,tmport);
+                       atp_writeb_io(dev, c, 0x15, j);
+                       atp_writeb_io(dev, c, 0x16, 0x80);
                        
                        /* enable 32 bit fifo transfer */       
-                       if (dev->dev_id == ATP885_DEVID) {
-                               tmpcip = dev->pciport[c] + 1;
-                               i=inb(tmpcip) & 0xf3;
+                       if (is885(dev)) {
+                               i = atp_readb_pci(dev, c, 1) & 0xf3;
                                //j=workreq->cmnd[0];                           
                                if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
                                   i |= 0x0c;
                                }
-                               outb(i,tmpcip);                                         
-                       } else if ((dev->dev_id == ATP880_DEVID1) ||
-                                  (dev->dev_id == ATP880_DEVID2) ) {
-                               tmport = workport - 0x05;
-                               if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
-                                       outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
-                               } else {
-                                       outb((unsigned char) (inb(tmport) & 0x3f), tmport);
-                               }
+                               atp_writeb_pci(dev, c, 1, i);
+                       } else if (is880(dev)) {
+                               if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+                                       atp_writeb_base(dev, 0x3b, (atp_readb_base(dev, 0x3b) & 0x3f) | 0xc0);
+                               else
+                                       atp_writeb_base(dev, 0x3b, atp_readb_base(dev, 0x3b) & 0x3f);
                        } else {                                
-                               tmport = workport + 0x3a;
-                               if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
-                                       outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport);
-                               } else {
-                                       outb((unsigned char) (inb(tmport) & 0xf3), tmport);
-                               }                                                                                                               
+                               if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+                                       atp_writeb_base(dev, 0x3a, (atp_readb_base(dev, 0x3a) & 0xf3) | 0x08);
+                               else
+                                       atp_writeb_base(dev, 0x3a, atp_readb_base(dev, 0x3a) & 0xf3);
                        }       
-                       tmport = workport + 0x1b;
                        j = 0;
                        id = 1;
                        id = id << target_id;
@@ -362,18 +386,16 @@ stop_dma:
                        if ((id & dev->wide_id[c]) != 0) {
                                j |= 0x01;
                        }
-                       outb(j, tmport);
-                       while ((inb(tmport) & 0x01) != j) {
-                               outb(j,tmport);
-                       }
+                       atp_writeb_io(dev, c, 0x1b, j);
+                       while ((atp_readb_io(dev, c, 0x1b) & 0x01) != j)
+                               atp_writeb_io(dev, c, 0x1b, j);
                        if (dev->id[c][target_id].last_len == 0) {
-                               tmport = workport + 0x18;
-                               outb(0x08, tmport);
+                               atp_writeb_io(dev, c, 0x18, 0x08);
                                dev->in_int[c] = 0;
 #ifdef ED_DBGP
                                printk("dev->id[c][target_id].last_len = 0\n");
 #endif                                 
-                               goto handled;
+                               return IRQ_HANDLED;
                        }
 #ifdef ED_DBGP
                        printk("target_id = %d adrcnt = %d\n",target_id,adrcnt);
@@ -401,39 +423,33 @@ stop_dma:
                                        }
                                }                               
                        }
-                       tmpcip = dev->pciport[c] + 0x04;
-                       outl(dev->id[c][target_id].prdaddr, tmpcip);
+                       atp_writel_pci(dev, c, 0x04, dev->id[c][target_id].prdaddr);
 #ifdef ED_DBGP
                        printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr);
 #endif
-                       if (dev->dev_id == ATP885_DEVID) {
-                               tmpcip -= 0x04;
-                       } else {
-                               tmpcip -= 0x02;
-                               outb(0x06, tmpcip);
-                               outb(0x00, tmpcip);
-                               tmpcip -= 0x02;
+                       if (!is885(dev)) {
+                               atp_writeb_pci(dev, c, 2, 0x06);
+                               atp_writeb_pci(dev, c, 2, 0x00);
                        }
-                       tmport = workport + 0x18;
                        /*
                         *      Check transfer direction
                         */
                        if (dev->id[c][target_id].dirct != 0) {
-                               outb(0x08, tmport);
-                               outb(0x01, tmpcip);
+                               atp_writeb_io(dev, c, 0x18, 0x08);
+                               atp_writeb_pci(dev, c, 0, 0x01);
                                dev->in_int[c] = 0;
 #ifdef ED_DBGP
                                printk("status 0x80 return dirct != 0\n");
 #endif                         
-                               goto handled;
+                               return IRQ_HANDLED;
                        }
-                       outb(0x08, tmport);
-                       outb(0x09, tmpcip);
+                       atp_writeb_io(dev, c, 0x18, 0x08);
+                       atp_writeb_pci(dev, c, 0, 0x09);
                        dev->in_int[c] = 0;
 #ifdef ED_DBGP
                        printk("status 0x80 return dirct = 0\n");
 #endif                 
-                       goto handled;
+                       return IRQ_HANDLED;
                }
 
                /*
@@ -442,31 +458,22 @@ stop_dma:
 
                workreq = dev->id[c][target_id].curr_req;
 
-               if (i == 0x42) {
-                       if ((dev->last_cmd[c] & 0xf0) != 0x40)
-                       {
-                          dev->last_cmd[c] = 0xff;
-                       }
-                       errstus = 0x02;
-                       workreq->result = errstus;
-                       goto go_42;
-               }
-               if (i == 0x16) {
+               if (i == 0x42 || i == 0x16) {
                        if ((dev->last_cmd[c] & 0xf0) != 0x40) {
                           dev->last_cmd[c] = 0xff;
                        }
-                       errstus = 0;
-                       tmport -= 0x08;
-                       errstus = inb(tmport);
-                       if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) {
-                          printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
-                          errstus = 0x02;
-                       }
-                       workreq->result = errstus;
-go_42:
-                       if (dev->dev_id == ATP885_DEVID) {              
-                               j = inb(dev->baseport + 0x29) | 0x01;
-                               outb(j, dev->baseport + 0x29);
+                       if (i == 0x16) {
+                               workreq->result = atp_readb_io(dev, c, 0x0f);
+                               if (((dev->r1f[c][target_id] & 0x10) != 0) && is885(dev)) {
+                                       printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
+                                       workreq->result = 0x02;
+                               }
+                       } else
+                               workreq->result = 0x02;
+
+                       if (is885(dev)) {
+                               j = atp_readb_base(dev, 0x29) | 0x01;
+                               atp_writeb_base(dev, 0x29, j);
                        }
                        /*
                         *      Complete the command
@@ -488,11 +495,9 @@ go_42:
                         *      Take it back wide
                         */
                        if (dev->wide_id[c] != 0) {
-                               tmport = workport + 0x1b;
-                               outb(0x01, tmport);
-                               while ((inb(tmport) & 0x01) != 0x01) {
-                                       outb(0x01, tmport);
-                               }       
+                               atp_writeb_io(dev, c, 0x1b, 0x01);
+                               while ((atp_readb_io(dev, c, 0x1b) & 0x01) != 0x01)
+                                       atp_writeb_io(dev, c, 0x1b, 0x01);
                        } 
                        /*
                         *      If there is stuff to send and nothing going then send it
@@ -507,7 +512,7 @@ go_42:
                        }
                        spin_unlock_irqrestore(dev->host->host_lock, flags);
                        dev->in_int[c] = 0;
-                       goto handled;
+                       return IRQ_HANDLED;
                }
                if ((dev->last_cmd[c] & 0xf0) != 0x40) {
                   dev->last_cmd[c] = 0xff;
@@ -517,84 +522,54 @@ go_42:
                }
                i &= 0x0f;
                if (i == 0x09) {
-                       tmpcip += 4;
-                       outl(dev->id[c][target_id].prdaddr, tmpcip);
-                       tmpcip = tmpcip - 2;
-                       outb(0x06, tmpcip);
-                       outb(0x00, tmpcip);
-                       tmpcip = tmpcip - 2;
-                       tmport = workport + 0x10;
-                       outb(0x41, tmport);
-                       if (dev->dev_id == ATP885_DEVID) {
-                               tmport += 2;
+                       atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+                       atp_writeb_pci(dev, c, 2, 0x06);
+                       atp_writeb_pci(dev, c, 2, 0x00);
+                       atp_writeb_io(dev, c, 0x10, 0x41);
+                       if (is885(dev)) {
                                k = dev->id[c][target_id].last_len;
-                               outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
-                               outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
-                               outb((unsigned char) (((unsigned char *) (&k))[0]), tmport);
+                               atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&k))[2]);
+                               atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&k))[1]);
+                               atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&k))[0]);
                                dev->id[c][target_id].dirct = 0x00;
-                               tmport += 0x04;
                        } else {
                                dev->id[c][target_id].dirct = 0x00;
-                               tmport += 0x08;                         
                        }
-                       outb(0x08, tmport);
-                       outb(0x09, tmpcip);
+                       atp_writeb_io(dev, c, 0x18, 0x08);
+                       atp_writeb_pci(dev, c, 0, 0x09);
                        dev->in_int[c] = 0;
-                       goto handled;
+                       return IRQ_HANDLED;
                }
                if (i == 0x08) {
-                       tmpcip += 4;
-                       outl(dev->id[c][target_id].prdaddr, tmpcip);
-                       tmpcip = tmpcip - 2;
-                       outb(0x06, tmpcip);
-                       outb(0x00, tmpcip);
-                       tmpcip = tmpcip - 2;
-                       tmport = workport + 0x10;
-                       outb(0x41, tmport);
-                       if (dev->dev_id == ATP885_DEVID) {              
-                               tmport += 2;
+                       atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+                       atp_writeb_pci(dev, c, 2, 0x06);
+                       atp_writeb_pci(dev, c, 2, 0x00);
+                       atp_writeb_io(dev, c, 0x10, 0x41);
+                       if (is885(dev)) {
                                k = dev->id[c][target_id].last_len;
-                               outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
-                               outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
-                               outb((unsigned char) (((unsigned char *) (&k))[0]), tmport++);
-                       } else {
-                               tmport += 5;
+                               atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&k))[2]);
+                               atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&k))[1]);
+                               atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&k))[0]);
                        }
-                       outb((unsigned char) (inb(tmport) | 0x20), tmport);
+                       atp_writeb_io(dev, c, 0x15, atp_readb_io(dev, c, 0x15) | 0x20);
                        dev->id[c][target_id].dirct = 0x20;
-                       tmport += 0x03;
-                       outb(0x08, tmport);
-                       outb(0x01, tmpcip);
+                       atp_writeb_io(dev, c, 0x18, 0x08);
+                       atp_writeb_pci(dev, c, 0, 0x01);
                        dev->in_int[c] = 0;
-                       goto handled;
-               }
-               tmport -= 0x07;
-               if (i == 0x0a) {
-                       outb(0x30, tmport);
-               } else {
-                       outb(0x46, tmport);
+                       return IRQ_HANDLED;
                }
+               if (i == 0x0a)
+                       atp_writeb_io(dev, c, 0x10, 0x30);
+               else
+                       atp_writeb_io(dev, c, 0x10, 0x46);
                dev->id[c][target_id].dirct = 0x00;
-               tmport += 0x02;
-               outb(0x00, tmport++);
-               outb(0x00, tmport++);
-               outb(0x00, tmport++);
-               tmport += 0x03;
-               outb(0x08, tmport);
-               dev->in_int[c] = 0;
-               goto handled;
-       } else {
-//             tmport = workport + 0x17;
-//             inb(tmport);
-//             dev->working[c] = 0;
-               dev->in_int[c] = 0;
-               goto handled;
+               atp_writeb_io(dev, c, 0x12, 0x00);
+               atp_writeb_io(dev, c, 0x13, 0x00);
+               atp_writeb_io(dev, c, 0x14, 0x00);
+               atp_writeb_io(dev, c, 0x18, 0x08);
        }
-       
-handled:
-#ifdef ED_DBGP
-       printk("atp870u_intr_handle exit\n");
-#endif                 
+       dev->in_int[c] = 0;
+
        return IRQ_HANDLED;
 }
 /**
@@ -608,7 +583,7 @@ static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
                         void (*done) (struct scsi_cmnd *))
 {
        unsigned char c;
-       unsigned int tmport,m;  
+       unsigned int m;
        struct atp_unit *dev;
        struct Scsi_Host *host;
 
@@ -677,11 +652,10 @@ static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
                return 0;
        }
        dev->quereq[c][dev->quend[c]] = req_p;
-       tmport = dev->ioport[c] + 0x1c;
 #ifdef ED_DBGP 
-       printk("dev->ioport[c] = %x inb(tmport) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(tmport),c,dev->in_int[c],c,dev->in_snd[c]);
+       printk("dev->ioport[c] = %x atp_readb_io(dev, c, 0x1c) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],atp_readb_io(dev, c, 0x1c),c,dev->in_int[c],c,dev->in_snd[c]);
 #endif
-       if ((inb(tmport) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
+       if ((atp_readb_io(dev, c, 0x1c) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
 #ifdef ED_DBGP
                printk("Call sent_s870(atp870u_queuecommand)\n");
 #endif         
@@ -706,14 +680,12 @@ static DEF_SCSI_QCMD(atp870u_queuecommand)
  */
 static void send_s870(struct atp_unit *dev,unsigned char c)
 {
-       unsigned int tmport;
-       struct scsi_cmnd *workreq;
+       struct scsi_cmnd *workreq = NULL;
        unsigned int i;//,k;
        unsigned char  j, target_id;
        unsigned char *prd;
-       unsigned short int tmpcip, w;
+       unsigned short int w;
        unsigned long l, bttl = 0;
-       unsigned int workport;
        unsigned long  sg_count;
 
        if (dev->in_snd[c] != 0) {
@@ -729,53 +701,42 @@ static void send_s870(struct atp_unit *dev,unsigned char c)
        if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) {
                dev->last_cmd[c] &= 0x0f;
                workreq = dev->id[c][dev->last_cmd[c]].curr_req;
-               if (workreq != NULL) {  /* check NULL pointer */
-                  goto cmd_subp;
-               }
-               dev->last_cmd[c] = 0xff;        
-               if (dev->quhd[c] == dev->quend[c]) {
-                       dev->in_snd[c] = 0;
-                       return ;
+               if (!workreq) {
+                       dev->last_cmd[c] = 0xff;
+                       if (dev->quhd[c] == dev->quend[c]) {
+                               dev->in_snd[c] = 0;
+                               return;
+                       }
                }
        }
-       if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
-               dev->in_snd[c] = 0;
-               return ;
-       }
-       dev->working[c]++;
-       j = dev->quhd[c];
-       dev->quhd[c]++;
-       if (dev->quhd[c] >= qcnt) {
-               dev->quhd[c] = 0;
-       }
-       workreq = dev->quereq[c][dev->quhd[c]];
-       if (dev->id[c][scmd_id(workreq)].curr_req == NULL) {
+       if (!workreq) {
+               if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
+                       dev->in_snd[c] = 0;
+                       return;
+               }
+               dev->working[c]++;
+               j = dev->quhd[c];
+               dev->quhd[c]++;
+               if (dev->quhd[c] >= qcnt)
+                       dev->quhd[c] = 0;
+               workreq = dev->quereq[c][dev->quhd[c]];
+               if (dev->id[c][scmd_id(workreq)].curr_req != NULL) {
+                       dev->quhd[c] = j;
+                       dev->working[c]--;
+                       dev->in_snd[c] = 0;
+                       return;
+               }
                dev->id[c][scmd_id(workreq)].curr_req = workreq;
                dev->last_cmd[c] = scmd_id(workreq);
-               goto cmd_subp;
-       }       
-       dev->quhd[c] = j;
-       dev->working[c]--;
-       dev->in_snd[c] = 0;
-       return;
-cmd_subp:
-       workport = dev->ioport[c];
-       tmport = workport + 0x1f;
-       if ((inb(tmport) & 0xb0) != 0) {
-               goto abortsnd;
-       }
-       tmport = workport + 0x1c;
-       if (inb(tmport) == 0) {
-               goto oktosend;
        }
-abortsnd:
+       if ((atp_readb_io(dev, c, 0x1f) & 0xb0) != 0 || atp_readb_io(dev, c, 0x1c) != 0) {
 #ifdef ED_DBGP
-       printk("Abort to Send\n");
+               printk("Abort to Send\n");
 #endif
-       dev->last_cmd[c] |= 0x40;
-       dev->in_snd[c] = 0;
-       return;
-oktosend:
+               dev->last_cmd[c] |= 0x40;
+               dev->in_snd[c] = 0;
+               return;
+       }
 #ifdef ED_DBGP
        printk("OK to Send\n");
        scmd_printk(KERN_DEBUG, workreq, "CDB");
@@ -786,9 +747,9 @@ oktosend:
 #endif 
        l = scsi_bufflen(workreq);
 
-       if (dev->dev_id == ATP885_DEVID) {
-               j = inb(dev->baseport + 0x29) & 0xfe;
-               outb(j, dev->baseport + 0x29);
+       if (is885(dev)) {
+               j = atp_readb_base(dev, 0x29) & 0xfe;
+               atp_writeb_base(dev, 0x29, j);
                dev->r1f[c][scmd_id(workreq)] = 0;
        }
        
@@ -800,7 +761,6 @@ oktosend:
                l = 0;
        }
 
-       tmport = workport + 0x1b;
        j = 0;
        target_id = scmd_id(workreq);
 
@@ -812,9 +772,9 @@ oktosend:
        if ((w & dev->wide_id[c]) != 0) {
                j |= 0x01;
        }
-       outb(j, tmport);
-       while ((inb(tmport) & 0x01) != j) {
-               outb(j,tmport);
+       atp_writeb_io(dev, c, 0x1b, j);
+       while ((atp_readb_io(dev, c, 0x1b) & 0x01) != j) {
+               atp_writeb_pci(dev, c, 0x1b, j);
 #ifdef ED_DBGP
                printk("send_s870 while loop 1\n");
 #endif
@@ -823,24 +783,19 @@ oktosend:
         *      Write the command
         */
 
-       tmport = workport;
-       outb(workreq->cmd_len, tmport++);
-       outb(0x2c, tmport++);
-       if (dev->dev_id == ATP885_DEVID) {
-               outb(0x7f, tmport++);
-       } else {
-               outb(0xcf, tmport++);   
-       }       
-       for (i = 0; i < workreq->cmd_len; i++) {
-               outb(workreq->cmnd[i], tmport++);
-       }
-       tmport = workport + 0x0f;
-       outb(workreq->device->lun, tmport);
-       tmport += 0x02;
+       atp_writeb_io(dev, c, 0x00, workreq->cmd_len);
+       atp_writeb_io(dev, c, 0x01, 0x2c);
+       if (is885(dev))
+               atp_writeb_io(dev, c, 0x02, 0x7f);
+       else
+               atp_writeb_io(dev, c, 0x02, 0xcf);
+       for (i = 0; i < workreq->cmd_len; i++)
+               atp_writeb_io(dev, c, 0x03 + i, workreq->cmnd[i]);
+       atp_writeb_io(dev, c, 0x0f, workreq->device->lun);
        /*
         *      Write the target
         */
-       outb(dev->id[c][target_id].devsp, tmport++);     
+       atp_writeb_io(dev, c, 0x11, dev->id[c][target_id].devsp);
 #ifdef ED_DBGP 
        printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
 #endif
@@ -849,9 +804,9 @@ oktosend:
        /*
         *      Write transfer size
         */
-       outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++);
-       outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++);
-       outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++);
+       atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&l))[2]);
+       atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&l))[1]);
+       atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&l))[0]);
        j = target_id;  
        dev->id[c][j].last_len = l;
        dev->id[c][j].tran_len = 0;
@@ -867,29 +822,24 @@ oktosend:
        /*
         *      Check transfer direction
         */
-       if (workreq->sc_data_direction == DMA_TO_DEVICE) {
-               outb((unsigned char) (j | 0x20), tmport++);
-       } else {
-               outb(j, tmport++);
-       }
-       outb((unsigned char) (inb(tmport) | 0x80), tmport);
-       outb(0x80, tmport);
-       tmport = workport + 0x1c;
+       if (workreq->sc_data_direction == DMA_TO_DEVICE)
+               atp_writeb_io(dev, c, 0x15, j | 0x20);
+       else
+               atp_writeb_io(dev, c, 0x15, j);
+       atp_writeb_io(dev, c, 0x16, atp_readb_io(dev, c, 0x16) | 0x80);
+       atp_writeb_io(dev, c, 0x16, 0x80);
        dev->id[c][target_id].dirct = 0;
        if (l == 0) {
-               if (inb(tmport) == 0) {
-                       tmport = workport + 0x18;
+               if (atp_readb_io(dev, c, 0x1c) == 0) {
 #ifdef ED_DBGP
                        printk("change SCSI_CMD_REG 0x08\n");   
 #endif                         
-                       outb(0x08, tmport);
-               } else {
+                       atp_writeb_io(dev, c, 0x18, 0x08);
+               } else
                        dev->last_cmd[c] |= 0x40;
-               }
                dev->in_snd[c] = 0;
                return;
        }
-       tmpcip = dev->pciport[c];
        prd = dev->id[c][target_id].prd_table;
        dev->id[c][target_id].prd_pos = prd;
 
@@ -926,50 +876,37 @@ oktosend:
                printk("2. bttl %x, l %x\n",bttl, l);
 #endif                 
        }
-       tmpcip += 4;
 #ifdef ED_DBGP         
-       printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id);
+       printk("send_s870: prdaddr_2 0x%8x target_id %d\n", dev->id[c][target_id].prdaddr,target_id);
 #endif 
        dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus;
-       outl(dev->id[c][target_id].prdaddr, tmpcip);
-       tmpcip = tmpcip - 2;
-       outb(0x06, tmpcip);
-       outb(0x00, tmpcip);
-       if (dev->dev_id == ATP885_DEVID) {
-               tmpcip--;
-               j=inb(tmpcip) & 0xf3;
+       atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+       atp_writeb_pci(dev, c, 2, 0x06);
+       atp_writeb_pci(dev, c, 2, 0x00);
+       if (is885(dev)) {
+               j = atp_readb_pci(dev, c, 1) & 0xf3;
                if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) ||
                (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
                        j |= 0x0c;
                }
-               outb(j,tmpcip);
-               tmpcip--;               
-       } else if ((dev->dev_id == ATP880_DEVID1) ||
-                  (dev->dev_id == ATP880_DEVID2)) {
-               tmpcip =tmpcip -2;      
-               tmport = workport - 0x05;
-               if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
-                       outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
-               } else {
-                       outb((unsigned char) (inb(tmport) & 0x3f), tmport);
-               }               
+               atp_writeb_pci(dev, c, 1, j);
+       } else if (is880(dev)) {
+               if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+                       atp_writeb_base(dev, 0x3b, (atp_readb_base(dev, 0x3b) & 0x3f) | 0xc0);
+               else
+                       atp_writeb_base(dev, 0x3b, atp_readb_base(dev, 0x3b) & 0x3f);
        } else {                
-               tmpcip =tmpcip -2;
-               tmport = workport + 0x3a;
-               if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
-                       outb((inb(tmport) & 0xf3) | 0x08, tmport);
-               } else {
-                       outb(inb(tmport) & 0xf3, tmport);
-               }               
+               if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+                       atp_writeb_base(dev, 0x3a, (atp_readb_base(dev, 0x3a) & 0xf3) | 0x08);
+               else
+                       atp_writeb_base(dev, 0x3a, atp_readb_base(dev, 0x3a) & 0xf3);
        }       
-       tmport = workport + 0x1c;
 
        if(workreq->sc_data_direction == DMA_TO_DEVICE) {
                dev->id[c][target_id].dirct = 0x20;
-               if (inb(tmport) == 0) {
-                       tmport = workport + 0x18;
-                       outb(0x08, tmport);
-                       outb(0x01, tmpcip);
+               if (atp_readb_io(dev, c, 0x1c) == 0) {
+                       atp_writeb_io(dev, c, 0x18, 0x08);
+                       atp_writeb_pci(dev, c, 0, 0x01);
 #ifdef ED_DBGP         
                printk( "start DMA(to target)\n");
 #endif                         
@@ -979,10 +916,9 @@ oktosend:
                dev->in_snd[c] = 0;
                return;
        }
-       if (inb(tmport) == 0) {         
-               tmport = workport + 0x18;
-               outb(0x08, tmport);
-               outb(0x09, tmpcip);
+       if (atp_readb_io(dev, c, 0x1c) == 0) {
+               atp_writeb_io(dev, c, 0x18, 0x08);
+               atp_writeb_pci(dev, c, 0, 0x09);
 #ifdef ED_DBGP         
                printk( "start DMA(to host)\n");
 #endif                 
@@ -996,49 +932,40 @@ oktosend:
 
 static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val)
 {
-       unsigned int tmport;
        unsigned short int i, k;
        unsigned char j;
 
-       tmport = dev->ioport[0] + 0x1c;
-       outw(*val, tmport);
-FUN_D7:
+       atp_writew_io(dev, 0, 0x1c, *val);
        for (i = 0; i < 10; i++) {      /* stable >= bus settle delay(400 ns)  */
-               k = inw(tmport);
+               k = atp_readw_io(dev, 0, 0x1c);
                j = (unsigned char) (k >> 8);
-               if ((k & 0x8000) != 0) {        /* DB7 all release?    */
-                       goto FUN_D7;
-               }
+               if ((k & 0x8000) != 0)  /* DB7 all release?    */
+                       i = 0;
        }
        *val |= 0x4000;         /* assert DB6           */
-       outw(*val, tmport);
+       atp_writew_io(dev, 0, 0x1c, *val);
        *val &= 0xdfff;         /* assert DB5           */
-       outw(*val, tmport);
-FUN_D5:
+       atp_writew_io(dev, 0, 0x1c, *val);
        for (i = 0; i < 10; i++) {      /* stable >= bus settle delay(400 ns) */
-               if ((inw(tmport) & 0x2000) != 0) {      /* DB5 all release?       */
-                       goto FUN_D5;
-               }
+               if ((atp_readw_io(dev, 0, 0x1c) & 0x2000) != 0) /* DB5 all release?       */
+                       i = 0;
        }
        *val |= 0x8000;         /* no DB4-0, assert DB7    */
        *val &= 0xe0ff;
-       outw(*val, tmport);
+       atp_writew_io(dev, 0, 0x1c, *val);
        *val &= 0xbfff;         /* release DB6             */
-       outw(*val, tmport);
-FUN_D6:
+       atp_writew_io(dev, 0, 0x1c, *val);
        for (i = 0; i < 10; i++) {      /* stable >= bus settle delay(400 ns)  */
-               if ((inw(tmport) & 0x4000) != 0) {      /* DB6 all release?  */
-                       goto FUN_D6;
-               }
+               if ((atp_readw_io(dev, 0, 0x1c) & 0x4000) != 0) /* DB6 all release?  */
+                       i = 0;
        }
 
        return j;
 }
 
-static void tscam(struct Scsi_Host *host)
+static void tscam(struct Scsi_Host *host, bool wide_chip, u8 scam_on)
 {
 
-       unsigned int tmport;
        unsigned char i, j, k;
        unsigned long n;
        unsigned short int m, assignid_map, val;
@@ -1055,31 +982,28 @@ static void tscam(struct Scsi_Host *host)
        }
  */
 
-       tmport = dev->ioport[0] + 1;
-       outb(0x08, tmport++);
-       outb(0x7f, tmport);
-       tmport = dev->ioport[0] + 0x11;
-       outb(0x20, tmport);
+       atp_writeb_io(dev, 0, 1, 0x08);
+       atp_writeb_io(dev, 0, 2, 0x7f);
+       atp_writeb_io(dev, 0, 0x11, 0x20);
 
-       if ((dev->scam_on & 0x40) == 0) {
+       if ((scam_on & 0x40) == 0) {
                return;
        }
        m = 1;
        m <<= dev->host_id[0];
        j = 16;
-       if (dev->chip_ver < 4) {
+       if (!wide_chip) {
                m |= 0xff00;
                j = 8;
        }
        assignid_map = m;
-       tmport = dev->ioport[0] + 0x02;
-       outb(0x02, tmport++);   /* 2*2=4ms,3EH 2/32*3E=3.9ms */
-       outb(0, tmport++);
-       outb(0, tmport++);
-       outb(0, tmport++);
-       outb(0, tmport++);
-       outb(0, tmport++);
-       outb(0, tmport++);
+       atp_writeb_io(dev, 0, 0x02, 0x02);      /* 2*2=4ms,3EH 2/32*3E=3.9ms */
+       atp_writeb_io(dev, 0, 0x03, 0);
+       atp_writeb_io(dev, 0, 0x04, 0);
+       atp_writeb_io(dev, 0, 0x05, 0);
+       atp_writeb_io(dev, 0, 0x06, 0);
+       atp_writeb_io(dev, 0, 0x07, 0);
+       atp_writeb_io(dev, 0, 0x08, 0);
 
        for (i = 0; i < j; i++) {
                m = 1;
@@ -1087,92 +1011,73 @@ static void tscam(struct Scsi_Host *host)
                if ((m & assignid_map) != 0) {
                        continue;
                }
-               tmport = dev->ioport[0] + 0x0f;
-               outb(0, tmport++);
-               tmport += 0x02;
-               outb(0, tmport++);
-               outb(0, tmport++);
-               outb(0, tmport++);
+               atp_writeb_io(dev, 0, 0x0f, 0);
+               atp_writeb_io(dev, 0, 0x12, 0);
+               atp_writeb_io(dev, 0, 0x13, 0);
+               atp_writeb_io(dev, 0, 0x14, 0);
                if (i > 7) {
                        k = (i & 0x07) | 0x40;
                } else {
                        k = i;
                }
-               outb(k, tmport++);
-               tmport = dev->ioport[0] + 0x1b;
-               if (dev->chip_ver == 4) {
-                       outb(0x01, tmport);
-               } else {
-                       outb(0x00, tmport);
-               }
-wait_rdyok:
-               tmport = dev->ioport[0] + 0x18;
-               outb(0x09, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-               tmport -= 0x08;
-               k = inb(tmport);
-               if (k != 0x16) {
-                       if ((k == 0x85) || (k == 0x42)) {
-                               continue;
-                       }
-                       tmport = dev->ioport[0] + 0x10;
-                       outb(0x41, tmport);
-                       goto wait_rdyok;
-               }
+               atp_writeb_io(dev, 0, 0x15, k);
+               if (wide_chip)
+                       atp_writeb_io(dev, 0, 0x1b, 0x01);
+               else
+                       atp_writeb_io(dev, 0, 0x1b, 0x00);
+               do {
+                       atp_writeb_io(dev, 0, 0x18, 0x09);
+
+                       while ((atp_readb_io(dev, 0, 0x1f) & 0x80) == 0x00)
+                               cpu_relax();
+                       k = atp_readb_io(dev, 0, 0x17);
+                       if ((k == 0x85) || (k == 0x42))
+                               break;
+                       if (k != 0x16)
+                               atp_writeb_io(dev, 0, 0x10, 0x41);
+               } while (k != 0x16);
+               if ((k == 0x85) || (k == 0x42))
+                       continue;
                assignid_map |= m;
 
        }
-       tmport = dev->ioport[0] + 0x02;
-       outb(0x7f, tmport);
-       tmport = dev->ioport[0] + 0x1b;
-       outb(0x02, tmport);
+       atp_writeb_io(dev, 0, 0x02, 0x7f);
+       atp_writeb_io(dev, 0, 0x1b, 0x02);
 
-       outb(0, 0x80);
+       udelay(2);
 
        val = 0x0080;           /* bsy  */
-       tmport = dev->ioport[0] + 0x1c;
-       outw(val, tmport);
+       atp_writew_io(dev, 0, 0x1c, val);
        val |= 0x0040;          /* sel  */
-       outw(val, tmport);
+       atp_writew_io(dev, 0, 0x1c, val);
        val |= 0x0004;          /* msg  */
-       outw(val, tmport);
-       inb(0x80);              /* 2 deskew delay(45ns*2=90ns) */
+       atp_writew_io(dev, 0, 0x1c, val);
+       udelay(2);              /* 2 deskew delay(45ns*2=90ns) */
        val &= 0x007f;          /* no bsy  */
-       outw(val, tmport);
+       atp_writew_io(dev, 0, 0x1c, val);
        mdelay(128);
        val &= 0x00fb;          /* after 1ms no msg */
-       outw(val, tmport);
-wait_nomsg:
-       if ((inb(tmport) & 0x04) != 0) {
-               goto wait_nomsg;
-       }
-       outb(1, 0x80);
+       atp_writew_io(dev, 0, 0x1c, val);
+       while ((atp_readb_io(dev, 0, 0x1c) & 0x04) != 0)
+               ;
+       udelay(2);
        udelay(100);
-       for (n = 0; n < 0x30000; n++) {
-               if ((inb(tmport) & 0x80) != 0) {        /* bsy ? */
-                       goto wait_io;
-               }
-       }
-       goto TCM_SYNC;
-wait_io:
-       for (n = 0; n < 0x30000; n++) {
-               if ((inb(tmport) & 0x81) == 0x0081) {
-                       goto wait_io1;
-               }
-       }
-       goto TCM_SYNC;
-wait_io1:
-       inb(0x80);
-       val |= 0x8003;          /* io,cd,db7  */
-       outw(val, tmport);
-       inb(0x80);
-       val &= 0x00bf;          /* no sel     */
-       outw(val, tmport);
-       outb(2, 0x80);
-TCM_SYNC:
+       for (n = 0; n < 0x30000; n++)
+               if ((atp_readb_io(dev, 0, 0x1c) & 0x80) != 0)   /* bsy ? */
+                       break;
+       if (n < 0x30000)
+               for (n = 0; n < 0x30000; n++)
+                       if ((atp_readb_io(dev, 0, 0x1c) & 0x81) == 0x0081) {
+                               udelay(2);
+                               val |= 0x8003;          /* io,cd,db7  */
+                               atp_writew_io(dev, 0, 0x1c, val);
+                               udelay(2);
+                               val &= 0x00bf;          /* no sel     */
+                               atp_writew_io(dev, 0, 0x1c, val);
+                               udelay(2);
+                               break;
+                       }
+       while (1) {
        /*
         * The funny division into multiple delays is to accomodate
         * arches like ARM where udelay() multiplies its argument by
@@ -1183,55 +1088,48 @@ TCM_SYNC:
         */
        mdelay(2);
        udelay(48);
-       if ((inb(tmport) & 0x80) == 0x00) {     /* bsy ? */
-               outw(0, tmport--);
-               outb(0, tmport);
-               tmport = dev->ioport[0] + 0x15;
-               outb(0, tmport);
-               tmport += 0x03;
-               outb(0x09, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0)
+       if ((atp_readb_io(dev, 0, 0x1c) & 0x80) == 0x00) {      /* bsy ? */
+               atp_writew_io(dev, 0, 0x1c, 0);
+               atp_writeb_io(dev, 0, 0x1b, 0);
+               atp_writeb_io(dev, 0, 0x15, 0);
+               atp_writeb_io(dev, 0, 0x18, 0x09);
+               while ((atp_readb_io(dev, 0, 0x1f) & 0x80) == 0)
                        cpu_relax();
-               tmport -= 0x08;
-               inb(tmport);
+               atp_readb_io(dev, 0, 0x17);
                return;
        }
        val &= 0x00ff;          /* synchronization  */
        val |= 0x3f00;
        fun_scam(dev, &val);
-       outb(3, 0x80);
+       udelay(2);
        val &= 0x00ff;          /* isolation        */
        val |= 0x2000;
        fun_scam(dev, &val);
-       outb(4, 0x80);
+       udelay(2);
        i = 8;
        j = 0;
-TCM_ID:
-       if ((inw(tmport) & 0x2000) == 0) {
-               goto TCM_ID;
-       }
-       outb(5, 0x80);
-       val &= 0x00ff;          /* get ID_STRING */
-       val |= 0x2000;
-       k = fun_scam(dev, &val);
-       if ((k & 0x03) == 0) {
-               goto TCM_5;
-       }
-       mbuf[j] <<= 0x01;
-       mbuf[j] &= 0xfe;
-       if ((k & 0x02) != 0) {
-               mbuf[j] |= 0x01;
-       }
-       i--;
-       if (i > 0) {
-               goto TCM_ID;
+
+       while (1) {
+               if ((atp_readw_io(dev, 0, 0x1c) & 0x2000) == 0)
+                       continue;
+               udelay(2);
+               val &= 0x00ff;          /* get ID_STRING */
+               val |= 0x2000;
+               k = fun_scam(dev, &val);
+               if ((k & 0x03) == 0)
+                       break;
+               mbuf[j] <<= 0x01;
+               mbuf[j] &= 0xfe;
+               if ((k & 0x02) != 0)
+                       mbuf[j] |= 0x01;
+               i--;
+               if (i > 0)
+                       continue;
+               j++;
+               i = 8;
        }
-       j++;
-       i = 8;
-       goto TCM_ID;
 
-TCM_5:                 /* isolation complete..  */
+       /* isolation complete..  */
 /*    mbuf[32]=0;
        printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
        i = 15;
@@ -1239,33 +1137,33 @@ TCM_5:                  /* isolation complete..  */
        if ((j & 0x20) != 0) {  /* bit5=1:ID up to 7      */
                i = 7;
        }
-       if ((j & 0x06) == 0) {  /* IDvalid?             */
-               goto G2Q5;
-       }
-       k = mbuf[1];
-small_id:
-       m = 1;
-       m <<= k;
-       if ((m & assignid_map) == 0) {
-               goto G2Q_QUIN;
-       }
-       if (k > 0) {
-               k--;
-               goto small_id;
-       }
-G2Q5:                  /* srch from max acceptable ID#  */
-       k = i;                  /* max acceptable ID#            */
-G2Q_LP:
-       m = 1;
-       m <<= k;
-       if ((m & assignid_map) == 0) {
-               goto G2Q_QUIN;
+       if ((j & 0x06) != 0) {  /* IDvalid?             */
+               k = mbuf[1];
+               while (1) {
+                       m = 1;
+                       m <<= k;
+                       if ((m & assignid_map) == 0)
+                               break;
+                       if (k > 0)
+                               k--;
+                       else
+                               break;
+               }
        }
-       if (k > 0) {
-               k--;
-               goto G2Q_LP;
+       if ((m & assignid_map) != 0) {  /* srch from max acceptable ID#  */
+               k = i;                  /* max acceptable ID#            */
+               while (1) {
+                       m = 1;
+                       m <<= k;
+                       if ((m & assignid_map) == 0)
+                               break;
+                       if (k > 0)
+                               k--;
+                       else
+                               break;
+               }
        }
-G2Q_QUIN:              /* k=binID#,       */
+       /* k=binID#,       */
        assignid_map |= m;
        if (k < 8) {
                quintet[0] = 0x38;      /* 1st dft ID<8    */
@@ -1284,1767 +1182,400 @@ G2Q_QUIN:            /* k=binID#,       */
        val |= m;
        fun_scam(dev, &val);
 
-       goto TCM_SYNC;
+       }
+}
 
+static void atp870u_free_tables(struct Scsi_Host *host)
+{
+       struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
+       int j, k;
+       for (j=0; j < 2; j++) {
+               for (k = 0; k < 16; k++) {
+                       if (!atp_dev->id[j][k].prd_table)
+                               continue;
+                       pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus);
+                       atp_dev->id[j][k].prd_table = NULL;
+               }
+       }
 }
 
-static void is870(struct atp_unit *dev, unsigned int wkport)
+static int atp870u_init_tables(struct Scsi_Host *host)
 {
-       unsigned int tmport;
-       unsigned char i, j, k, rmb, n;
-       unsigned short int m;
-       static unsigned char mbuf[512];
-       static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
-       static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
-       static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
-       static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e };
-       static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
-       static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
-       
-       tmport = wkport + 0x3a;
-       outb((unsigned char) (inb(tmport) | 0x10), tmport);
+       struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
+       int c,k;
+       for(c=0;c < 2;c++) {
+               for(k=0;k<16;k++) {
+                               atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prd_bus));
+                               if (!atp_dev->id[c][k].prd_table) {
+                                       printk("atp870u_init_tables fail\n");
+                               atp870u_free_tables(host);
+                               return -ENOMEM;
+                       }
+                       atp_dev->id[c][k].prdaddr = atp_dev->id[c][k].prd_bus;
+                       atp_dev->id[c][k].devsp=0x20;
+                       atp_dev->id[c][k].devtype = 0x7f;
+                       atp_dev->id[c][k].curr_req = NULL;                         
+               }
+                               
+               atp_dev->active_id[c] = 0;
+               atp_dev->wide_id[c] = 0;
+               atp_dev->host_id[c] = 0x07;
+               atp_dev->quhd[c] = 0;
+               atp_dev->quend[c] = 0;
+               atp_dev->last_cmd[c] = 0xff;
+               atp_dev->in_snd[c] = 0;
+               atp_dev->in_int[c] = 0;
+               
+               for (k = 0; k < qcnt; k++) {
+                         atp_dev->quereq[c][k] = NULL;
+               }                          
+               for (k = 0; k < 16; k++) {
+                          atp_dev->id[c][k].curr_req = NULL;
+                          atp_dev->sp[c][k] = 0x04;
+               }                  
+       }
+       return 0;
+}
 
-       for (i = 0; i < 16; i++) {
-               if ((dev->chip_ver != 4) && (i > 7)) {
-                       break;
-               }
-               m = 1;
-               m = m << i;
-               if ((m & dev->active_id[0]) != 0) {
-                       continue;
-               }
-               if (i == dev->host_id[0]) {
-                       printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_id[0]);
-                       continue;
-               }
-               tmport = wkport + 0x1b;
-               if (dev->chip_ver == 4) {
-                       outb(0x01, tmport);
-               } else {
-                       outb(0x00, tmport);
-               }
-               tmport = wkport + 1;
-               outb(0x08, tmport++);
-               outb(0x7f, tmport++);
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[0][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               j = i;
-               if ((j & 0x08) != 0) {
-                       j = (j & 0x07) | 0x40;
-               }
-               outb(j, tmport);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
+static void atp_set_host_id(struct atp_unit *atp, u8 c, u8 host_id)
+{
+       atp_writeb_io(atp, c, 0, host_id | 0x08);
+       atp_writeb_io(atp, c, 0x18, 0);
+       while ((atp_readb_io(atp, c, 0x1f) & 0x80) == 0)
+               mdelay(1);
+       atp_readb_io(atp, c, 0x17);
+       atp_writeb_io(atp, c, 1, 8);
+       atp_writeb_io(atp, c, 2, 0x7f);
+       atp_writeb_io(atp, c, 0x11, 0x20);
+}
 
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
+static void atp870_init(struct Scsi_Host *shpnt)
+{
+       struct atp_unit *atpdev = shost_priv(shpnt);
+       struct pci_dev *pdev = atpdev->pdev;
+       unsigned char k, host_id;
+       u8 scam_on;
+       bool wide_chip =
+               (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7610 &&
+                pdev->revision == 4) ||
+               (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7612UW) ||
+               (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7612SUW);
+
+       pci_read_config_byte(pdev, 0x49, &host_id);
+
+       dev_info(&pdev->dev, "ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: IO:%lx, IRQ:%d.\n",
+                shpnt->io_port, shpnt->irq);
+
+       atpdev->ioport[0] = shpnt->io_port;
+       atpdev->pciport[0] = shpnt->io_port + 0x20;
+       host_id &= 0x07;
+       atpdev->host_id[0] = host_id;
+       scam_on = atp_readb_pci(atpdev, 0, 2);
+       atpdev->global_map[0] = atp_readb_base(atpdev, 0x2d);
+       atpdev->ultra_map[0] = atp_readw_base(atpdev, 0x2e);
+
+       if (atpdev->ultra_map[0] == 0) {
+               scam_on = 0x00;
+               atpdev->global_map[0] = 0x20;
+               atpdev->ultra_map[0] = 0xffff;
+       }
 
-               tmport -= 0x08;
-               if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
-                       continue;
+       if (pdev->revision > 0x07)      /* check if atp876 chip */
+               atp_writeb_base(atpdev, 0x3e, 0x00); /* enable terminator */
+
+       k = (atp_readb_base(atpdev, 0x3a) & 0xf3) | 0x10;
+       atp_writeb_base(atpdev, 0x3a, k);
+       atp_writeb_base(atpdev, 0x3a, k & 0xdf);
+       mdelay(32);
+       atp_writeb_base(atpdev, 0x3a, k);
+       mdelay(32);
+       atp_set_host_id(atpdev, 0, host_id);
+
+       tscam(shpnt, wide_chip, scam_on);
+       atp_writeb_base(atpdev, 0x3a, atp_readb_base(atpdev, 0x3a) | 0x10);
+       atp_is(atpdev, 0, wide_chip, 0);
+       atp_writeb_base(atpdev, 0x3a, atp_readb_base(atpdev, 0x3a) & 0xef);
+       atp_writeb_base(atpdev, 0x3b, atp_readb_base(atpdev, 0x3b) | 0x20);
+       shpnt->max_id = wide_chip ? 16 : 8;
+       shpnt->this_id = host_id;
+}
 
-               while (inb(tmport) != 0x8e)
-                       cpu_relax();
+static void atp880_init(struct Scsi_Host *shpnt)
+{
+       struct atp_unit *atpdev = shost_priv(shpnt);
+       struct pci_dev *pdev = atpdev->pdev;
+       unsigned char k, m, host_id;
+       unsigned int n;
 
-               dev->active_id[0] |= m;
+       pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
 
-               tmport = wkport + 0x10;
-               outb(0x30, tmport);
-               tmport = wkport + 0x04;
-               outb(0x00, tmport);
+       atpdev->ioport[0] = shpnt->io_port + 0x40;
+       atpdev->pciport[0] = shpnt->io_port + 0x28;
 
-phase_cmd:
-               tmport = wkport + 0x18;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j != 0x16) {
-                       tmport = wkport + 0x10;
-                       outb(0x41, tmport);
-                       goto phase_cmd;
-               }
-sel_ok:
-               tmport = wkport + 3;
-               outb(inqd[0], tmport++);
-               outb(inqd[1], tmport++);
-               outb(inqd[2], tmport++);
-               outb(inqd[3], tmport++);
-               outb(inqd[4], tmport++);
-               outb(inqd[5], tmport);
-               tmport += 0x07;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[0][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(inqd[6], tmport++);
-               outb(inqd[7], tmport++);
-               tmport += 0x03;
-               outb(inqd[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               tmport -= 0x08;
-               if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
-                       continue;
+       host_id = atp_readb_base(atpdev, 0x39) >> 4;
 
-               while (inb(tmport) != 0x8e)
-                       cpu_relax();
-                       
-               tmport = wkport + 0x1b;
-               if (dev->chip_ver == 4)
-                       outb(0x00, tmport);
+       dev_info(&pdev->dev, "ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: IO:%lx, IRQ:%d.\n",
+                shpnt->io_port, shpnt->irq);
+       atpdev->host_id[0] = host_id;
 
-               tmport = wkport + 0x18;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               j = 0;
-rd_inq_data:
-               k = inb(tmport);
-               if ((k & 0x01) != 0) {
-                       tmport -= 0x06;
-                       mbuf[j++] = inb(tmport);
-                       tmport += 0x06;
-                       goto rd_inq_data;
-               }
-               if ((k & 0x80) == 0) {
-                       goto rd_inq_data;
-               }
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j == 0x16) {
-                       goto inq_ok;
-               }
-               tmport = wkport + 0x10;
-               outb(0x46, tmport);
-               tmport += 0x02;
-               outb(0, tmport++);
-               outb(0, tmport++);
-               outb(0, tmport++);
-               tmport += 0x03;
-               outb(0x08, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               tmport -= 0x08;
-               if (inb(tmport) != 0x16) {
-                       goto sel_ok;
-               }
-inq_ok:
-               mbuf[36] = 0;
-               printk(KERN_INFO "         ID: %2d  %s\n", i, &mbuf[8]);
-               dev->id[0][i].devtype = mbuf[0];
-               rmb = mbuf[1];
-               n = mbuf[7];
-               if (dev->chip_ver != 4) {
-                       goto not_wide;
-               }
-               if ((mbuf[7] & 0x60) == 0) {
-                       goto not_wide;
-               }
-               if ((dev->global_map[0] & 0x20) == 0) {
-                       goto not_wide;
-               }
-               tmport = wkport + 0x1b;
-               outb(0x01, tmport);
-               tmport = wkport + 3;
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[0][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               tmport -= 0x08;
-               if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
-                       continue;
-
-               while (inb(tmport) != 0x8e)
-                       cpu_relax();
-                       
-try_wide:
-               j = 0;
-               tmport = wkport + 0x14;
-               outb(0x05, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(wide[j++], tmport);
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-               
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto widep_in;
-               }
-               if (j == 0x0a) {
-                       goto widep_cmd;
-               }
-               if (j == 0x0e) {
-                       goto try_wide;
-               }
-               continue;
-widep_out:
-               tmport = wkport + 0x18;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(0, tmport);
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto widep_in;
-               }
-               if (j == 0x0a) {
-                       goto widep_cmd;
-               }
-               if (j == 0x0e) {
-                       goto widep_out;
-               }
-               continue;
-widep_in:
-               tmport = wkport + 0x14;
-               outb(0xff, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               k = 0;
-widep_in1:
-               j = inb(tmport);
-               if ((j & 0x01) != 0) {
-                       tmport -= 0x06;
-                       mbuf[k++] = inb(tmport);
-                       tmport += 0x06;
-                       goto widep_in1;
-               }
-               if ((j & 0x80) == 0x00) {
-                       goto widep_in1;
-               }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto widep_in;
-               }
-               if (j == 0x0a) {
-                       goto widep_cmd;
-               }
-               if (j == 0x0e) {
-                       goto widep_out;
-               }
-               continue;
-widep_cmd:
-               tmport = wkport + 0x10;
-               outb(0x30, tmport);
-               tmport = wkport + 0x14;
-               outb(0x00, tmport);
-               tmport += 0x04;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j != 0x16) {
-                       if (j == 0x4e) {
-                               goto widep_out;
-                       }
-                       continue;
-               }
-               if (mbuf[0] != 0x01) {
-                       goto not_wide;
-               }
-               if (mbuf[1] != 0x02) {
-                       goto not_wide;
-               }
-               if (mbuf[2] != 0x03) {
-                       goto not_wide;
-               }
-               if (mbuf[3] != 0x01) {
-                       goto not_wide;
-               }
-               m = 1;
-               m = m << i;
-               dev->wide_id[0] |= m;
-not_wide:
-               if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
-                       goto set_sync;
-               }
-               continue;
-set_sync:
-               tmport = wkport + 0x1b;
-               j = 0;
-               if ((m & dev->wide_id[0]) != 0) {
-                       j |= 0x01;
-               }
-               outb(j, tmport);
-               tmport = wkport + 3;
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[0][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               tmport -= 0x08;
-               if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
-                       continue;
-
-               while (inb(tmport) != 0x8e)
-                       cpu_relax();
-                       
-try_sync:
-               j = 0;
-               tmport = wkport + 0x14;
-               outb(0x06, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               if ((m & dev->wide_id[0]) != 0) {
-                                       outb(synw[j++], tmport);
-                               } else {
-                                       if ((m & dev->ultra_map[0]) != 0) {
-                                               outb(synu[j++], tmport);
-                                       } else {
-                                               outb(synn[j++], tmport);
-                                       }
-                               }
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-               
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto phase_ins;
-               }
-               if (j == 0x0a) {
-                       goto phase_cmds;
-               }
-               if (j == 0x0e) {
-                       goto try_sync;
-               }
-               continue;
-phase_outs:
-               tmport = wkport + 0x18;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00) {
-                       if ((inb(tmport) & 0x01) != 0x00) {
-                               tmport -= 0x06;
-                               outb(0x00, tmport);
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j == 0x85) {
-                       goto tar_dcons;
-               }
-               j &= 0x0f;
-               if (j == 0x0f) {
-                       goto phase_ins;
-               }
-               if (j == 0x0a) {
-                       goto phase_cmds;
-               }
-               if (j == 0x0e) {
-                       goto phase_outs;
-               }
-               continue;
-phase_ins:
-               tmport = wkport + 0x14;
-               outb(0xff, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               k = 0;
-phase_ins1:
-               j = inb(tmport);
-               if ((j & 0x01) != 0x00) {
-                       tmport -= 0x06;
-                       mbuf[k++] = inb(tmport);
-                       tmport += 0x06;
-                       goto phase_ins1;
-               }
-               if ((j & 0x80) == 0x00) {
-                       goto phase_ins1;
-               }
-               tmport -= 0x08;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               j = inb(tmport);
-               if (j == 0x85) {
-                       goto tar_dcons;
-               }
-               j &= 0x0f;
-               if (j == 0x0f) {
-                       goto phase_ins;
-               }
-               if (j == 0x0a) {
-                       goto phase_cmds;
-               }
-               if (j == 0x0e) {
-                       goto phase_outs;
-               }
-               continue;
-phase_cmds:
-               tmport = wkport + 0x10;
-               outb(0x30, tmport);
-tar_dcons:
-               tmport = wkport + 0x14;
-               outb(0x00, tmport);
-               tmport += 0x04;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j != 0x16) {
-                       continue;
-               }
-               if (mbuf[0] != 0x01) {
-                       continue;
-               }
-               if (mbuf[1] != 0x03) {
-                       continue;
-               }
-               if (mbuf[4] == 0x00) {
-                       continue;
-               }
-               if (mbuf[3] > 0x64) {
-                       continue;
-               }
-               if (mbuf[4] > 0x0c) {
-                       mbuf[4] = 0x0c;
-               }
-               dev->id[0][i].devsp = mbuf[4];
-               if ((mbuf[3] < 0x0d) && (rmb == 0)) {
-                       j = 0xa0;
-                       goto set_syn_ok;
-               }
-               if (mbuf[3] < 0x1a) {
-                       j = 0x20;
-                       goto set_syn_ok;
-               }
-               if (mbuf[3] < 0x33) {
-                       j = 0x40;
-                       goto set_syn_ok;
-               }
-               if (mbuf[3] < 0x4c) {
-                       j = 0x50;
-                       goto set_syn_ok;
-               }
-               j = 0x60;
-set_syn_ok:
-               dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
-       }
-       tmport = wkport + 0x3a;
-       outb((unsigned char) (inb(tmport) & 0xef), tmport);
-}
-
-static void is880(struct atp_unit *dev, unsigned int wkport)
-{
-       unsigned int tmport;
-       unsigned char i, j, k, rmb, n, lvdmode;
-       unsigned short int m;
-       static unsigned char mbuf[512];
-       static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
-       static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
-       static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
-       unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
-       static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
-       unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
-       static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
-       static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
-
-       lvdmode = inb(wkport + 0x3f) & 0x40;
-
-       for (i = 0; i < 16; i++) {
-               m = 1;
-               m = m << i;
-               if ((m & dev->active_id[0]) != 0) {
-                       continue;
-               }
-               if (i == dev->host_id[0]) {
-                       printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_id[0]);
-                       continue;
-               }
-               tmport = wkport + 0x5b;
-               outb(0x01, tmport);
-               tmport = wkport + 0x41;
-               outb(0x08, tmport++);
-               outb(0x7f, tmport++);
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[0][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               j = i;
-               if ((j & 0x08) != 0) {
-                       j = (j & 0x07) | 0x40;
-               }
-               outb(j, tmport);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-
-               tmport -= 0x08;
-               if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
-                       continue;
-
-               while (inb(tmport) != 0x8e)
-                       cpu_relax();
-                       
-               dev->active_id[0] |= m;
-
-               tmport = wkport + 0x50;
-               outb(0x30, tmport);
-               tmport = wkport + 0x54;
-               outb(0x00, tmport);
-
-phase_cmd:
-               tmport = wkport + 0x58;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j != 0x16) {
-                       tmport = wkport + 0x50;
-                       outb(0x41, tmport);
-                       goto phase_cmd;
-               }
-sel_ok:
-               tmport = wkport + 0x43;
-               outb(inqd[0], tmport++);
-               outb(inqd[1], tmport++);
-               outb(inqd[2], tmport++);
-               outb(inqd[3], tmport++);
-               outb(inqd[4], tmport++);
-               outb(inqd[5], tmport);
-               tmport += 0x07;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[0][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(inqd[6], tmport++);
-               outb(inqd[7], tmport++);
-               tmport += 0x03;
-               outb(inqd[8], tmport);
-               tmport += 0x07;
-               
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               tmport -= 0x08;
-               if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
-                       continue;
-
-               while (inb(tmport) != 0x8e)
-                       cpu_relax();
-                       
-               tmport = wkport + 0x5b;
-               outb(0x00, tmport);
-               tmport = wkport + 0x58;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               j = 0;
-rd_inq_data:
-               k = inb(tmport);
-               if ((k & 0x01) != 0) {
-                       tmport -= 0x06;
-                       mbuf[j++] = inb(tmport);
-                       tmport += 0x06;
-                       goto rd_inq_data;
-               }
-               if ((k & 0x80) == 0) {
-                       goto rd_inq_data;
-               }
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j == 0x16) {
-                       goto inq_ok;
-               }
-               tmport = wkport + 0x50;
-               outb(0x46, tmport);
-               tmport += 0x02;
-               outb(0, tmport++);
-               outb(0, tmport++);
-               outb(0, tmport++);
-               tmport += 0x03;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               tmport -= 0x08;
-               if (inb(tmport) != 0x16)
-                       goto sel_ok;
-
-inq_ok:
-               mbuf[36] = 0;
-               printk(KERN_INFO "         ID: %2d  %s\n", i, &mbuf[8]);
-               dev->id[0][i].devtype = mbuf[0];
-               rmb = mbuf[1];
-               n = mbuf[7];
-               if ((mbuf[7] & 0x60) == 0) {
-                       goto not_wide;
-               }
-               if ((i < 8) && ((dev->global_map[0] & 0x20) == 0)) {
-                       goto not_wide;
-               }
-               if (lvdmode == 0) {
-                       goto chg_wide;
-               }
-               if (dev->sp[0][i] != 0x04)      // force u2
-               {
-                       goto chg_wide;
-               }
-
-               tmport = wkport + 0x5b;
-               outb(0x01, tmport);
-               tmport = wkport + 0x43;
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[0][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-
-               tmport -= 0x08;
-
-               if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
-                       continue;
-
-               while (inb(tmport) != 0x8e)
-                       cpu_relax();
-
-try_u3:
-               j = 0;
-               tmport = wkport + 0x54;
-               outb(0x09, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(u3[j++], tmport);
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto u3p_in;
-               }
-               if (j == 0x0a) {
-                       goto u3p_cmd;
-               }
-               if (j == 0x0e) {
-                       goto try_u3;
-               }
-               continue;
-u3p_out:
-               tmport = wkport + 0x58;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(0, tmport);
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto u3p_in;
-               }
-               if (j == 0x0a) {
-                       goto u3p_cmd;
-               }
-               if (j == 0x0e) {
-                       goto u3p_out;
-               }
-               continue;
-u3p_in:
-               tmport = wkport + 0x54;
-               outb(0x09, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               k = 0;
-u3p_in1:
-               j = inb(tmport);
-               if ((j & 0x01) != 0) {
-                       tmport -= 0x06;
-                       mbuf[k++] = inb(tmport);
-                       tmport += 0x06;
-                       goto u3p_in1;
-               }
-               if ((j & 0x80) == 0x00) {
-                       goto u3p_in1;
-               }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto u3p_in;
-               }
-               if (j == 0x0a) {
-                       goto u3p_cmd;
-               }
-               if (j == 0x0e) {
-                       goto u3p_out;
-               }
-               continue;
-u3p_cmd:
-               tmport = wkport + 0x50;
-               outb(0x30, tmport);
-               tmport = wkport + 0x54;
-               outb(0x00, tmport);
-               tmport += 0x04;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j != 0x16) {
-                       if (j == 0x4e) {
-                               goto u3p_out;
-                       }
-                       continue;
-               }
-               if (mbuf[0] != 0x01) {
-                       goto chg_wide;
-               }
-               if (mbuf[1] != 0x06) {
-                       goto chg_wide;
-               }
-               if (mbuf[2] != 0x04) {
-                       goto chg_wide;
-               }
-               if (mbuf[3] == 0x09) {
-                       m = 1;
-                       m = m << i;
-                       dev->wide_id[0] |= m;
-                       dev->id[0][i].devsp = 0xce;
-                       continue;
-               }
-chg_wide:
-               tmport = wkport + 0x5b;
-               outb(0x01, tmport);
-               tmport = wkport + 0x43;
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[0][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               tmport -= 0x08;
-               if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
-                       continue;
-
-               while (inb(tmport) != 0x8e)
-                       cpu_relax();
-                       
-try_wide:
-               j = 0;
-               tmport = wkport + 0x54;
-               outb(0x05, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(wide[j++], tmport);
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-                       
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto widep_in;
-               }
-               if (j == 0x0a) {
-                       goto widep_cmd;
-               }
-               if (j == 0x0e) {
-                       goto try_wide;
-               }
-               continue;
-widep_out:
-               tmport = wkport + 0x58;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(0, tmport);
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto widep_in;
-               }
-               if (j == 0x0a) {
-                       goto widep_cmd;
-               }
-               if (j == 0x0e) {
-                       goto widep_out;
-               }
-               continue;
-widep_in:
-               tmport = wkport + 0x54;
-               outb(0xff, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               k = 0;
-widep_in1:
-               j = inb(tmport);
-               if ((j & 0x01) != 0) {
-                       tmport -= 0x06;
-                       mbuf[k++] = inb(tmport);
-                       tmport += 0x06;
-                       goto widep_in1;
-               }
-               if ((j & 0x80) == 0x00) {
-                       goto widep_in1;
-               }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto widep_in;
-               }
-               if (j == 0x0a) {
-                       goto widep_cmd;
-               }
-               if (j == 0x0e) {
-                       goto widep_out;
-               }
-               continue;
-widep_cmd:
-               tmport = wkport + 0x50;
-               outb(0x30, tmport);
-               tmport = wkport + 0x54;
-               outb(0x00, tmport);
-               tmport += 0x04;
-               outb(0x08, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j != 0x16) {
-                       if (j == 0x4e) {
-                               goto widep_out;
-                       }
-                       continue;
-               }
-               if (mbuf[0] != 0x01) {
-                       goto not_wide;
-               }
-               if (mbuf[1] != 0x02) {
-                       goto not_wide;
-               }
-               if (mbuf[2] != 0x03) {
-                       goto not_wide;
-               }
-               if (mbuf[3] != 0x01) {
-                       goto not_wide;
-               }
-               m = 1;
-               m = m << i;
-               dev->wide_id[0] |= m;
-not_wide:
-               if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
-                       m = 1;
-                       m = m << i;
-                       if ((dev->async[0] & m) != 0) {
-                               goto set_sync;
-                       }
-               }
-               continue;
-set_sync:
-               if (dev->sp[0][i] == 0x02) {
-                       synu[4] = 0x0c;
-                       synuw[4] = 0x0c;
-               } else {
-                       if (dev->sp[0][i] >= 0x03) {
-                               synu[4] = 0x0a;
-                               synuw[4] = 0x0a;
-                       }
-               }
-               tmport = wkport + 0x5b;
-               j = 0;
-               if ((m & dev->wide_id[0]) != 0) {
-                       j |= 0x01;
-               }
-               outb(j, tmport);
-               tmport = wkport + 0x43;
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[0][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-
-               tmport -= 0x08;
-               if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
-                       continue;
-               }
-               while (inb(tmport) != 0x8e)
-                       cpu_relax();
-
-try_sync:
-               j = 0;
-               tmport = wkport + 0x54;
-               outb(0x06, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               if ((m & dev->wide_id[0]) != 0) {
-                                       if ((m & dev->ultra_map[0]) != 0) {
-                                               outb(synuw[j++], tmport);
-                                       } else {
-                                               outb(synw[j++], tmport);
-                                       }
-                               } else {
-                                       if ((m & dev->ultra_map[0]) != 0) {
-                                               outb(synu[j++], tmport);
-                                       } else {
-                                               outb(synn[j++], tmport);
-                                       }
-                               }
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-
-               j = inb(tmport) & 0x0f;
-               if (j == 0x0f) {
-                       goto phase_ins;
-               }
-               if (j == 0x0a) {
-                       goto phase_cmds;
-               }
-               if (j == 0x0e) {
-                       goto try_sync;
-               }
-               continue;
-phase_outs:
-               tmport = wkport + 0x58;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00) {
-                       if ((inb(tmport) & 0x01) != 0x00) {
-                               tmport -= 0x06;
-                               outb(0x00, tmport);
-                               tmport += 0x06;
-                       }
-               }
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j == 0x85) {
-                       goto tar_dcons;
-               }
-               j &= 0x0f;
-               if (j == 0x0f) {
-                       goto phase_ins;
-               }
-               if (j == 0x0a) {
-                       goto phase_cmds;
-               }
-               if (j == 0x0e) {
-                       goto phase_outs;
-               }
-               continue;
-phase_ins:
-               tmport = wkport + 0x54;
-               outb(0x06, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               k = 0;
-phase_ins1:
-               j = inb(tmport);
-               if ((j & 0x01) != 0x00) {
-                       tmport -= 0x06;
-                       mbuf[k++] = inb(tmport);
-                       tmport += 0x06;
-                       goto phase_ins1;
-               }
-               if ((j & 0x80) == 0x00) {
-                       goto phase_ins1;
-               }
-               tmport -= 0x08;
-
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
-
-               j = inb(tmport);
-               if (j == 0x85) {
-                       goto tar_dcons;
-               }
-               j &= 0x0f;
-               if (j == 0x0f) {
-                       goto phase_ins;
-               }
-               if (j == 0x0a) {
-                       goto phase_cmds;
-               }
-               if (j == 0x0e) {
-                       goto phase_outs;
-               }
-               continue;
-phase_cmds:
-               tmport = wkport + 0x50;
-               outb(0x30, tmport);
-tar_dcons:
-               tmport = wkport + 0x54;
-               outb(0x00, tmport);
-               tmport += 0x04;
-               outb(0x08, tmport);
-               tmport += 0x07;
+       atpdev->global_map[0] = atp_readb_base(atpdev, 0x35);
+       atpdev->ultra_map[0] = atp_readw_base(atpdev, 0x3c);
 
-               while ((inb(tmport) & 0x80) == 0x00)
-                       cpu_relax();
+       n = 0x3f09;
+       while (n < 0x4000) {
+               m = 0;
+               atp_writew_base(atpdev, 0x34, n);
+               n += 0x0002;
+               if (atp_readb_base(atpdev, 0x30) == 0xff)
+                       break;
 
-               tmport -= 0x08;
-               j = inb(tmport);
-               if (j != 0x16) {
-                       continue;
-               }
-               if (mbuf[0] != 0x01) {
-                       continue;
-               }
-               if (mbuf[1] != 0x03) {
-                       continue;
-               }
-               if (mbuf[4] == 0x00) {
-                       continue;
-               }
-               if (mbuf[3] > 0x64) {
-                       continue;
-               }
-               if (mbuf[4] > 0x0e) {
-                       mbuf[4] = 0x0e;
-               }
-               dev->id[0][i].devsp = mbuf[4];
-               if (mbuf[3] < 0x0c) {
-                       j = 0xb0;
-                       goto set_syn_ok;
-               }
-               if ((mbuf[3] < 0x0d) && (rmb == 0)) {
-                       j = 0xa0;
-                       goto set_syn_ok;
-               }
-               if (mbuf[3] < 0x1a) {
-                       j = 0x20;
-                       goto set_syn_ok;
-               }
-               if (mbuf[3] < 0x33) {
-                       j = 0x40;
-                       goto set_syn_ok;
-               }
-               if (mbuf[3] < 0x4c) {
-                       j = 0x50;
-                       goto set_syn_ok;
-               }
-               j = 0x60;
-set_syn_ok:
-               dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+               atp_writew_base(atpdev, 0x34, n);
+               n += 0x0002;
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+               atp_writew_base(atpdev, 0x34, n);
+               n += 0x0002;
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+               atp_writew_base(atpdev, 0x34, n);
+               n += 0x0002;
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+               atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+               n += 0x0018;
+       }
+       atp_writew_base(atpdev, 0x34, 0);
+       atpdev->ultra_map[0] = 0;
+       atpdev->async[0] = 0;
+       for (k = 0; k < 16; k++) {
+               n = 1 << k;
+               if (atpdev->sp[0][k] > 1)
+                       atpdev->ultra_map[0] |= n;
+               else
+                       if (atpdev->sp[0][k] == 0)
+                               atpdev->async[0] |= n;
        }
+       atpdev->async[0] = ~(atpdev->async[0]);
+       atp_writeb_base(atpdev, 0x35, atpdev->global_map[0]);
+
+       k = atp_readb_base(atpdev, 0x38) & 0x80;
+       atp_writeb_base(atpdev, 0x38, k);
+       atp_writeb_base(atpdev, 0x3b, 0x20);
+       mdelay(32);
+       atp_writeb_base(atpdev, 0x3b, 0);
+       mdelay(32);
+       atp_readb_io(atpdev, 0, 0x1b);
+       atp_readb_io(atpdev, 0, 0x17);
+
+       atp_set_host_id(atpdev, 0, host_id);
+
+       tscam(shpnt, true, atp_readb_base(atpdev, 0x22));
+       atp_is(atpdev, 0, true, atp_readb_base(atpdev, 0x3f) & 0x40);
+       atp_writeb_base(atpdev, 0x38, 0xb0);
+       shpnt->max_id = 16;
+       shpnt->this_id = host_id;
 }
 
-static void atp870u_free_tables(struct Scsi_Host *host)
+static void atp885_init(struct Scsi_Host *shpnt)
 {
-       struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
-       int j, k;
-       for (j=0; j < 2; j++) {
+       struct atp_unit *atpdev = shost_priv(shpnt);
+       struct pci_dev *pdev = atpdev->pdev;
+       unsigned char k, m, c;
+       unsigned int n;
+       unsigned char setupdata[2][16];
+
+       dev_info(&pdev->dev, "ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%lx, IRQ:%d.\n",
+                shpnt->io_port, shpnt->irq);
+
+       atpdev->ioport[0] = shpnt->io_port + 0x80;
+       atpdev->ioport[1] = shpnt->io_port + 0xc0;
+       atpdev->pciport[0] = shpnt->io_port + 0x40;
+       atpdev->pciport[1] = shpnt->io_port + 0x50;
+
+       c = atp_readb_base(atpdev, 0x29);
+       atp_writeb_base(atpdev, 0x29, c | 0x04);
+
+       n = 0x1f80;
+       while (n < 0x2000) {
+               atp_writew_base(atpdev, 0x3c, n);
+               if (atp_readl_base(atpdev, 0x38) == 0xffffffff)
+                       break;
+               for (m = 0; m < 2; m++) {
+                       atpdev->global_map[m] = 0;
+                       for (k = 0; k < 4; k++) {
+                               atp_writew_base(atpdev, 0x3c, n++);
+                               ((unsigned long *)&setupdata[m][0])[k] = atp_readl_base(atpdev, 0x38);
+                       }
+                       for (k = 0; k < 4; k++) {
+                               atp_writew_base(atpdev, 0x3c, n++);
+                               ((unsigned long *)&atpdev->sp[m][0])[k] = atp_readl_base(atpdev, 0x38);
+                       }
+                       n += 8;
+               }
+       }
+       c = atp_readb_base(atpdev, 0x29);
+       atp_writeb_base(atpdev, 0x29, c & 0xfb);
+       for (c = 0; c < 2; c++) {
+               atpdev->ultra_map[c] = 0;
+               atpdev->async[c] = 0;
                for (k = 0; k < 16; k++) {
-                       if (!atp_dev->id[j][k].prd_table)
-                               continue;
-                       pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus);
-                       atp_dev->id[j][k].prd_table = NULL;
+                       n = 1 << k;
+                       if (atpdev->sp[c][k] > 1)
+                               atpdev->ultra_map[c] |= n;
+                       else
+                               if (atpdev->sp[c][k] == 0)
+                                       atpdev->async[c] |= n;
+               }
+               atpdev->async[c] = ~(atpdev->async[c]);
+
+               if (atpdev->global_map[c] == 0) {
+                       k = setupdata[c][1];
+                       if ((k & 0x40) != 0)
+                               atpdev->global_map[c] |= 0x20;
+                       k &= 0x07;
+                       atpdev->global_map[c] |= k;
+                       if ((setupdata[c][2] & 0x04) != 0)
+                               atpdev->global_map[c] |= 0x08;
+                       atpdev->host_id[c] = setupdata[c][0] & 0x07;
                }
        }
-}
 
-static int atp870u_init_tables(struct Scsi_Host *host)
-{
-       struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
-       int c,k;
-       for(c=0;c < 2;c++) {
-               for(k=0;k<16;k++) {
-                               atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prd_bus));
-                               if (!atp_dev->id[c][k].prd_table) {
-                                       printk("atp870u_init_tables fail\n");
-                               atp870u_free_tables(host);
-                               return -ENOMEM;
-                       }
-                       atp_dev->id[c][k].prdaddr = atp_dev->id[c][k].prd_bus;
-                       atp_dev->id[c][k].devsp=0x20;
-                       atp_dev->id[c][k].devtype = 0x7f;
-                       atp_dev->id[c][k].curr_req = NULL;                         
-               }
-                               
-               atp_dev->active_id[c] = 0;
-               atp_dev->wide_id[c] = 0;
-               atp_dev->host_id[c] = 0x07;
-               atp_dev->quhd[c] = 0;
-               atp_dev->quend[c] = 0;
-               atp_dev->last_cmd[c] = 0xff;
-               atp_dev->in_snd[c] = 0;
-               atp_dev->in_int[c] = 0;
-               
-               for (k = 0; k < qcnt; k++) {
-                         atp_dev->quereq[c][k] = NULL;
-               }                          
-               for (k = 0; k < 16; k++) {
-                          atp_dev->id[c][k].curr_req = NULL;
-                          atp_dev->sp[c][k] = 0x04;
-               }                  
-       }
-       return 0;
+       k = atp_readb_base(atpdev, 0x28) & 0x8f;
+       k |= 0x10;
+       atp_writeb_base(atpdev, 0x28, k);
+       atp_writeb_pci(atpdev, 0, 1, 0x80);
+       atp_writeb_pci(atpdev, 1, 1, 0x80);
+       mdelay(100);
+       atp_writeb_pci(atpdev, 0, 1, 0);
+       atp_writeb_pci(atpdev, 1, 1, 0);
+       mdelay(1000);
+       atp_readb_io(atpdev, 0, 0x1b);
+       atp_readb_io(atpdev, 0, 0x17);
+       atp_readb_io(atpdev, 1, 0x1b);
+       atp_readb_io(atpdev, 1, 0x17);
+
+       k = atpdev->host_id[0];
+       if (k > 7)
+               k = (k & 0x07) | 0x40;
+       atp_set_host_id(atpdev, 0, k);
+
+       k = atpdev->host_id[1];
+       if (k > 7)
+               k = (k & 0x07) | 0x40;
+       atp_set_host_id(atpdev, 1, k);
+
+       mdelay(600); /* this delay used to be called tscam_885() */
+       dev_info(&pdev->dev, "Scanning Channel A SCSI Device ...\n");
+       atp_is(atpdev, 0, true, atp_readb_io(atpdev, 0, 0x1b) >> 7);
+       atp_writeb_io(atpdev, 0, 0x16, 0x80);
+       dev_info(&pdev->dev, "Scanning Channel B SCSI Device ...\n");
+       atp_is(atpdev, 1, true, atp_readb_io(atpdev, 1, 0x1b) >> 7);
+       atp_writeb_io(atpdev, 1, 0x16, 0x80);
+       k = atp_readb_base(atpdev, 0x28) & 0xcf;
+       k |= 0xc0;
+       atp_writeb_base(atpdev, 0x28, k);
+       k = atp_readb_base(atpdev, 0x1f) | 0x80;
+       atp_writeb_base(atpdev, 0x1f, k);
+       k = atp_readb_base(atpdev, 0x29) | 0x01;
+       atp_writeb_base(atpdev, 0x29, k);
+       shpnt->max_id = 16;
+       shpnt->max_lun = (atpdev->global_map[0] & 0x07) + 1;
+       shpnt->max_channel = 1;
+       shpnt->this_id = atpdev->host_id[0];
 }
 
 /* return non-zero on detection */
 static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       unsigned char k, m, c;
-       unsigned long flags;
-       unsigned int base_io, tmport, error,n;
-       unsigned char host_id;
        struct Scsi_Host *shpnt = NULL;
-       struct atp_unit *atpdev, *p;
-       unsigned char setupdata[2][16];
-       int count = 0;
+       struct atp_unit *atpdev;
+       int err;
 
-       atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL);
-       if (!atpdev)
-               return -ENOMEM;
+       if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610 && pdev->revision < 2) {
+               dev_err(&pdev->dev, "ATP850S chips (AEC6710L/F cards) are not supported.\n");
+               return -ENODEV;
+       }
 
-       if (pci_enable_device(pdev))
-               goto err_eio;
+       err = pci_enable_device(pdev);
+       if (err)
+               goto fail;
 
-        if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
-                printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
-        } else {
+       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
                 printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
-               goto err_eio;
+                err = -EIO;
+                goto disable_device;
         }
 
-       /*
-        * It's probably easier to weed out some revisions like
-        * this than via the PCI device table
-        */
-       if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
-               atpdev->chip_ver = pdev->revision;
-               if (atpdev->chip_ver < 2)
-                       goto err_eio;
+       err = pci_request_regions(pdev, "atp870u");
+       if (err)
+               goto disable_device;
+       pci_set_master(pdev);
+
+        err = -ENOMEM;
+       shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
+       if (!shpnt)
+               goto release_region;
+
+       atpdev = shost_priv(shpnt);
+
+       atpdev->host = shpnt;
+       atpdev->pdev = pdev;
+       pci_set_drvdata(pdev, atpdev);
+
+       shpnt->io_port = pci_resource_start(pdev, 0);
+       shpnt->io_port &= 0xfffffff8;
+       shpnt->n_io_port = pci_resource_len(pdev, 0);
+       atpdev->baseport = shpnt->io_port;
+       shpnt->unique_id = shpnt->io_port;
+       shpnt->irq = pdev->irq;
+
+       err = atp870u_init_tables(shpnt);
+       if (err) {
+               dev_err(&pdev->dev, "Unable to allocate tables for Acard controller\n");
+               goto unregister;
        }
 
-       switch (ent->device) {
-       case PCI_DEVICE_ID_ARTOP_AEC7612UW:
-       case PCI_DEVICE_ID_ARTOP_AEC7612SUW:
-       case ATP880_DEVID1:     
-       case ATP880_DEVID2:     
-       case ATP885_DEVID:      
-               atpdev->chip_ver = 0x04;
-       default:
-               break;
+       if (is880(atpdev))
+               atp880_init(shpnt);
+       else if (is885(atpdev))
+               atp885_init(shpnt);
+       else
+               atp870_init(shpnt);
+
+       err = request_irq(shpnt->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt);
+       if (err) {
+               dev_err(&pdev->dev, "Unable to allocate IRQ %d.\n", shpnt->irq);
+               goto free_tables;
        }
-       base_io = pci_resource_start(pdev, 0);
-       base_io &= 0xfffffff8;
-
-       if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
-               atpdev->chip_ver = pdev->revision;
-               pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
-
-               host_id = inb(base_io + 0x39);
-               host_id >>= 0x04;
-
-               printk(KERN_INFO "   ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
-                       "    IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
-               atpdev->ioport[0] = base_io + 0x40;
-               atpdev->pciport[0] = base_io + 0x28;
-               atpdev->dev_id = ent->device;
-               atpdev->host_id[0] = host_id;
-
-               tmport = base_io + 0x22;
-               atpdev->scam_on = inb(tmport);
-               tmport += 0x13;
-               atpdev->global_map[0] = inb(tmport);
-               tmport += 0x07;
-               atpdev->ultra_map[0] = inw(tmport);
-
-               n = 0x3f09;
-next_fblk_880:
-               if (n >= 0x4000)
-                       goto flash_ok_880;
-
-               m = 0;
-               outw(n, base_io + 0x34);
-               n += 0x0002;
-               if (inb(base_io + 0x30) == 0xff)
-                       goto flash_ok_880;
-
-               atpdev->sp[0][m++] = inb(base_io + 0x30);
-               atpdev->sp[0][m++] = inb(base_io + 0x31);
-               atpdev->sp[0][m++] = inb(base_io + 0x32);
-               atpdev->sp[0][m++] = inb(base_io + 0x33);
-               outw(n, base_io + 0x34);
-               n += 0x0002;
-               atpdev->sp[0][m++] = inb(base_io + 0x30);
-               atpdev->sp[0][m++] = inb(base_io + 0x31);
-               atpdev->sp[0][m++] = inb(base_io + 0x32);
-               atpdev->sp[0][m++] = inb(base_io + 0x33);
-               outw(n, base_io + 0x34);
-               n += 0x0002;
-               atpdev->sp[0][m++] = inb(base_io + 0x30);
-               atpdev->sp[0][m++] = inb(base_io + 0x31);
-               atpdev->sp[0][m++] = inb(base_io + 0x32);
-               atpdev->sp[0][m++] = inb(base_io + 0x33);
-               outw(n, base_io + 0x34);
-               n += 0x0002;
-               atpdev->sp[0][m++] = inb(base_io + 0x30);
-               atpdev->sp[0][m++] = inb(base_io + 0x31);
-               atpdev->sp[0][m++] = inb(base_io + 0x32);
-               atpdev->sp[0][m++] = inb(base_io + 0x33);
-               n += 0x0018;
-               goto next_fblk_880;
-flash_ok_880:
-               outw(0, base_io + 0x34);
-               atpdev->ultra_map[0] = 0;
-               atpdev->async[0] = 0;
-               for (k = 0; k < 16; k++) {
-                       n = 1;
-                       n = n << k;
-                       if (atpdev->sp[0][k] > 1) {
-                               atpdev->ultra_map[0] |= n;
-                       } else {
-                               if (atpdev->sp[0][k] == 0)
-                                       atpdev->async[0] |= n;
-                       }
-               }
-               atpdev->async[0] = ~(atpdev->async[0]);
-               outb(atpdev->global_map[0], base_io + 0x35);
-               shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
-               if (!shpnt)
-                       goto err_nomem;
-
-               p = (struct atp_unit *)&shpnt->hostdata;
-
-               atpdev->host = shpnt;
-               atpdev->pdev = pdev;
-               pci_set_drvdata(pdev, p);
-               memcpy(p, atpdev, sizeof(*atpdev));
-               if (atp870u_init_tables(shpnt) < 0) {
-                       printk(KERN_ERR "Unable to allocate tables for Acard controller\n");
-                       goto unregister;
-               }
-
-               if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp880i", shpnt)) {
-                       printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
-                       goto free_tables;
-               }
-
-               spin_lock_irqsave(shpnt->host_lock, flags);
-               tmport = base_io + 0x38;
-               k = inb(tmport) & 0x80;
-               outb(k, tmport);
-               tmport += 0x03;
-               outb(0x20, tmport);
-               mdelay(32);
-               outb(0, tmport);
-               mdelay(32);
-               tmport = base_io + 0x5b;
-               inb(tmport);
-               tmport -= 0x04;
-               inb(tmport);
-               tmport = base_io + 0x40;
-               outb((host_id | 0x08), tmport);
-               tmport += 0x18;
-               outb(0, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0)
-                       mdelay(1);
-               tmport -= 0x08;
-               inb(tmport);
-               tmport = base_io + 0x41;
-               outb(8, tmport++);
-               outb(0x7f, tmport);
-               tmport = base_io + 0x51;
-               outb(0x20, tmport);
-
-               tscam(shpnt);
-               is880(p, base_io);
-               tmport = base_io + 0x38;
-               outb(0xb0, tmport);
-               shpnt->max_id = 16;
-               shpnt->this_id = host_id;
-               shpnt->unique_id = base_io;
-               shpnt->io_port = base_io;
-               shpnt->n_io_port = 0x60;        /* Number of bytes of I/O space used */
-               shpnt->irq = pdev->irq;                 
-       } else if (ent->device == ATP885_DEVID) {       
-                       printk(KERN_INFO "   ACARD AEC-67162 PCI Ultra3 LVD Host Adapter:  IO:%x, IRQ:%d.\n"
-                              , base_io, pdev->irq);
-               
-               atpdev->pdev = pdev;
-               atpdev->dev_id  = ent->device;
-               atpdev->baseport = base_io;
-               atpdev->ioport[0] = base_io + 0x80;
-               atpdev->ioport[1] = base_io + 0xc0;
-               atpdev->pciport[0] = base_io + 0x40;
-               atpdev->pciport[1] = base_io + 0x50;
-                               
-               shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
-               if (!shpnt)
-                       goto err_nomem;
-               
-               p = (struct atp_unit *)&shpnt->hostdata;
-               
-               atpdev->host = shpnt;
-               atpdev->pdev = pdev;
-               pci_set_drvdata(pdev, p);
-               memcpy(p, atpdev, sizeof(struct atp_unit));
-               if (atp870u_init_tables(shpnt) < 0)
-                       goto unregister;
-                       
-#ifdef ED_DBGP         
-       printk("request_irq() shpnt %p hostdata %p\n", shpnt, p);
-#endif         
-               if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt)) {
-                               printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
-                       goto free_tables;
-               }
-               
-               spin_lock_irqsave(shpnt->host_lock, flags);                                             
-                               
-               c=inb(base_io + 0x29);
-               outb((c | 0x04),base_io + 0x29);
-               
-               n=0x1f80;
-next_fblk_885:
-               if (n >= 0x2000) {
-                  goto flash_ok_885;
-               }
-               outw(n,base_io + 0x3c);
-               if (inl(base_io + 0x38) == 0xffffffff) {
-                  goto flash_ok_885;
-               }
-               for (m=0; m < 2; m++) {
-                   p->global_map[m]= 0;
-                   for (k=0; k < 4; k++) {
-                       outw(n++,base_io + 0x3c);
-                       ((unsigned long *)&setupdata[m][0])[k]=inl(base_io + 0x38);
-                   }
-                   for (k=0; k < 4; k++) {
-                       outw(n++,base_io + 0x3c);
-                       ((unsigned long *)&p->sp[m][0])[k]=inl(base_io + 0x38);
-                   }
-                   n += 8;
-               }
-               goto next_fblk_885;
-flash_ok_885:
-#ifdef ED_DBGP
-               printk( "Flash Read OK\n");
-#endif 
-               c=inb(base_io + 0x29);
-               outb((c & 0xfb),base_io + 0x29);
-               for (c=0;c < 2;c++) {
-                   p->ultra_map[c]=0;
-                   p->async[c] = 0;
-                   for (k=0; k < 16; k++) {
-                       n=1;
-                       n = n << k;
-                       if (p->sp[c][k] > 1) {
-                          p->ultra_map[c] |= n;
-                       } else {
-                          if (p->sp[c][k] == 0) {
-                             p->async[c] |= n;
-                          }
-                       }
-                   }
-                   p->async[c] = ~(p->async[c]);
-
-                   if (p->global_map[c] == 0) {
-                      k=setupdata[c][1];
-                      if ((k & 0x40) != 0)
-                         p->global_map[c] |= 0x20;
-                      k &= 0x07;
-                      p->global_map[c] |= k;
-                      if ((setupdata[c][2] & 0x04) != 0)
-                         p->global_map[c] |= 0x08;
-                      p->host_id[c] = setupdata[c][0] & 0x07;
-                   }
-               }
-
-               k = inb(base_io + 0x28) & 0x8f;
-               k |= 0x10;
-               outb(k, base_io + 0x28);
-               outb(0x80, base_io + 0x41);
-               outb(0x80, base_io + 0x51);
-               mdelay(100);
-               outb(0, base_io + 0x41);
-               outb(0, base_io + 0x51);
-               mdelay(1000);
-               inb(base_io + 0x9b);
-               inb(base_io + 0x97);
-               inb(base_io + 0xdb);
-               inb(base_io + 0xd7);
-               tmport = base_io + 0x80;
-               k=p->host_id[0];
-               if (k > 7)
-                  k = (k & 0x07) | 0x40;
-               k |= 0x08;
-               outb(k, tmport);
-               tmport += 0x18;
-               outb(0, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0)
-                       cpu_relax();
-       
-               tmport -= 0x08;
-               inb(tmport);
-               tmport = base_io + 0x81;
-               outb(8, tmport++);
-               outb(0x7f, tmport);
-               tmport = base_io + 0x91;
-               outb(0x20, tmport);
-
-               tmport = base_io + 0xc0;
-               k=p->host_id[1];
-               if (k > 7)
-                  k = (k & 0x07) | 0x40;
-               k |= 0x08;
-               outb(k, tmport);
-               tmport += 0x18;
-               outb(0, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0)
-                       cpu_relax();
-
-               tmport -= 0x08;
-               inb(tmport);
-               tmport = base_io + 0xc1;
-               outb(8, tmport++);
-               outb(0x7f, tmport);
-               tmport = base_io + 0xd1;
-               outb(0x20, tmport);
-
-               tscam_885();
-               printk(KERN_INFO "   Scanning Channel A SCSI Device ...\n");
-               is885(p, base_io + 0x80, 0);
-               printk(KERN_INFO "   Scanning Channel B SCSI Device ...\n");
-               is885(p, base_io + 0xc0, 1);
-
-               k = inb(base_io + 0x28) & 0xcf;
-               k |= 0xc0;
-               outb(k, base_io + 0x28);
-               k = inb(base_io + 0x1f) | 0x80;
-               outb(k, base_io + 0x1f);
-               k = inb(base_io + 0x29) | 0x01;
-               outb(k, base_io + 0x29);
-#ifdef ED_DBGP
-               //printk("atp885: atp_host[0] 0x%p\n", atp_host[0]);
-#endif         
-               shpnt->max_id = 16;
-               shpnt->max_lun = (p->global_map[0] & 0x07) + 1;
-               shpnt->max_channel = 1;
-               shpnt->this_id = p->host_id[0];
-               shpnt->unique_id = base_io;
-               shpnt->io_port = base_io;
-               shpnt->n_io_port = 0xff;        /* Number of bytes of I/O space used */
-               shpnt->irq = pdev->irq;
-                               
-       } else {
-               error = pci_read_config_byte(pdev, 0x49, &host_id);
-
-               printk(KERN_INFO "   ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d "
-                       "IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
-
-               atpdev->ioport[0] = base_io;
-               atpdev->pciport[0] = base_io + 0x20;
-               atpdev->dev_id = ent->device;
-               host_id &= 0x07;
-               atpdev->host_id[0] = host_id;
-               tmport = base_io + 0x22;
-               atpdev->scam_on = inb(tmport);
-               tmport += 0x0b;
-               atpdev->global_map[0] = inb(tmport++);
-               atpdev->ultra_map[0] = inw(tmport);
-
-               if (atpdev->ultra_map[0] == 0) {
-                       atpdev->scam_on = 0x00;
-                       atpdev->global_map[0] = 0x20;
-                       atpdev->ultra_map[0] = 0xffff;
-               }
 
-               shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
-               if (!shpnt)
-                       goto err_nomem;
+       err = scsi_add_host(shpnt, &pdev->dev);
+       if (err)
+               goto scsi_add_fail;
+       scsi_scan_host(shpnt);
 
-               p = (struct atp_unit *)&shpnt->hostdata;
-               
-               atpdev->host = shpnt;
-               atpdev->pdev = pdev;
-               pci_set_drvdata(pdev, p);
-               memcpy(p, atpdev, sizeof(*atpdev));
-               if (atp870u_init_tables(shpnt) < 0)
-                       goto unregister;
-
-               if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870i", shpnt)) {
-                       printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
-                       goto free_tables;
-               }
-
-               spin_lock_irqsave(shpnt->host_lock, flags);
-               if (atpdev->chip_ver > 0x07) {  /* check if atp876 chip then enable terminator */
-                       tmport = base_io + 0x3e;
-                       outb(0x00, tmport);
-               }
-               tmport = base_io + 0x3a;
-               k = (inb(tmport) & 0xf3) | 0x10;
-               outb(k, tmport);
-               outb((k & 0xdf), tmport);
-               mdelay(32);
-               outb(k, tmport);
-               mdelay(32);
-               tmport = base_io;
-               outb((host_id | 0x08), tmport);
-               tmport += 0x18;
-               outb(0, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0)
-                       mdelay(1);
-
-               tmport -= 0x08;
-               inb(tmport);
-               tmport = base_io + 1;
-               outb(8, tmport++);
-               outb(0x7f, tmport);
-               tmport = base_io + 0x11;
-               outb(0x20, tmport);
-
-               tscam(shpnt);
-               is870(p, base_io);
-               tmport = base_io + 0x3a;
-               outb((inb(tmport) & 0xef), tmport);
-               tmport++;
-               outb((inb(tmport) | 0x20), tmport);
-               if (atpdev->chip_ver == 4)
-                       shpnt->max_id = 16;
-               else            
-                       shpnt->max_id = 8;
-               shpnt->this_id = host_id;
-               shpnt->unique_id = base_io;
-               shpnt->io_port = base_io;
-               shpnt->n_io_port = 0x40;        /* Number of bytes of I/O space used */
-               shpnt->irq = pdev->irq;         
-       } 
-               spin_unlock_irqrestore(shpnt->host_lock, flags);
-               if(ent->device==ATP885_DEVID) {
-                       if(!request_region(base_io, 0xff, "atp870u")) /* Register the IO ports that we use */
-                               goto request_io_fail;
-               } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
-                       if(!request_region(base_io, 0x60, "atp870u")) /* Register the IO ports that we use */
-                               goto request_io_fail;
-               } else {
-                       if(!request_region(base_io, 0x40, "atp870u")) /* Register the IO ports that we use */
-                               goto request_io_fail;
-               }                               
-               count++;
-               if (scsi_add_host(shpnt, &pdev->dev))
-                       goto scsi_add_fail;
-               scsi_scan_host(shpnt);
-#ifdef ED_DBGP                 
-               printk("atp870u_prob : exit\n");
-#endif         
-               return 0;
+       return 0;
 
 scsi_add_fail:
-       printk("atp870u_prob:scsi_add_fail\n");
-       if(ent->device==ATP885_DEVID) {
-               release_region(base_io, 0xff);
-       } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
-               release_region(base_io, 0x60);
-       } else {
-               release_region(base_io, 0x40);
-       }
-request_io_fail:
-       printk("atp870u_prob:request_io_fail\n");
-       free_irq(pdev->irq, shpnt);
+       free_irq(shpnt->irq, shpnt);
 free_tables:
-       printk("atp870u_prob:free_table\n");
        atp870u_free_tables(shpnt);
 unregister:
-       printk("atp870u_prob:unregister\n");
        scsi_host_put(shpnt);
-       return -1;              
-err_eio:
-       kfree(atpdev);
-       return -EIO;
-err_nomem:
-       kfree(atpdev);
-       return -ENOMEM;
+release_region:
+       pci_release_regions(pdev);
+disable_device:
+       pci_disable_device(pdev);
+fail:
+       return err;
 }
 
 /* The abort command does not leave the device in a clean state where
@@ -3055,7 +1586,6 @@ static int atp870u_abort(struct scsi_cmnd * SCpnt)
 {
        unsigned char  j, k, c;
        struct scsi_cmnd *workrequ;
-       unsigned int tmport;
        struct atp_unit *dev;   
        struct Scsi_Host *host;
        host = SCpnt->device->host;
@@ -3065,18 +1595,13 @@ static int atp870u_abort(struct scsi_cmnd * SCpnt)
        printk(" atp870u: abort Channel = %x \n", c);
        printk("working=%x last_cmd=%x ", dev->working[c], dev->last_cmd[c]);
        printk(" quhdu=%x quendu=%x ", dev->quhd[c], dev->quend[c]);
-       tmport = dev->ioport[c];
        for (j = 0; j < 0x18; j++) {
-               printk(" r%2x=%2x", j, inb(tmport++));
+               printk(" r%2x=%2x", j, atp_readb_io(dev, c, j));
        }
-       tmport += 0x04;
-       printk(" r1c=%2x", inb(tmport));
-       tmport += 0x03;
-       printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd[c]);
-       tmport= dev->pciport[c];
-       printk(" d00=%2x", inb(tmport));
-       tmport += 0x02;
-       printk(" d02=%2x", inb(tmport));
+       printk(" r1c=%2x", atp_readb_io(dev, c, 0x1c));
+       printk(" r1f=%2x in_snd=%2x ", atp_readb_io(dev, c, 0x1f), dev->in_snd[c]);
+       printk(" d00=%2x", atp_readb_pci(dev, c, 0x00));
+       printk(" d02=%2x", atp_readb_pci(dev, c, 0x02));
        for(j=0;j<16;j++) {
           if (dev->id[c][j].curr_req != NULL) {
                workrequ = dev->id[c][j].curr_req;
@@ -3136,12 +1661,10 @@ static void atp870u_remove (struct pci_dev *pdev)
        
        
        scsi_remove_host(pshost);
-       printk(KERN_INFO "free_irq : %d\n",pshost->irq);
        free_irq(pshost->irq, pshost);
-       release_region(pshost->io_port, pshost->n_io_port);
-       printk(KERN_INFO "atp870u_free_tables : %p\n",pshost);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
        atp870u_free_tables(pshost);
-       printk(KERN_INFO "scsi_host_put : %p\n",pshost);
        scsi_host_put(pshost);
 }
 MODULE_LICENSE("GPL");
@@ -3185,52 +1708,26 @@ static struct pci_driver atp870u_driver = {
        .remove         = atp870u_remove,
 };
 
-static int __init atp870u_init(void)
-{
-#ifdef ED_DBGP 
-       printk("atp870u_init: Entry\n");
-#endif 
-       return pci_register_driver(&atp870u_driver);
-}
-
-static void __exit atp870u_exit(void)
-{
-#ifdef ED_DBGP 
-       printk("atp870u_exit: Entry\n");
-#endif
-       pci_unregister_driver(&atp870u_driver);
-}
-
-static void tscam_885(void)
-{
-       unsigned char i;
-
-       for (i = 0; i < 0x2; i++) {
-               mdelay(300);
-       }
-       return;
-}
-
-
+module_pci_driver(atp870u_driver);
 
-static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
+static void atp_is(struct atp_unit *dev, unsigned char c, bool wide_chip, unsigned char lvdmode)
 {
-       unsigned int tmport;
-       unsigned char i, j, k, rmb, n, lvdmode;
+       unsigned char i, j, k, rmb, n;
        unsigned short int m;
        static unsigned char mbuf[512];
-       static unsigned char satn[9] =  {0, 0, 0, 0, 0, 0, 0, 6, 6};
-       static unsigned char inqd[9] =  {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
-       static unsigned char synn[6] =  {0x80, 1, 3, 1, 0x19, 0x0e};
-       unsigned char synu[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
-       static unsigned char synw[6] =  {0x80, 1, 3, 1, 0x19, 0x0e};
-       unsigned char synuw[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
-       static unsigned char wide[6] =  {0x80, 1, 2, 3, 1, 0};
-       static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 };
-
-       lvdmode=inb(wkport + 0x1b) >> 7;
+       static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
+       static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
+       static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+       unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+       static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+       static unsigned char synw_870[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
+       unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+       static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
+       static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
 
        for (i = 0; i < 16; i++) {
+               if (!wide_chip && (i > 7))
+                       break;
                m = 1;
                m = m << i;
                if ((m & dev->active_id[c]) != 0) {
@@ -3240,192 +1737,172 @@ static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
                        printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_id[c]);
                        continue;
                }
-               tmport = wkport + 0x1b;
-               outb(0x01, tmport);
-               tmport = wkport + 0x01;
-               outb(0x08, tmport++);
-               outb(0x7f, tmport++);
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[c][i].devsp, tmport++);
-               
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
+               atp_writeb_io(dev, c, 0x1b, wide_chip ? 0x01 : 0x00);
+               atp_writeb_io(dev, c, 1, 0x08);
+               atp_writeb_io(dev, c, 2, 0x7f);
+               atp_writeb_io(dev, c, 3, satn[0]);
+               atp_writeb_io(dev, c, 4, satn[1]);
+               atp_writeb_io(dev, c, 5, satn[2]);
+               atp_writeb_io(dev, c, 6, satn[3]);
+               atp_writeb_io(dev, c, 7, satn[4]);
+               atp_writeb_io(dev, c, 8, satn[5]);
+               atp_writeb_io(dev, c, 0x0f, 0);
+               atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+               atp_writeb_io(dev, c, 0x12, 0);
+               atp_writeb_io(dev, c, 0x13, satn[6]);
+               atp_writeb_io(dev, c, 0x14, satn[7]);
                j = i;
                if ((j & 0x08) != 0) {
                        j = (j & 0x07) | 0x40;
                }
-               outb(j, tmport);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
+               atp_writeb_io(dev, c, 0x15, j);
+               atp_writeb_io(dev, c, 0x18, satn[8]);
 
-               while ((inb(tmport) & 0x80) == 0x00)
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
                        cpu_relax();
-               tmport -= 0x08;
-               if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+               if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
                        continue;
-               }
-               while (inb(tmport) != 0x8e)
+
+               while (atp_readb_io(dev, c, 0x17) != 0x8e)
                        cpu_relax();
+
                dev->active_id[c] |= m;
 
-               tmport = wkport + 0x10;
-               outb(0x30, tmport);
-               tmport = wkport + 0x14;
-               outb(0x00, tmport);
+               atp_writeb_io(dev, c, 0x10, 0x30);
+               if (is885(dev) || is880(dev))
+                       atp_writeb_io(dev, c, 0x14, 0x00);
+               else /* result of is870() merge - is this a bug? */
+                       atp_writeb_io(dev, c, 0x04, 0x00);
 
 phase_cmd:
-               tmport = wkport + 0x18;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00)
+               atp_writeb_io(dev, c, 0x18, 0x08);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
                        cpu_relax();
-               tmport -= 0x08;
-               j = inb(tmport);
+
+               j = atp_readb_io(dev, c, 0x17);
                if (j != 0x16) {
-                       tmport = wkport + 0x10;
-                       outb(0x41, tmport);
+                       atp_writeb_io(dev, c, 0x10, 0x41);
                        goto phase_cmd;
                }
 sel_ok:
-               tmport = wkport + 0x03;
-               outb(inqd[0], tmport++);
-               outb(inqd[1], tmport++);
-               outb(inqd[2], tmport++);
-               outb(inqd[3], tmport++);
-               outb(inqd[4], tmport++);
-               outb(inqd[5], tmport);
-               tmport += 0x07;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[c][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(inqd[6], tmport++);
-               outb(inqd[7], tmport++);
-               tmport += 0x03;
-               outb(inqd[8], tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00)
+               atp_writeb_io(dev, c, 3, inqd[0]);
+               atp_writeb_io(dev, c, 4, inqd[1]);
+               atp_writeb_io(dev, c, 5, inqd[2]);
+               atp_writeb_io(dev, c, 6, inqd[3]);
+               atp_writeb_io(dev, c, 7, inqd[4]);
+               atp_writeb_io(dev, c, 8, inqd[5]);
+               atp_writeb_io(dev, c, 0x0f, 0);
+               atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+               atp_writeb_io(dev, c, 0x12, 0);
+               atp_writeb_io(dev, c, 0x13, inqd[6]);
+               atp_writeb_io(dev, c, 0x14, inqd[7]);
+               atp_writeb_io(dev, c, 0x18, inqd[8]);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
                        cpu_relax();
-               tmport -= 0x08;
-               if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+               if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
                        continue;
-               }
-               while (inb(tmport) != 0x8e)
+
+               while (atp_readb_io(dev, c, 0x17) != 0x8e)
                        cpu_relax();
-               tmport = wkport + 0x1b;
-               outb(0x00, tmport);
-               tmport = wkport + 0x18;
-               outb(0x08, tmport);
-               tmport += 0x07;
+
+               if (wide_chip)
+                       atp_writeb_io(dev, c, 0x1b, 0x00);
+
+               atp_writeb_io(dev, c, 0x18, 0x08);
                j = 0;
 rd_inq_data:
-               k = inb(tmport);
+               k = atp_readb_io(dev, c, 0x1f);
                if ((k & 0x01) != 0) {
-                       tmport -= 0x06;
-                       mbuf[j++] = inb(tmport);
-                       tmport += 0x06;
+                       mbuf[j++] = atp_readb_io(dev, c, 0x19);
                        goto rd_inq_data;
                }
                if ((k & 0x80) == 0) {
                        goto rd_inq_data;
                }
-               tmport -= 0x08;
-               j = inb(tmport);
+               j = atp_readb_io(dev, c, 0x17);
                if (j == 0x16) {
                        goto inq_ok;
                }
-               tmport = wkport + 0x10;
-               outb(0x46, tmport);
-               tmport += 0x02;
-               outb(0, tmport++);
-               outb(0, tmport++);
-               outb(0, tmport++);
-               tmport += 0x03;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00)
+               atp_writeb_io(dev, c, 0x10, 0x46);
+               atp_writeb_io(dev, c, 0x12, 0);
+               atp_writeb_io(dev, c, 0x13, 0);
+               atp_writeb_io(dev, c, 0x14, 0);
+               atp_writeb_io(dev, c, 0x18, 0x08);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
                        cpu_relax();
-               tmport -= 0x08;
-               if (inb(tmport) != 0x16) {
+
+               if (atp_readb_io(dev, c, 0x17) != 0x16)
                        goto sel_ok;
-               }
+
 inq_ok:
                mbuf[36] = 0;
-               printk( KERN_INFO"         ID: %2d  %s\n", i, &mbuf[8]);
+               printk(KERN_INFO "         ID: %2d  %s\n", i, &mbuf[8]);
                dev->id[c][i].devtype = mbuf[0];
                rmb = mbuf[1];
                n = mbuf[7];
+               if (!wide_chip)
+                       goto not_wide;
                if ((mbuf[7] & 0x60) == 0) {
                        goto not_wide;
                }
-               if ((i < 8) && ((dev->global_map[c] & 0x20) == 0)) {
-                       goto not_wide;
+               if (is885(dev) || is880(dev)) {
+                       if ((i < 8) && ((dev->global_map[c] & 0x20) == 0))
+                               goto not_wide;
+               } else { /* result of is870() merge - is this a bug? */
+                       if ((dev->global_map[c] & 0x20) == 0)
+                               goto not_wide;
                }
                if (lvdmode == 0) {
-                  goto chg_wide;
-               }
-               if (dev->sp[c][i] != 0x04) {    // force u2
-                  goto chg_wide;
-               }
-
-               tmport = wkport + 0x1b;
-               outb(0x01, tmport);
-               tmport = wkport + 0x03;
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[c][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
+                       goto chg_wide;
+               }
+               if (dev->sp[c][i] != 0x04)      // force u2
+               {
+                       goto chg_wide;
+               }
+
+               atp_writeb_io(dev, c, 0x1b, 0x01);
+               atp_writeb_io(dev, c, 3, satn[0]);
+               atp_writeb_io(dev, c, 4, satn[1]);
+               atp_writeb_io(dev, c, 5, satn[2]);
+               atp_writeb_io(dev, c, 6, satn[3]);
+               atp_writeb_io(dev, c, 7, satn[4]);
+               atp_writeb_io(dev, c, 8, satn[5]);
+               atp_writeb_io(dev, c, 0x0f, 0);
+               atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+               atp_writeb_io(dev, c, 0x12, 0);
+               atp_writeb_io(dev, c, 0x13, satn[6]);
+               atp_writeb_io(dev, c, 0x14, satn[7]);
+               atp_writeb_io(dev, c, 0x18, satn[8]);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
                        cpu_relax();
-               tmport -= 0x08;
-               if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+               if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
                        continue;
-               }
-               while (inb(tmport) != 0x8e)
+
+               while (atp_readb_io(dev, c, 0x17) != 0x8e)
                        cpu_relax();
+
 try_u3:
                j = 0;
-               tmport = wkport + 0x14;
-               outb(0x09, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(u3[j++], tmport);
-                               tmport += 0x06;
-                       }
+               atp_writeb_io(dev, c, 0x14, 0x09);
+               atp_writeb_io(dev, c, 0x18, 0x20);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+                       if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+                               atp_writeb_io(dev, c, 0x19, u3[j++]);
                        cpu_relax();
                }
-               tmport -= 0x08;
-               while ((inb(tmport) & 0x80) == 0x00)
+
+               while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
                        cpu_relax();
-               j = inb(tmport) & 0x0f;
+
+               j = atp_readb_io(dev, c, 0x17) & 0x0f;
                if (j == 0x0f) {
                        goto u3p_in;
                }
@@ -3437,19 +1914,13 @@ try_u3:
                }
                continue;
 u3p_out:
-               tmport = wkport + 0x18;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(0, tmport);
-                               tmport += 0x06;
-                       }
+               atp_writeb_io(dev, c, 0x18, 0x20);
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+                       if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+                               atp_writeb_io(dev, c, 0x19, 0);
                        cpu_relax();
                }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
+               j = atp_readb_io(dev, c, 0x17) & 0x0f;
                if (j == 0x0f) {
                        goto u3p_in;
                }
@@ -3461,25 +1932,19 @@ u3p_out:
                }
                continue;
 u3p_in:
-               tmport = wkport + 0x14;
-               outb(0x09, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
+               atp_writeb_io(dev, c, 0x14, 0x09);
+               atp_writeb_io(dev, c, 0x18, 0x20);
                k = 0;
 u3p_in1:
-               j = inb(tmport);
+               j = atp_readb_io(dev, c, 0x1f);
                if ((j & 0x01) != 0) {
-                       tmport -= 0x06;
-                       mbuf[k++] = inb(tmport);
-                       tmport += 0x06;
+                       mbuf[k++] = atp_readb_io(dev, c, 0x19);
                        goto u3p_in1;
                }
                if ((j & 0x80) == 0x00) {
                        goto u3p_in1;
                }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
+               j = atp_readb_io(dev, c, 0x17) & 0x0f;
                if (j == 0x0f) {
                        goto u3p_in;
                }
@@ -3491,16 +1956,13 @@ u3p_in1:
                }
                continue;
 u3p_cmd:
-               tmport = wkport + 0x10;
-               outb(0x30, tmport);
-               tmport = wkport + 0x14;
-               outb(0x00, tmport);
-               tmport += 0x04;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00);
-               tmport -= 0x08;
-               j = inb(tmport);
+               atp_writeb_io(dev, c, 0x10, 0x30);
+               atp_writeb_io(dev, c, 0x14, 0x00);
+               atp_writeb_io(dev, c, 0x18, 0x08);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00);
+
+               j = atp_readb_io(dev, c, 0x17);
                if (j != 0x16) {
                        if (j == 0x4e) {
                                goto u3p_out;
@@ -3527,54 +1989,44 @@ u3p_cmd:
                        continue;
                }
 chg_wide:
-               tmport = wkport + 0x1b;
-               outb(0x01, tmport);
-               tmport = wkport + 0x03;
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[c][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
+               atp_writeb_io(dev, c, 0x1b, 0x01);
+               atp_writeb_io(dev, c, 3, satn[0]);
+               atp_writeb_io(dev, c, 4, satn[1]);
+               atp_writeb_io(dev, c, 5, satn[2]);
+               atp_writeb_io(dev, c, 6, satn[3]);
+               atp_writeb_io(dev, c, 7, satn[4]);
+               atp_writeb_io(dev, c, 8, satn[5]);
+               atp_writeb_io(dev, c, 0x0f, 0);
+               atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+               atp_writeb_io(dev, c, 0x12, 0);
+               atp_writeb_io(dev, c, 0x13, satn[6]);
+               atp_writeb_io(dev, c, 0x14, satn[7]);
+               atp_writeb_io(dev, c, 0x18, satn[8]);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
                        cpu_relax();
-               tmport -= 0x08;
-               if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+               if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
                        continue;
-               }
-               while (inb(tmport) != 0x8e)
+
+               while (atp_readb_io(dev, c, 0x17) != 0x8e)
                        cpu_relax();
+
 try_wide:
                j = 0;
-               tmport = wkport + 0x14;
-               outb(0x05, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(wide[j++], tmport);
-                               tmport += 0x06;
-                       }
+               atp_writeb_io(dev, c, 0x14, 0x05);
+               atp_writeb_io(dev, c, 0x18, 0x20);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+                       if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+                               atp_writeb_io(dev, c, 0x19, wide[j++]);
                        cpu_relax();
                }
-               tmport -= 0x08;
-               while ((inb(tmport) & 0x80) == 0x00)
+
+               while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
                        cpu_relax();
-               j = inb(tmport) & 0x0f;
+
+               j = atp_readb_io(dev, c, 0x17) & 0x0f;
                if (j == 0x0f) {
                        goto widep_in;
                }
@@ -3586,19 +2038,13 @@ try_wide:
                }
                continue;
 widep_out:
-               tmport = wkport + 0x18;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
-                               outb(0, tmport);
-                               tmport += 0x06;
-                       }
+               atp_writeb_io(dev, c, 0x18, 0x20);
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+                       if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+                               atp_writeb_io(dev, c, 0x19, 0);
                        cpu_relax();
                }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
+               j = atp_readb_io(dev, c, 0x17) & 0x0f;
                if (j == 0x0f) {
                        goto widep_in;
                }
@@ -3610,25 +2056,19 @@ widep_out:
                }
                continue;
 widep_in:
-               tmport = wkport + 0x14;
-               outb(0xff, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
+               atp_writeb_io(dev, c, 0x14, 0xff);
+               atp_writeb_io(dev, c, 0x18, 0x20);
                k = 0;
 widep_in1:
-               j = inb(tmport);
+               j = atp_readb_io(dev, c, 0x1f);
                if ((j & 0x01) != 0) {
-                       tmport -= 0x06;
-                       mbuf[k++] = inb(tmport);
-                       tmport += 0x06;
+                       mbuf[k++] = atp_readb_io(dev, c, 0x19);
                        goto widep_in1;
                }
                if ((j & 0x80) == 0x00) {
                        goto widep_in1;
                }
-               tmport -= 0x08;
-               j = inb(tmport) & 0x0f;
+               j = atp_readb_io(dev, c, 0x17) & 0x0f;
                if (j == 0x0f) {
                        goto widep_in;
                }
@@ -3640,17 +2080,14 @@ widep_in1:
                }
                continue;
 widep_cmd:
-               tmport = wkport + 0x10;
-               outb(0x30, tmport);
-               tmport = wkport + 0x14;
-               outb(0x00, tmport);
-               tmport += 0x04;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00)
+               atp_writeb_io(dev, c, 0x10, 0x30);
+               atp_writeb_io(dev, c, 0x14, 0x00);
+               atp_writeb_io(dev, c, 0x18, 0x08);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
                        cpu_relax();
-               tmport -= 0x08;
-               j = inb(tmport);
+
+               j = atp_readb_io(dev, c, 0x17);
                if (j != 0x16) {
                        if (j == 0x4e) {
                                goto widep_out;
@@ -3673,88 +2110,81 @@ widep_cmd:
                m = m << i;
                dev->wide_id[c] |= m;
 not_wide:
-               if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) ||
-                   ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
+               if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) || ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
                        m = 1;
                        m = m << i;
                        if ((dev->async[c] & m) != 0) {
-                          goto set_sync;
+                               goto set_sync;
                        }
                }
                continue;
 set_sync:
-               if (dev->sp[c][i] == 0x02) {
-                  synu[4]=0x0c;
-                  synuw[4]=0x0c;
+               if ((!is885(dev) && !is880(dev)) || (dev->sp[c][i] == 0x02)) {
+                       synu[4] = 0x0c;
+                       synuw[4] = 0x0c;
                } else {
-                  if (dev->sp[c][i] >= 0x03) {
-                     synu[4]=0x0a;
-                     synuw[4]=0x0a;
-                  }
+                       if (dev->sp[c][i] >= 0x03) {
+                               synu[4] = 0x0a;
+                               synuw[4] = 0x0a;
+                       }
                }
-               tmport = wkport + 0x1b;
                j = 0;
                if ((m & dev->wide_id[c]) != 0) {
                        j |= 0x01;
                }
-               outb(j, tmport);
-               tmport = wkport + 0x03;
-               outb(satn[0], tmport++);
-               outb(satn[1], tmport++);
-               outb(satn[2], tmport++);
-               outb(satn[3], tmport++);
-               outb(satn[4], tmport++);
-               outb(satn[5], tmport++);
-               tmport += 0x06;
-               outb(0, tmport);
-               tmport += 0x02;
-               outb(dev->id[c][i].devsp, tmport++);
-               outb(0, tmport++);
-               outb(satn[6], tmport++);
-               outb(satn[7], tmport++);
-               tmport += 0x03;
-               outb(satn[8], tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0x00)
+               atp_writeb_io(dev, c, 0x1b, j);
+               atp_writeb_io(dev, c, 3, satn[0]);
+               atp_writeb_io(dev, c, 4, satn[1]);
+               atp_writeb_io(dev, c, 5, satn[2]);
+               atp_writeb_io(dev, c, 6, satn[3]);
+               atp_writeb_io(dev, c, 7, satn[4]);
+               atp_writeb_io(dev, c, 8, satn[5]);
+               atp_writeb_io(dev, c, 0x0f, 0);
+               atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+               atp_writeb_io(dev, c, 0x12, 0);
+               atp_writeb_io(dev, c, 0x13, satn[6]);
+               atp_writeb_io(dev, c, 0x14, satn[7]);
+               atp_writeb_io(dev, c, 0x18, satn[8]);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
                        cpu_relax();
-               tmport -= 0x08;
-               if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+               if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
                        continue;
-               }
-               while (inb(tmport) != 0x8e)
+
+               while (atp_readb_io(dev, c, 0x17) != 0x8e)
                        cpu_relax();
+
 try_sync:
                j = 0;
-               tmport = wkport + 0x14;
-               outb(0x06, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
-
-               while ((inb(tmport) & 0x80) == 0) {
-                       if ((inb(tmport) & 0x01) != 0) {
-                               tmport -= 0x06;
+               atp_writeb_io(dev, c, 0x14, 0x06);
+               atp_writeb_io(dev, c, 0x18, 0x20);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+                       if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0) {
                                if ((m & dev->wide_id[c]) != 0) {
-                                       if ((m & dev->ultra_map[c]) != 0) {
-                                               outb(synuw[j++], tmport);
-                                       } else {
-                                               outb(synw[j++], tmport);
-                                       }
+                                       if (is885(dev) || is880(dev)) {
+                                               if ((m & dev->ultra_map[c]) != 0) {
+                                                       atp_writeb_io(dev, c, 0x19, synuw[j++]);
+                                               } else {
+                                                       atp_writeb_io(dev, c, 0x19, synw[j++]);
+                                               }
+                                       } else
+                                               atp_writeb_io(dev, c, 0x19, synw_870[j++]);
                                } else {
                                        if ((m & dev->ultra_map[c]) != 0) {
-                                               outb(synu[j++], tmport);
+                                               atp_writeb_io(dev, c, 0x19, synu[j++]);
                                        } else {
-                                               outb(synn[j++], tmport);
+                                               atp_writeb_io(dev, c, 0x19, synn[j++]);
                                        }
                                }
-                               tmport += 0x06;
                        }
                }
-               tmport -= 0x08;
-               while ((inb(tmport) & 0x80) == 0x00)
+
+               while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
                        cpu_relax();
-               j = inb(tmport) & 0x0f;
+
+               j = atp_readb_io(dev, c, 0x17) & 0x0f;
                if (j == 0x0f) {
                        goto phase_ins;
                }
@@ -3766,19 +2196,13 @@ try_sync:
                }
                continue;
 phase_outs:
-               tmport = wkport + 0x18;
-               outb(0x20, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00) {
-                       if ((inb(tmport) & 0x01) != 0x00) {
-                               tmport -= 0x06;
-                               outb(0x00, tmport);
-                               tmport += 0x06;
-                       }
+               atp_writeb_io(dev, c, 0x18, 0x20);
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00) {
+                       if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0x00)
+                               atp_writeb_io(dev, c, 0x19, 0x00);
                        cpu_relax();
                }
-               tmport -= 0x08;
-               j = inb(tmport);
+               j = atp_readb_io(dev, c, 0x17);
                if (j == 0x85) {
                        goto tar_dcons;
                }
@@ -3794,26 +2218,25 @@ phase_outs:
                }
                continue;
 phase_ins:
-               tmport = wkport + 0x14;
-               outb(0x06, tmport);
-               tmport += 0x04;
-               outb(0x20, tmport);
-               tmport += 0x07;
+               if (is885(dev) || is880(dev))
+                       atp_writeb_io(dev, c, 0x14, 0x06);
+               else
+                       atp_writeb_io(dev, c, 0x14, 0xff);
+               atp_writeb_io(dev, c, 0x18, 0x20);
                k = 0;
 phase_ins1:
-               j = inb(tmport);
+               j = atp_readb_io(dev, c, 0x1f);
                if ((j & 0x01) != 0x00) {
-                       tmport -= 0x06;
-                       mbuf[k++] = inb(tmport);
-                       tmport += 0x06;
+                       mbuf[k++] = atp_readb_io(dev, c, 0x19);
                        goto phase_ins1;
                }
                if ((j & 0x80) == 0x00) {
                        goto phase_ins1;
                }
-               tmport -= 0x08;
-               while ((inb(tmport) & 0x80) == 0x00);
-               j = inb(tmport);
+
+               while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00);
+
+               j = atp_readb_io(dev, c, 0x17);
                if (j == 0x85) {
                        goto tar_dcons;
                }
@@ -3829,18 +2252,15 @@ phase_ins1:
                }
                continue;
 phase_cmds:
-               tmport = wkport + 0x10;
-               outb(0x30, tmport);
+               atp_writeb_io(dev, c, 0x10, 0x30);
 tar_dcons:
-               tmport = wkport + 0x14;
-               outb(0x00, tmport);
-               tmport += 0x04;
-               outb(0x08, tmport);
-               tmport += 0x07;
-               while ((inb(tmport) & 0x80) == 0x00)
+               atp_writeb_io(dev, c, 0x14, 0x00);
+               atp_writeb_io(dev, c, 0x18, 0x08);
+
+               while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
                        cpu_relax();
-               tmport -= 0x08;
-               j = inb(tmport);
+
+               j = atp_readb_io(dev, c, 0x17);
                if (j != 0x16) {
                        continue;
                }
@@ -3856,14 +2276,21 @@ tar_dcons:
                if (mbuf[3] > 0x64) {
                        continue;
                }
-               if (mbuf[4] > 0x0e) {
-                       mbuf[4] = 0x0e;
+               if (is885(dev) || is880(dev)) {
+                       if (mbuf[4] > 0x0e) {
+                               mbuf[4] = 0x0e;
+                       }
+               } else {
+                       if (mbuf[4] > 0x0c) {
+                               mbuf[4] = 0x0c;
+                       }
                }
                dev->id[c][i].devsp = mbuf[4];
-               if (mbuf[3] < 0x0c){
-                       j = 0xb0;
-                       goto set_syn_ok;
-               }
+               if (is885(dev) || is880(dev))
+                       if (mbuf[3] < 0x0c) {
+                               j = 0xb0;
+                               goto set_syn_ok;
+                       }
                if ((mbuf[3] < 0x0d) && (rmb == 0)) {
                        j = 0xa0;
                        goto set_syn_ok;
@@ -3881,16 +2308,10 @@ tar_dcons:
                        goto set_syn_ok;
                }
                j = 0x60;
-             set_syn_ok:
+set_syn_ok:
                dev->id[c][i].devsp = (dev->id[c][i].devsp & 0x0f) | j;
-#ifdef ED_DBGP         
+#ifdef ED_DBGP
                printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
 #endif
        }
-       tmport = wkport + 0x16;
-       outb(0x80, tmport);
 }
-
-module_init(atp870u_init);
-module_exit(atp870u_exit);
-
index 5cf62566ad4282422f4288605d8f6ac7a2469859..9b839b1e895a1dd285fc7be1dbda7dcda53b275b 100644 (file)
@@ -26,22 +26,18 @@ struct atp_unit
        unsigned long baseport;
        unsigned long ioport[2];
        unsigned long pciport[2];
-       unsigned long irq;
        unsigned char last_cmd[2];
        unsigned char in_snd[2];
        unsigned char in_int[2];
        unsigned char quhd[2];
        unsigned char quend[2];
        unsigned char global_map[2];
-       unsigned char chip_ver;
-       unsigned char scam_on;
        unsigned char host_id[2];
        unsigned int working[2];
        unsigned short wide_id[2];
        unsigned short active_id[2];
        unsigned short ultra_map[2];
        unsigned short async[2];
-       unsigned short dev_id;
        unsigned char sp[2][16];
        unsigned char r1f[2][16];               
        struct scsi_cmnd *quereq[2][qcnt];
index 4ad7e368bbc2505a0c0b86a637d6a718dd0a4dac..0e119d838e1b6cc569f2b6905d11d2acdbf6ce15 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index e3f67b097a5ca78df71b382e2fedf8a380c92e16..2ea0db4b62a737f373f921ce5faf2225f906619d 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 91a8aa394db516b94aa501974718d0f9c18c5283..da9cf655be2600d897f06eb49d47cb8c72c929a2 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 877b86dd2837da70f2292e90abee16bef7bb875f..5dc3782d615b6e38134c1255d948b14d869e4885 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 06f0a163ca35bd87a854dd0ea0861a4bb35c9e29..5815a904574d969d80d0836d601852a4bbd615f8 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 638f441ffc388fc738551974b891dc033312ed7d..e81707f938cb0d3b9371eef04a9288b5714d1354 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 64069a0a3d0d10de0a17f89c5a8e23b74a65f302..18b7304d6b0bc0cdfa4cdbcfafc748432e12ea7f 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index dce787f6cca2e421169e8f80b4f9a228b0f1bf4f..b8dadc9cc9935cb5c8b07c4c66627728b704b873 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 03c753d1e548949573a785463f203c685e1936b4..b109a8813401a6cb4ec0346d0c3f0aae25519b6e 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index d7385d1d9c5aeac6d9a62c6069bc45bb969cc719..20982e7cdd818fa064e614385dfd93b8713d3f16 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index e693af6e59300aef03127dcd6c2d62e000e1c1c9..e93921dec3478a3b5d68e30943b34cc55f41d3cc 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 0f19455951ec37a4d165e9b0bcc03b5c77f9db50..1e7e139d71eabd1bbdc9e1daa4b589f640e231e6 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 42bcb970445a8a7212fafa1aa7285639d5c7d8a3..06dc215ea0503b89126cb0bee19fdd55c698e502 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
@@ -633,7 +634,7 @@ void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
 
 /*
  * HBA Attribute Block : BFA internal representation. Note : Some variable
- * sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based
+ * sizes have been trimmed to suit BFA For Ex : Model will be "QLogic ". Based
  * on this the size has been reduced to 16 bytes from the standard's 64 bytes.
  */
 struct bfa_fcs_fdmi_hba_attr_s {
index 6dc7926a3edd4d9927199530b57af61554a492d3..4f089d76afb1a8c6820cd85d6ab0b7f2af1393b1 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index ff75ef8917551b35a61ff1e2eea41239b76b8332..7733ad5305d4100bd87b472dceb8e98bbc53373d 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
@@ -2653,7 +2654,7 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
 
        strncpy(hba_attr->node_sym_name.symname,
                port->port_cfg.node_sym_name.symname, BFA_SYMNAME_MAXLEN);
-       strcpy(hba_attr->vendor_info, "BROCADE");
+       strcpy(hba_attr->vendor_info, "QLogic");
        hba_attr->num_ports =
                cpu_to_be32(bfa_ioc_get_nports(&port->fcs->bfa->ioc));
        hba_attr->fabric_name = port->fabric->lps->pr_nwwn;
index 2035b0d6435186186af4a497109a9a57b3843931..de50349a39ce2dbbf0b8a841db07b76c9fc70ed5 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index ea24d4c6e67afc025ce68e5363f8eda1771f335e..c4a0c0eb88a576ac7105ad5789403f62d7d03a59 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 637527f48b400c741805dbdf9a2e5758cad64a7e..b0ff378dece2c74d3b975860238eaab1ef5e73c2 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 98f7e8cca52df25e017887b3d491b2272d7a798e..251e2ff8ff5f797848b9603fdfff2d4fdc5eea71 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
@@ -2697,7 +2698,7 @@ bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc)
        bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_UNINIT);
 }
 
-#define BFA_MFG_NAME "Brocade"
+#define BFA_MFG_NAME "QLogic"
 void
 bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
                         struct bfa_adapter_attr_s *ad_attr)
index a38aafa030b35256ede14da888f421d27dc4166d..713745da44c6ac457ad61b3174ffe4056bdcba83 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 453c2f5b55611c96c72c3dd54f519e224d34fed6..f1b80da298c8d2951eafddedb7c5bc2e2313d487 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index bd53150e4ee00048491df42f40e4f6a9209984f1..651a8fb930377b18ff894455ef338a8d3531edc6 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index a14c784ff3fc2d06338c5aa011f1e035afcd7f05..53135f21fa0e4e2a93665f2068596e6a2fba8c28 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 1c9baa68339b4bee83f53d64e439c0dddd1b2812..da570c0b8275e01b527ac86e248b3cc8e20a6853 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 8ea7697deb9bdd87f6be661d6cf5a70ff44c171a..da1721e0d1673cef13d95b5675789a1fec02f21a 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 2fcab6bc62807cdd2ea6fcc1f48131e2fa9944b0..26dc1bf14c85e14a8ffc69fc8d823f8b2d3449f4 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 625225f31081ada0f732621c38f078f174ab0fdf..12de292175ef64000ad38d7d8b0c1b1a536c8686 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index ef07365991e75186a41e4974eff7008a27c57ae5..ea2278bc78a8d44f497a5985357dcd9ce28c9625 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index cc3b9d3d6d4095ac5c44c4f938219f36bab5844f..9d253cb83ee762692c1ec0f56303f3c7fc8b416e 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
@@ -130,13 +131,9 @@ MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for "
                        "boot port. Otherwise 10 secs in RHEL4 & 0 for "
                        "[RHEL5, SLES10, ESX40] Range[>0]");
 module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts "
-                       "for Brocade-415/425/815/825 cards, default=0, "
-                       " Range[false:0|true:1]");
+MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts for QLogic-415/425/815/825 cards, default=0 Range[false:0|true:1]");
 module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts "
-                       "if possible for Brocade-1010/1020/804/1007/902/1741 "
-                       "cards, default=0, Range[false:0|true:1]");
+MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts if possible for QLogic-1010/1020/804/1007/902/1741 cards, default=0, Range[false:0|true:1]");
 module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1, "
                                "Range[false:0|true:1]");
@@ -838,8 +835,7 @@ bfad_drv_init(struct bfad_s *bfad)
                printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n",
                       bfad->inst_no);
                printk(KERN_WARNING
-                       "Not enough memory to attach all Brocade HBA ports, %s",
-                       "System may need more memory.\n");
+                       "Not enough memory to attach all QLogic BR-series HBA ports. System may need more memory.\n");
                return BFA_STATUS_FAILED;
        }
 
@@ -1710,7 +1706,7 @@ bfad_init(void)
 {
        int             error = 0;
 
-       printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n",
+       pr_info("QLogic BR-series BFA FC/FCOE SCSI driver - version: %s\n",
                        BFAD_DRIVER_VERSION);
 
        if (num_sgpgs > 0)
@@ -1817,6 +1813,6 @@ bfad_free_fwimg(void)
 module_init(bfad_init);
 module_exit(bfad_exit);
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Brocade Fibre Channel HBA Driver" BFAD_PROTO_NAME);
-MODULE_AUTHOR("Brocade Communications Systems, Inc.");
+MODULE_DESCRIPTION("QLogic BR-series Fibre Channel HBA Driver" BFAD_PROTO_NAME);
+MODULE_AUTHOR("QLogic Corporation");
 MODULE_VERSION(BFAD_DRIVER_VERSION);
index 40be670a1cbc865c4b39694d10e86584f0dc6321..13db3b7bc8737fc949b68129385c5291f3f7c018 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
@@ -750,65 +751,65 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr,
 
        bfa_get_adapter_model(&bfad->bfa, model);
        nports = bfa_get_nports(&bfad->bfa);
-       if (!strcmp(model, "Brocade-425"))
+       if (!strcmp(model, "QLogic-425"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 4Gbps PCIe dual port FC HBA");
-       else if (!strcmp(model, "Brocade-825"))
+                       "QLogic BR-series 4Gbps PCIe dual port FC HBA");
+       else if (!strcmp(model, "QLogic-825"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 8Gbps PCIe dual port FC HBA");
-       else if (!strcmp(model, "Brocade-42B"))
+                       "QLogic BR-series 8Gbps PCIe dual port FC HBA");
+       else if (!strcmp(model, "QLogic-42B"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 4Gbps PCIe dual port FC HBA for HP");
-       else if (!strcmp(model, "Brocade-82B"))
+                       "QLogic BR-series 4Gbps PCIe dual port FC HBA for HP");
+       else if (!strcmp(model, "QLogic-82B"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 8Gbps PCIe dual port FC HBA for HP");
-       else if (!strcmp(model, "Brocade-1010"))
+                       "QLogic BR-series 8Gbps PCIe dual port FC HBA for HP");
+       else if (!strcmp(model, "QLogic-1010"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 10Gbps single port CNA");
-       else if (!strcmp(model, "Brocade-1020"))
+                       "QLogic BR-series 10Gbps single port CNA");
+       else if (!strcmp(model, "QLogic-1020"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 10Gbps dual port CNA");
-       else if (!strcmp(model, "Brocade-1007"))
+                       "QLogic BR-series 10Gbps dual port CNA");
+       else if (!strcmp(model, "QLogic-1007"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 10Gbps CNA for IBM Blade Center");
-       else if (!strcmp(model, "Brocade-415"))
+                       "QLogic BR-series 10Gbps CNA for IBM Blade Center");
+       else if (!strcmp(model, "QLogic-415"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 4Gbps PCIe single port FC HBA");
-       else if (!strcmp(model, "Brocade-815"))
+                       "QLogic BR-series 4Gbps PCIe single port FC HBA");
+       else if (!strcmp(model, "QLogic-815"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 8Gbps PCIe single port FC HBA");
-       else if (!strcmp(model, "Brocade-41B"))
+                       "QLogic BR-series 8Gbps PCIe single port FC HBA");
+       else if (!strcmp(model, "QLogic-41B"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 4Gbps PCIe single port FC HBA for HP");
-       else if (!strcmp(model, "Brocade-81B"))
+                       "QLogic BR-series 4Gbps PCIe single port FC HBA for HP");
+       else if (!strcmp(model, "QLogic-81B"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 8Gbps PCIe single port FC HBA for HP");
-       else if (!strcmp(model, "Brocade-804"))
+                       "QLogic BR-series 8Gbps PCIe single port FC HBA for HP");
+       else if (!strcmp(model, "QLogic-804"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 8Gbps FC HBA for HP Bladesystem C-class");
-       else if (!strcmp(model, "Brocade-1741"))
+                       "QLogic BR-series 8Gbps FC HBA for HP Bladesystem C-class");
+       else if (!strcmp(model, "QLogic-1741"))
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                       "Brocade 10Gbps CNA for Dell M-Series Blade Servers");
-       else if (strstr(model, "Brocade-1860")) {
+                       "QLogic BR-series 10Gbps CNA for Dell M-Series Blade Servers");
+       else if (strstr(model, "QLogic-1860")) {
                if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc))
                        snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                               "Brocade 10Gbps single port CNA");
+                               "QLogic BR-series 10Gbps single port CNA");
                else if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
                        snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                               "Brocade 16Gbps PCIe single port FC HBA");
+                               "QLogic BR-series 16Gbps PCIe single port FC HBA");
                else if (nports == 2 && bfa_ioc_is_cna(&bfad->bfa.ioc))
                        snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                               "Brocade 10Gbps dual port CNA");
+                               "QLogic BR-series 10Gbps dual port CNA");
                else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
                        snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                               "Brocade 16Gbps PCIe dual port FC HBA");
-       } else if (!strcmp(model, "Brocade-1867")) {
+                               "QLogic BR-series 16Gbps PCIe dual port FC HBA");
+       } else if (!strcmp(model, "QLogic-1867")) {
                if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
                        snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                               "Brocade 16Gbps PCIe single port FC HBA for IBM");
+                               "QLogic BR-series 16Gbps PCIe single port FC HBA for IBM");
                else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
                        snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
-                               "Brocade 16Gbps PCIe dual port FC HBA for IBM");
+                               "QLogic BR-series 16Gbps PCIe dual port FC HBA for IBM");
        } else
                snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
                        "Invalid Model");
index 023b9d42ad9a229ebca4876de4336e25d611f59d..d1ad0208dfe754e08d648ff8f3e8abd750ac845d 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 90abef6915850e0681b3ff80aadeda1639eee8f5..917e140dfbcced89d3a69b30486ca1f03c334e82 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 74a307c0a2407c45af6ad42796d4944a3bec2bed..8dcd8c70c7ee088535a875c7ec2f04d72c8110ef 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 8b97877d42cf660ae1bb928888fa34794bfeaaf7..f9e862093a25935e601c45b4854035e98e035f03 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
@@ -57,7 +58,7 @@
 #ifdef BFA_DRIVER_VERSION
 #define BFAD_DRIVER_VERSION    BFA_DRIVER_VERSION
 #else
-#define BFAD_DRIVER_VERSION    "3.2.23.0"
+#define BFAD_DRIVER_VERSION    "3.2.25.0"
 #endif
 
 #define BFAD_PROTO_NAME FCPI_NAME
index 299c6f80d4605116c5039cb1a23b77a0b4324d05..6c805e13f8dd8637b6547f8879eb549097ab913c 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
@@ -185,7 +186,7 @@ bfad_im_info(struct Scsi_Host *shost)
 
        memset(bfa_buf, 0, sizeof(bfa_buf));
        snprintf(bfa_buf, sizeof(bfa_buf),
-               "Brocade FC/FCOE Adapter, " "hwpath: %s driver: %s",
+               "QLogic BR-series FC/FCOE Adapter, hwpath: %s driver: %s",
                bfad->pci_name, BFAD_DRIVER_VERSION);
 
        return bfa_buf;
@@ -271,6 +272,19 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
        cmnd->host_scribble = NULL;
        cmnd->SCp.Status = 0;
        bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+       /*
+        * bfa_itnim can be NULL if the port gets disconnected and the bfa
+        * and fcs layers have cleaned up their nexus with the targets and
+        * the same has not been cleaned up by the shim
+        */
+       if (bfa_itnim == NULL) {
+               bfa_tskim_free(tskim);
+               BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+                       "target reset, bfa_itnim is NULL\n");
+               rc = BFA_STATUS_FAILED;
+               goto out;
+       }
+
        memset(&scsilun, 0, sizeof(scsilun));
        bfa_tskim_start(tskim, bfa_itnim, scsilun,
                            FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO);
@@ -326,6 +340,19 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
        cmnd->SCp.ptr = (char *)&wq;
        cmnd->SCp.Status = 0;
        bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+       /*
+        * bfa_itnim can be NULL if the port gets disconnected and the bfa
+        * and fcs layers have cleaned up their nexus with the targets and
+        * the same has not been cleaned up by the shim
+        */
+       if (bfa_itnim == NULL) {
+               bfa_tskim_free(tskim);
+               BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+                       "lun reset, bfa_itnim is NULL\n");
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               rc = FAILED;
+               goto out;
+       }
        int_to_scsilun(cmnd->device->lun, &scsilun);
        bfa_tskim_start(tskim, bfa_itnim, scsilun,
                            FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO);
index f6c1023e502a13cd04f19551d4893ec5f9014129..836fdc221edd31ccabd9e4ec3227c247f5f12fdf 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 9ef91f907decb70d74c689082830003d08bf0855..97600dcec6491865f23fcc8df3e0365a6d692e92 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 1a3fe5ad58fa71f8e97504bdaa0d7fec0c93d211..ae5bfe039fcc0012ed65ca4d81c3e20be9e65070 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
index 99133bcf53f99f0ec6b9812fff8b173e5398fcbe..fd5b87616e8b1c46ec246a813338789c0cd81b3e 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
  * All rights reserved
- * www.brocade.com
+ * www.qlogic.com
  *
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License (GPL) Version 2 as
@@ -16,7 +17,7 @@
  */
 
 /*
- * bfi_reg.h ASIC register defines for all Brocade adapter ASICs
+ * bfi_reg.h ASIC register defines for all QLogic BR-series adapter ASICs
  */
 
 #ifndef __BFI_REG_H__
index c11cd193f8964ff1741453e309a85a0f6d5d4402..5ada9268a450db224663f2fa28e43fc79701c886 100644 (file)
@@ -165,6 +165,8 @@ struct afu {
        struct sisl_host_map __iomem *host_map;         /* MC host map */
        struct sisl_ctrl_map __iomem *ctrl_map;         /* MC control map */
 
+       struct kref mapcount;
+
        ctx_hndl_t ctx_hndl;    /* master's context handle */
        u64 *hrrq_start;
        u64 *hrrq_end;
index 1e5bf0ca81da1043a3be9d752271baf9c0a85836..f6d90ce8f3b7eaa64b09e03aa515333323d1870e 100644 (file)
@@ -368,6 +368,7 @@ out:
 
 no_room:
        afu->read_room = true;
+       kref_get(&cfg->afu->mapcount);
        schedule_work(&cfg->work_q);
        rc = SCSI_MLQUEUE_HOST_BUSY;
        goto out;
@@ -473,6 +474,16 @@ out:
        return rc;
 }
 
+static void afu_unmap(struct kref *ref)
+{
+       struct afu *afu = container_of(ref, struct afu, mapcount);
+
+       if (likely(afu->afu_map)) {
+               cxl_psa_unmap((void __iomem *)afu->afu_map);
+               afu->afu_map = NULL;
+       }
+}
+
 /**
  * cxlflash_driver_info() - information handler for this host driver
  * @host:      SCSI host associated with device.
@@ -503,6 +514,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
        ulong lock_flags;
        short lflag = 0;
        int rc = 0;
+       int kref_got = 0;
 
        dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
                            "cdb=(%08X-%08X-%08X-%08X)\n",
@@ -547,6 +559,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
                goto out;
        }
 
+       kref_get(&cfg->afu->mapcount);
+       kref_got = 1;
+
        cmd->rcb.ctx_id = afu->ctx_hndl;
        cmd->rcb.port_sel = port_sel;
        cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
@@ -587,6 +602,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
        }
 
 out:
+       if (kref_got)
+               kref_put(&afu->mapcount, afu_unmap);
        pr_devel("%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
@@ -632,20 +649,36 @@ static void free_mem(struct cxlflash_cfg *cfg)
  * @cfg:       Internal structure associated with the host.
  *
  * Safe to call with AFU in a partially allocated/initialized state.
+ *
+ * Cleans up all state associated with the command queue, and unmaps
+ * the MMIO space.
+ *
+ *  - complete() will take care of commands we initiated (they'll be checked
+ *  in as part of the cleanup that occurs after the completion)
+ *
+ *  - cmd_checkin() will take care of entries that we did not initiate and that
+ *  have not (and will not) complete because they are sitting on a [now stale]
+ *  hardware queue
  */
 static void stop_afu(struct cxlflash_cfg *cfg)
 {
        int i;
        struct afu *afu = cfg->afu;
+       struct afu_cmd *cmd;
 
        if (likely(afu)) {
-               for (i = 0; i < CXLFLASH_NUM_CMDS; i++)
-                       complete(&afu->cmd[i].cevent);
+               for (i = 0; i < CXLFLASH_NUM_CMDS; i++) {
+                       cmd = &afu->cmd[i];
+                       complete(&cmd->cevent);
+                       if (!atomic_read(&cmd->free))
+                               cmd_checkin(cmd);
+               }
 
                if (likely(afu->afu_map)) {
                        cxl_psa_unmap((void __iomem *)afu->afu_map);
                        afu->afu_map = NULL;
                }
+               kref_put(&afu->mapcount, afu_unmap);
        }
 }
 
@@ -731,8 +764,8 @@ static void cxlflash_remove(struct pci_dev *pdev)
                scsi_remove_host(cfg->host);
                /* fall through */
        case INIT_STATE_AFU:
-               term_afu(cfg);
                cancel_work_sync(&cfg->work_q);
+               term_afu(cfg);
        case INIT_STATE_PCI:
                pci_release_regions(cfg->dev);
                pci_disable_device(pdev);
@@ -1108,7 +1141,7 @@ static const struct asyc_intr_info ainfo[] = {
        {SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET},
        {SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0},
        {SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET},
-       {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0},
+       {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, LINK_RESET},
        {SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR},
        {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST},
        {SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0},
@@ -1316,6 +1349,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
                                __func__, port);
                        cfg->lr_state = LINK_RESET_REQUIRED;
                        cfg->lr_port = port;
+                       kref_get(&cfg->afu->mapcount);
                        schedule_work(&cfg->work_q);
                }
 
@@ -1336,6 +1370,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
 
                if (info->action & SCAN_HOST) {
                        atomic_inc(&cfg->scan_host_needed);
+                       kref_get(&cfg->afu->mapcount);
                        schedule_work(&cfg->work_q);
                }
        }
@@ -1731,6 +1766,7 @@ static int init_afu(struct cxlflash_cfg *cfg)
                rc = -ENOMEM;
                goto err1;
        }
+       kref_init(&afu->mapcount);
 
        /* No byte reverse on reading afu_version or string will be backwards */
        reg = readq(&afu->afu_map->global.regs.afu_version);
@@ -1765,8 +1801,7 @@ out:
        return rc;
 
 err2:
-       cxl_psa_unmap((void __iomem *)afu->afu_map);
-       afu->afu_map = NULL;
+       kref_put(&afu->mapcount, afu_unmap);
 err1:
        term_mc(cfg, UNDO_START);
        goto out;
@@ -2274,6 +2309,7 @@ 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 };
 
 /*
  * PCI device binding table
@@ -2281,6 +2317,8 @@ static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
 static struct pci_device_id cxlflash_pci_table[] = {
        {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
+       {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals},
        {}
 };
 
@@ -2339,6 +2377,7 @@ static void cxlflash_worker_thread(struct work_struct *work)
 
        if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
                scsi_scan_host(cfg->host);
+       kref_put(&afu->mapcount, afu_unmap);
 }
 
 /**
@@ -2585,8 +2624,7 @@ static struct pci_driver cxlflash_driver = {
  */
 static int __init init_cxlflash(void)
 {
-       pr_info("%s: IBM Power CXL Flash Adapter: %s\n",
-               __func__, CXLFLASH_DRIVER_DATE);
+       pr_info("%s: %s\n", __func__, CXLFLASH_ADAPTER_NAME);
 
        cxlflash_list_init();
 
index 60324566c14f4f85a5178581d39648e5c5115e00..0faed422c7f47eec6ac8f474cb85f7e61dd6ed1d 100644 (file)
 
 #define CXLFLASH_NAME          "cxlflash"
 #define CXLFLASH_ADAPTER_NAME  "IBM POWER CXL Flash Adapter"
-#define CXLFLASH_DRIVER_DATE   "(August 13, 2015)"
 
-#define PCI_DEVICE_ID_IBM_CORSA        0x04F0
-#define CXLFLASH_SUBS_DEV_ID   0x04F0
+#define PCI_DEVICE_ID_IBM_CORSA                0x04F0
+#define PCI_DEVICE_ID_IBM_FLASH_GT     0x0600
 
 /* Since there is only one target, make it 0 */
 #define CXLFLASH_TARGET                0
index cac2e6a50efd83ab001bdb84cf56fb2d8d1d35b2..f4020dbb55c32440d78b3de073347b8f87d14ab6 100644 (file)
@@ -1372,7 +1372,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
        }
 
        ctx = cxl_dev_context_init(cfg->dev);
-       if (unlikely(IS_ERR_OR_NULL(ctx))) {
+       if (IS_ERR_OR_NULL(ctx)) {
                dev_err(dev, "%s: Could not initialize context %p\n",
                        __func__, ctx);
                rc = -ENODEV;
@@ -1380,7 +1380,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
        }
 
        ctxid = cxl_process_element(ctx);
-       if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+       if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
                dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
                rc = -EPERM;
                goto err2;
@@ -1500,7 +1500,7 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
        struct afu *afu = cfg->afu;
 
        ctx = cxl_dev_context_init(cfg->dev);
-       if (unlikely(IS_ERR_OR_NULL(ctx))) {
+       if (IS_ERR_OR_NULL(ctx)) {
                dev_err(dev, "%s: Could not initialize context %p\n",
                        __func__, ctx);
                rc = -ENODEV;
@@ -1508,7 +1508,7 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
        }
 
        ctxid = cxl_process_element(ctx);
-       if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+       if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
                dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
                rc = -EPERM;
                goto err1;
index a53f583e2d7b1ea5b58e817e66715a35567698da..50f8e93007704667fb0c1311834c0a5f0d50ff52 100644 (file)
@@ -1008,6 +1008,8 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
        virt->last_lba = last_lba;
        virt->rsrc_handle = rsrc_handle;
 
+       if (lli->port_sel == BOTH_PORTS)
+               virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE;
 out:
        if (likely(ctxi))
                put_context(ctxi);
index cc2773b5de68f5c8751ddb25d940cc0c2eef9017..5a328bf8183678ecc27fa63f6c2d808e5fb7163f 100644 (file)
@@ -22,7 +22,9 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <asm/unaligned.h>
 #include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_dh.h>
 
@@ -58,8 +60,9 @@
 #define ALUA_FAILOVER_TIMEOUT          60
 #define ALUA_FAILOVER_RETRIES          5
 
-/* flags passed from user level */
+/* device handler flags */
 #define ALUA_OPTIMIZE_STPG             1
+#define ALUA_RTPG_EXT_HDR_UNSUPP       2
 
 struct alua_dh_data {
        int                     group_id;
@@ -73,7 +76,6 @@ struct alua_dh_data {
        int                     bufflen;
        unsigned char           transition_tmo;
        unsigned char           sense[SCSI_SENSE_BUFFERSIZE];
-       int                     senselen;
        struct scsi_device      *sdev;
        activate_complete       callback_fn;
        void                    *callback_data;
@@ -83,7 +85,6 @@ struct alua_dh_data {
 #define ALUA_POLICY_SWITCH_ALL         1
 
 static char print_alua_state(int);
-static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
 
 static int realloc_buffer(struct alua_dh_data *h, unsigned len)
 {
@@ -130,94 +131,48 @@ static struct request *get_alua_req(struct scsi_device *sdev,
        return rq;
 }
 
-/*
- * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
- * @sdev: sdev the command should be sent to
- */
-static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
-{
-       struct request *rq;
-       int err = SCSI_DH_RES_TEMP_UNAVAIL;
-
-       rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
-       if (!rq)
-               goto done;
-
-       /* Prepare the command. */
-       rq->cmd[0] = INQUIRY;
-       rq->cmd[1] = 1;
-       rq->cmd[2] = 0x83;
-       rq->cmd[4] = h->bufflen;
-       rq->cmd_len = COMMAND_SIZE(INQUIRY);
-
-       rq->sense = h->sense;
-       memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-       rq->sense_len = h->senselen = 0;
-
-       err = blk_execute_rq(rq->q, NULL, rq, 1);
-       if (err == -EIO) {
-               sdev_printk(KERN_INFO, sdev,
-                           "%s: evpd inquiry failed with %x\n",
-                           ALUA_DH_NAME, rq->errors);
-               h->senselen = rq->sense_len;
-               err = SCSI_DH_IO;
-       }
-       blk_put_request(rq);
-done:
-       return err;
-}
-
 /*
  * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
  * @sdev: sdev the command should be sent to
  */
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
-                           bool rtpg_ext_hdr_req)
+static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
 {
        struct request *rq;
-       int err = SCSI_DH_RES_TEMP_UNAVAIL;
+       int err = 0;
 
        rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
-       if (!rq)
+       if (!rq) {
+               err = DRIVER_BUSY << 24;
                goto done;
+       }
 
        /* Prepare the command. */
        rq->cmd[0] = MAINTENANCE_IN;
-       if (rtpg_ext_hdr_req)
+       if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP))
                rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
        else
                rq->cmd[1] = MI_REPORT_TARGET_PGS;
-       rq->cmd[6] = (h->bufflen >> 24) & 0xff;
-       rq->cmd[7] = (h->bufflen >> 16) & 0xff;
-       rq->cmd[8] = (h->bufflen >>  8) & 0xff;
-       rq->cmd[9] = h->bufflen & 0xff;
+       put_unaligned_be32(h->bufflen, &rq->cmd[6]);
        rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
 
        rq->sense = h->sense;
        memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-       rq->sense_len = h->senselen = 0;
+       rq->sense_len = 0;
 
-       err = blk_execute_rq(rq->q, NULL, rq, 1);
-       if (err == -EIO) {
-               sdev_printk(KERN_INFO, sdev,
-                           "%s: rtpg failed with %x\n",
-                           ALUA_DH_NAME, rq->errors);
-               h->senselen = rq->sense_len;
-               err = SCSI_DH_IO;
-       }
+       blk_execute_rq(rq->q, NULL, rq, 1);
+       if (rq->errors)
+               err = rq->errors;
        blk_put_request(rq);
 done:
        return err;
 }
 
 /*
- * alua_stpg - Evaluate SET TARGET GROUP STATES
+ * stpg_endio - Evaluate SET TARGET GROUP STATES
  * @sdev: the device to be evaluated
  * @state: the new target group state
  *
- * Send a SET TARGET GROUP STATES command to the device.
- * We only have to test here if we should resubmit the command;
- * any other error is assumed as a failure.
+ * Evaluate a SET TARGET GROUP STATES command response.
  */
 static void stpg_endio(struct request *req, int error)
 {
@@ -231,22 +186,21 @@ static void stpg_endio(struct request *req, int error)
                goto done;
        }
 
-       if (req->sense_len > 0) {
-               err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
-                                          &sense_hdr);
-               if (!err) {
-                       err = SCSI_DH_IO;
+       if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+                                &sense_hdr)) {
+               if (sense_hdr.sense_key == NOT_READY &&
+                   sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) {
+                       /* ALUA state transition already in progress */
+                       err = SCSI_DH_OK;
                        goto done;
                }
-               err = alua_check_sense(h->sdev, &sense_hdr);
-               if (err == ADD_TO_MLQUEUE) {
+               if (sense_hdr.sense_key == UNIT_ATTENTION) {
                        err = SCSI_DH_RETRY;
                        goto done;
                }
-               sdev_printk(KERN_INFO, h->sdev,
-                           "%s: stpg sense code: %02x/%02x/%02x\n",
-                           ALUA_DH_NAME, sense_hdr.sense_key,
-                           sense_hdr.asc, sense_hdr.ascq);
+               sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
+                           ALUA_DH_NAME);
+               scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr);
                err = SCSI_DH_IO;
        } else if (error)
                err = SCSI_DH_IO;
@@ -284,8 +238,7 @@ static unsigned submit_stpg(struct alua_dh_data *h)
        /* Prepare the data buffer */
        memset(h->buff, 0, stpg_len);
        h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
-       h->buff[6] = (h->group_id >> 8) & 0xff;
-       h->buff[7] = h->group_id & 0xff;
+       put_unaligned_be16(h->group_id, &h->buff[6]);
 
        rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
        if (!rq)
@@ -294,15 +247,12 @@ static unsigned submit_stpg(struct alua_dh_data *h)
        /* Prepare the command. */
        rq->cmd[0] = MAINTENANCE_OUT;
        rq->cmd[1] = MO_SET_TARGET_PGS;
-       rq->cmd[6] = (stpg_len >> 24) & 0xff;
-       rq->cmd[7] = (stpg_len >> 16) & 0xff;
-       rq->cmd[8] = (stpg_len >>  8) & 0xff;
-       rq->cmd[9] = stpg_len & 0xff;
+       put_unaligned_be32(stpg_len, &rq->cmd[6]);
        rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
 
        rq->sense = h->sense;
        memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-       rq->sense_len = h->senselen = 0;
+       rq->sense_len = 0;
        rq->end_io_data = h;
 
        blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
@@ -316,12 +266,23 @@ static unsigned submit_stpg(struct alua_dh_data *h)
  * Examine the TPGS setting of the sdev to find out if ALUA
  * is supported.
  */
-static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_tpgs(struct scsi_device *sdev)
 {
-       int err = SCSI_DH_OK;
+       int tpgs = TPGS_MODE_NONE;
+
+       /*
+        * ALUA support for non-disk devices is fraught with
+        * difficulties, so disable it for now.
+        */
+       if (sdev->type != TYPE_DISK) {
+               sdev_printk(KERN_INFO, sdev,
+                           "%s: disable for non-disk devices\n",
+                           ALUA_DH_NAME);
+               return tpgs;
+       }
 
-       h->tpgs = scsi_device_tpgs(sdev);
-       switch (h->tpgs) {
+       tpgs = scsi_device_tpgs(sdev);
+       switch (tpgs) {
        case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
                sdev_printk(KERN_INFO, sdev,
                            "%s: supports implicit and explicit TPGS\n",
@@ -335,71 +296,34 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
                sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
                            ALUA_DH_NAME);
                break;
-       default:
-               h->tpgs = TPGS_MODE_NONE;
+       case TPGS_MODE_NONE:
                sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
                            ALUA_DH_NAME);
-               err = SCSI_DH_DEV_UNSUPP;
+               break;
+       default:
+               sdev_printk(KERN_INFO, sdev,
+                           "%s: unsupported TPGS setting %d\n",
+                           ALUA_DH_NAME, tpgs);
+               tpgs = TPGS_MODE_NONE;
                break;
        }
 
-       return err;
+       return tpgs;
 }
 
 /*
- * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83
+ * alua_check_vpd - Evaluate INQUIRY vpd page 0x83
  * @sdev: device to be checked
  *
  * Extract the relative target port and the target port group
  * descriptor from the list of identificators.
  */
-static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
 {
-       int len;
-       unsigned err;
-       unsigned char *d;
-
- retry:
-       err = submit_vpd_inquiry(sdev, h);
-
-       if (err != SCSI_DH_OK)
-               return err;
-
-       /* Check if vpd page exceeds initial buffer */
-       len = (h->buff[2] << 8) + h->buff[3] + 4;
-       if (len > h->bufflen) {
-               /* Resubmit with the correct length */
-               if (realloc_buffer(h, len)) {
-                       sdev_printk(KERN_WARNING, sdev,
-                                   "%s: kmalloc buffer failed\n",
-                                   ALUA_DH_NAME);
-                       /* Temporary failure, bypass */
-                       return SCSI_DH_DEV_TEMP_BUSY;
-               }
-               goto retry;
-       }
+       int rel_port = -1, group_id;
 
-       /*
-        * Now look for the correct descriptor.
-        */
-       d = h->buff + 4;
-       while (d < h->buff + len) {
-               switch (d[1] & 0xf) {
-               case 0x4:
-                       /* Relative target port */
-                       h->rel_port = (d[6] << 8) + d[7];
-                       break;
-               case 0x5:
-                       /* Target port group */
-                       h->group_id = (d[6] << 8) + d[7];
-                       break;
-               default:
-                       break;
-               }
-               d += d[3] + 4;
-       }
-
-       if (h->group_id == -1) {
+       group_id = scsi_vpd_tpg_id(sdev, &rel_port);
+       if (group_id < 0) {
                /*
                 * Internal error; TPGS supported but required
                 * VPD identification descriptors not present.
@@ -408,16 +332,16 @@ static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
                sdev_printk(KERN_INFO, sdev,
                            "%s: No target port descriptors found\n",
                            ALUA_DH_NAME);
-               h->state = TPGS_STATE_OPTIMIZED;
-               h->tpgs = TPGS_MODE_NONE;
-               err = SCSI_DH_DEV_UNSUPP;
-       } else {
-               sdev_printk(KERN_INFO, sdev,
-                           "%s: port group %02x rel port %02x\n",
-                           ALUA_DH_NAME, h->group_id, h->rel_port);
+               return SCSI_DH_DEV_UNSUPP;
        }
+       h->state = TPGS_STATE_OPTIMIZED;
+       h->group_id = group_id;
 
-       return err;
+       sdev_printk(KERN_INFO, sdev,
+                   "%s: port group %02x rel port %02x\n",
+                   ALUA_DH_NAME, h->group_id, h->rel_port);
+
+       return 0;
 }
 
 static char print_alua_state(int state)
@@ -452,28 +376,6 @@ static int alua_check_sense(struct scsi_device *sdev,
                         * LUN Not Accessible - ALUA state transition
                         */
                        return ADD_TO_MLQUEUE;
-               if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
-                       /*
-                        * LUN Not Accessible -- Target port in standby state
-                        */
-                       return SUCCESS;
-               if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c)
-                       /*
-                        * LUN Not Accessible -- Target port in unavailable state
-                        */
-                       return SUCCESS;
-               if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12)
-                       /*
-                        * LUN Not Ready -- Offline
-                        */
-                       return SUCCESS;
-               if (sdev->allow_restart &&
-                   sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x02)
-                       /*
-                        * if the device is not started, we need to wake
-                        * the error handler to start the motor
-                        */
-                       return FAILED;
                break;
        case UNIT_ATTENTION:
                if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
@@ -533,8 +435,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
        struct scsi_sense_hdr sense_hdr;
        int len, k, off, valid_states = 0;
        unsigned char *ucp;
-       unsigned err;
-       bool rtpg_ext_hdr_req = 1;
+       unsigned err, retval;
        unsigned long expiry, interval = 0;
        unsigned int tpg_desc_tbl_off;
        unsigned char orig_transition_tmo;
@@ -545,13 +446,17 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
                expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
 
  retry:
-       err = submit_rtpg(sdev, h, rtpg_ext_hdr_req);
-
-       if (err == SCSI_DH_IO && h->senselen > 0) {
-               err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
-                                          &sense_hdr);
-               if (!err)
+       retval = submit_rtpg(sdev, h);
+       if (retval) {
+               if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+                                         &sense_hdr)) {
+                       sdev_printk(KERN_INFO, sdev,
+                                   "%s: rtpg failed, result %d\n",
+                                   ALUA_DH_NAME, retval);
+                       if (driver_byte(retval) == DRIVER_BUSY)
+                               return SCSI_DH_DEV_TEMP_BUSY;
                        return SCSI_DH_IO;
+               }
 
                /*
                 * submit_rtpg() has failed on existing arrays
@@ -561,27 +466,34 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
                 * The retry without rtpg_ext_hdr_req set
                 * handles this.
                 */
-               if (rtpg_ext_hdr_req == 1 &&
+               if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
                    sense_hdr.sense_key == ILLEGAL_REQUEST &&
                    sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
-                       rtpg_ext_hdr_req = 0;
+                       h->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
                        goto retry;
                }
-
-               err = alua_check_sense(sdev, &sense_hdr);
-               if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry))
+               /*
+                * Retry on ALUA state transition or if any
+                * UNIT ATTENTION occurred.
+                */
+               if (sense_hdr.sense_key == NOT_READY &&
+                   sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+                       err = SCSI_DH_RETRY;
+               else if (sense_hdr.sense_key == UNIT_ATTENTION)
+                       err = SCSI_DH_RETRY;
+               if (err == SCSI_DH_RETRY && time_before(jiffies, expiry)) {
+                       sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
+                                   ALUA_DH_NAME);
+                       scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
                        goto retry;
-               sdev_printk(KERN_INFO, sdev,
-                           "%s: rtpg sense code %02x/%02x/%02x\n",
-                           ALUA_DH_NAME, sense_hdr.sense_key,
-                           sense_hdr.asc, sense_hdr.ascq);
-               err = SCSI_DH_IO;
+               }
+               sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
+                           ALUA_DH_NAME);
+               scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+               return SCSI_DH_IO;
        }
-       if (err != SCSI_DH_OK)
-               return err;
 
-       len = (h->buff[0] << 24) + (h->buff[1] << 16) +
-               (h->buff[2] << 8) + h->buff[3] + 4;
+       len = get_unaligned_be32(&h->buff[0]) + 4;
 
        if (len > h->bufflen) {
                /* Resubmit with the correct length */
@@ -616,7 +528,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
             k < len;
             k += off, ucp += off) {
 
-               if (h->group_id == (ucp[2] << 8) + ucp[3]) {
+               if (h->group_id == get_unaligned_be16(&ucp[2])) {
                        h->state = ucp[0] & 0x0f;
                        h->pref = ucp[0] >> 7;
                        valid_states = ucp[1];
@@ -674,13 +586,13 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
  */
 static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
 {
-       int err;
+       int err = SCSI_DH_DEV_UNSUPP;
 
-       err = alua_check_tpgs(sdev, h);
-       if (err != SCSI_DH_OK)
+       h->tpgs = alua_check_tpgs(sdev);
+       if (h->tpgs == TPGS_MODE_NONE)
                goto out;
 
-       err = alua_vpd_inquiry(sdev, h);
+       err = alua_check_vpd(sdev, h);
        if (err != SCSI_DH_OK)
                goto out;
 
diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig
new file mode 100644 (file)
index 0000000..37a0c71
--- /dev/null
@@ -0,0 +1,6 @@
+config SCSI_HISI_SAS
+       tristate "HiSilicon SAS"
+       select SCSI_SAS_LIBSAS
+       select BLK_DEV_INTEGRITY
+       help
+               This driver supports HiSilicon's SAS HBA
diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile
new file mode 100644 (file)
index 0000000..3e70eae
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SCSI_HISI_SAS)            += hisi_sas_main.o
+obj-$(CONFIG_SCSI_HISI_SAS)            += hisi_sas_v1_hw.o
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
new file mode 100644 (file)
index 0000000..5af2e41
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef _HISI_SAS_H_
+#define _HISI_SAS_H_
+
+#include <linux/dmapool.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <scsi/libsas.h>
+
+#define DRV_VERSION "v1.0"
+
+#define HISI_SAS_MAX_PHYS      9
+#define HISI_SAS_MAX_QUEUES    32
+#define HISI_SAS_QUEUE_SLOTS 512
+#define HISI_SAS_MAX_ITCT_ENTRIES 4096
+#define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES
+#define HISI_SAS_COMMAND_ENTRIES 8192
+
+#define HISI_SAS_STATUS_BUF_SZ \
+               (sizeof(struct hisi_sas_err_record) + 1024)
+#define HISI_SAS_COMMAND_TABLE_SZ \
+               (((sizeof(union hisi_sas_command_table)+3)/4)*4)
+
+#define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024)
+#define HISI_SAS_MAX_SMP_RESP_SZ 1028
+
+struct hisi_hba;
+
+enum {
+       PORT_TYPE_SAS = (1U << 1),
+       PORT_TYPE_SATA = (1U << 0),
+};
+
+enum dev_status {
+       HISI_SAS_DEV_NORMAL,
+       HISI_SAS_DEV_EH,
+};
+
+enum hisi_sas_dev_type {
+       HISI_SAS_DEV_TYPE_STP = 0,
+       HISI_SAS_DEV_TYPE_SSP,
+       HISI_SAS_DEV_TYPE_SATA,
+};
+
+struct hisi_sas_phy {
+       struct hisi_hba *hisi_hba;
+       struct hisi_sas_port    *port;
+       struct asd_sas_phy      sas_phy;
+       struct sas_identify     identify;
+       struct timer_list       timer;
+       struct work_struct      phyup_ws;
+       u64             port_id; /* from hw */
+       u64             dev_sas_addr;
+       u64             phy_type;
+       u64             frame_rcvd_size;
+       u8              frame_rcvd[32];
+       u8              phy_attached;
+       u8              reserved[3];
+       enum sas_linkrate       minimum_linkrate;
+       enum sas_linkrate       maximum_linkrate;
+};
+
+struct hisi_sas_port {
+       struct asd_sas_port     sas_port;
+       u8      port_attached;
+       u8      id; /* from hw */
+       struct list_head        list;
+};
+
+struct hisi_sas_cq {
+       struct hisi_hba *hisi_hba;
+       int     id;
+};
+
+struct hisi_sas_device {
+       enum sas_device_type    dev_type;
+       struct hisi_hba         *hisi_hba;
+       struct domain_device    *sas_device;
+       u64 attached_phy;
+       u64 device_id;
+       u64 running_req;
+       u8 dev_status;
+};
+
+struct hisi_sas_slot {
+       struct list_head entry;
+       struct sas_task *task;
+       struct hisi_sas_port    *port;
+       u64     n_elem;
+       int     dlvry_queue;
+       int     dlvry_queue_slot;
+       int     cmplt_queue;
+       int     cmplt_queue_slot;
+       int     idx;
+       void    *cmd_hdr;
+       dma_addr_t cmd_hdr_dma;
+       void    *status_buffer;
+       dma_addr_t status_buffer_dma;
+       void *command_table;
+       dma_addr_t command_table_dma;
+       struct hisi_sas_sge_page *sge_page;
+       dma_addr_t sge_page_dma;
+};
+
+struct hisi_sas_tmf_task {
+       u8 tmf;
+       u16 tag_of_task_to_be_managed;
+};
+
+struct hisi_sas_hw {
+       int (*hw_init)(struct hisi_hba *hisi_hba);
+       void (*setup_itct)(struct hisi_hba *hisi_hba,
+                          struct hisi_sas_device *device);
+       void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no);
+       int (*get_free_slot)(struct hisi_hba *hisi_hba, int *q, int *s);
+       void (*start_delivery)(struct hisi_hba *hisi_hba);
+       int (*prep_ssp)(struct hisi_hba *hisi_hba,
+                       struct hisi_sas_slot *slot, int is_tmf,
+                       struct hisi_sas_tmf_task *tmf);
+       int (*prep_smp)(struct hisi_hba *hisi_hba,
+                       struct hisi_sas_slot *slot);
+       int (*slot_complete)(struct hisi_hba *hisi_hba,
+                            struct hisi_sas_slot *slot, int abort);
+       void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
+       void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no);
+       void (*phy_hard_reset)(struct hisi_hba *hisi_hba, int phy_no);
+       void (*free_device)(struct hisi_hba *hisi_hba,
+                           struct hisi_sas_device *dev);
+       int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
+       int complete_hdr_size;
+};
+
+struct hisi_hba {
+       /* This must be the first element, used by SHOST_TO_SAS_HA */
+       struct sas_ha_struct *p;
+
+       struct platform_device *pdev;
+       void __iomem *regs;
+       struct regmap *ctrl;
+       u32 ctrl_reset_reg;
+       u32 ctrl_reset_sts_reg;
+       u32 ctrl_clock_ena_reg;
+       u8 sas_addr[SAS_ADDR_SIZE];
+
+       int n_phy;
+       int scan_finished;
+       spinlock_t lock;
+
+       struct timer_list timer;
+       struct workqueue_struct *wq;
+
+       int slot_index_count;
+       unsigned long *slot_index_tags;
+
+       /* SCSI/SAS glue */
+       struct sas_ha_struct sha;
+       struct Scsi_Host *shost;
+
+       struct hisi_sas_cq cq[HISI_SAS_MAX_QUEUES];
+       struct hisi_sas_phy phy[HISI_SAS_MAX_PHYS];
+       struct hisi_sas_port port[HISI_SAS_MAX_PHYS];
+
+       int     queue_count;
+       int     queue;
+       struct hisi_sas_slot    *slot_prep;
+
+       struct dma_pool *sge_page_pool;
+       struct hisi_sas_device  devices[HISI_SAS_MAX_DEVICES];
+       struct dma_pool *command_table_pool;
+       struct dma_pool *status_buffer_pool;
+       struct hisi_sas_cmd_hdr *cmd_hdr[HISI_SAS_MAX_QUEUES];
+       dma_addr_t cmd_hdr_dma[HISI_SAS_MAX_QUEUES];
+       void *complete_hdr[HISI_SAS_MAX_QUEUES];
+       dma_addr_t complete_hdr_dma[HISI_SAS_MAX_QUEUES];
+       struct hisi_sas_initial_fis *initial_fis;
+       dma_addr_t initial_fis_dma;
+       struct hisi_sas_itct *itct;
+       dma_addr_t itct_dma;
+       struct hisi_sas_iost *iost;
+       dma_addr_t iost_dma;
+       struct hisi_sas_breakpoint *breakpoint;
+       dma_addr_t breakpoint_dma;
+       struct hisi_sas_breakpoint *sata_breakpoint;
+       dma_addr_t sata_breakpoint_dma;
+       struct hisi_sas_slot    *slot_info;
+       const struct hisi_sas_hw *hw;   /* Low level hw interface */
+};
+
+/* Generic HW DMA host memory structures */
+/* Delivery queue header */
+struct hisi_sas_cmd_hdr {
+       /* dw0 */
+       __le32 dw0;
+
+       /* dw1 */
+       __le32 dw1;
+
+       /* dw2 */
+       __le32 dw2;
+
+       /* dw3 */
+       __le32 transfer_tags;
+
+       /* dw4 */
+       __le32 data_transfer_len;
+
+       /* dw5 */
+       __le32 first_burst_num;
+
+       /* dw6 */
+       __le32 sg_len;
+
+       /* dw7 */
+       __le32 dw7;
+
+       /* dw8-9 */
+       __le64 cmd_table_addr;
+
+       /* dw10-11 */
+       __le64 sts_buffer_addr;
+
+       /* dw12-13 */
+       __le64 prd_table_addr;
+
+       /* dw14-15 */
+       __le64 dif_prd_table_addr;
+};
+
+struct hisi_sas_itct {
+       __le64 qw0;
+       __le64 sas_addr;
+       __le64 qw2;
+       __le64 qw3;
+       __le64 qw4;
+       __le64 qw_sata_ncq0_3;
+       __le64 qw_sata_ncq7_4;
+       __le64 qw_sata_ncq11_8;
+       __le64 qw_sata_ncq15_12;
+       __le64 qw_sata_ncq19_16;
+       __le64 qw_sata_ncq23_20;
+       __le64 qw_sata_ncq27_24;
+       __le64 qw_sata_ncq31_28;
+       __le64 qw_non_ncq_iptt;
+       __le64 qw_rsvd0;
+       __le64 qw_rsvd1;
+};
+
+struct hisi_sas_iost {
+       __le64 qw0;
+       __le64 qw1;
+       __le64 qw2;
+       __le64 qw3;
+};
+
+struct hisi_sas_err_record {
+       /* dw0 */
+       __le32 dma_err_type;
+
+       /* dw1 */
+       __le32 trans_tx_fail_type;
+
+       /* dw2 */
+       __le32 trans_rx_fail_type;
+
+       /* dw3 */
+       u32 rsvd;
+};
+
+struct hisi_sas_initial_fis {
+       struct hisi_sas_err_record err_record;
+       struct dev_to_host_fis fis;
+       u32 rsvd[3];
+};
+
+struct hisi_sas_breakpoint {
+       u8      data[128];      /*io128 byte*/
+};
+
+struct hisi_sas_sge {
+       __le64 addr;
+       __le32 page_ctrl_0;
+       __le32 page_ctrl_1;
+       __le32 data_len;
+       __le32 data_off;
+};
+
+struct hisi_sas_command_table_smp {
+       u8 bytes[44];
+};
+
+struct hisi_sas_command_table_stp {
+       struct  host_to_dev_fis command_fis;
+       u8      dummy[12];
+       u8      atapi_cdb[ATAPI_CDB_LEN];
+};
+
+#define HISI_SAS_SGE_PAGE_CNT SCSI_MAX_SG_SEGMENTS
+struct hisi_sas_sge_page {
+       struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT];
+};
+
+struct hisi_sas_command_table_ssp {
+       struct ssp_frame_hdr hdr;
+       union {
+               struct {
+                       struct ssp_command_iu task;
+                       u32 prot[6];
+               };
+               struct ssp_tmf_iu ssp_task;
+               struct xfer_rdy_iu xfer_rdy;
+               struct ssp_response_iu ssp_res;
+       } u;
+};
+
+union hisi_sas_command_table {
+       struct hisi_sas_command_table_ssp ssp;
+       struct hisi_sas_command_table_smp smp;
+       struct hisi_sas_command_table_stp stp;
+};
+extern int hisi_sas_probe(struct platform_device *pdev,
+                         const struct hisi_sas_hw *ops);
+extern int hisi_sas_remove(struct platform_device *pdev);
+
+extern void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy);
+extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
+                                   struct sas_task *task,
+                                   struct hisi_sas_slot *slot);
+#endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
new file mode 100644 (file)
index 0000000..99b1950
--- /dev/null
@@ -0,0 +1,1358 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hisi_sas.h"
+#define DRV_NAME "hisi_sas"
+
+#define DEV_IS_EXPANDER(type) \
+       ((type == SAS_EDGE_EXPANDER_DEVICE) || \
+       (type == SAS_FANOUT_EXPANDER_DEVICE))
+
+#define DEV_IS_GONE(dev) \
+       ((!dev) || (dev->dev_type == SAS_PHY_UNUSED))
+
+static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
+{
+       return device->port->ha->lldd_ha;
+}
+
+static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
+{
+       void *bitmap = hisi_hba->slot_index_tags;
+
+       clear_bit(slot_idx, bitmap);
+}
+
+static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx)
+{
+       hisi_sas_slot_index_clear(hisi_hba, slot_idx);
+}
+
+static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx)
+{
+       void *bitmap = hisi_hba->slot_index_tags;
+
+       set_bit(slot_idx, bitmap);
+}
+
+static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, int *slot_idx)
+{
+       unsigned int index;
+       void *bitmap = hisi_hba->slot_index_tags;
+
+       index = find_first_zero_bit(bitmap, hisi_hba->slot_index_count);
+       if (index >= hisi_hba->slot_index_count)
+               return -SAS_QUEUE_FULL;
+       hisi_sas_slot_index_set(hisi_hba, index);
+       *slot_idx = index;
+       return 0;
+}
+
+static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba)
+{
+       int i;
+
+       for (i = 0; i < hisi_hba->slot_index_count; ++i)
+               hisi_sas_slot_index_clear(hisi_hba, i);
+}
+
+void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
+                            struct hisi_sas_slot *slot)
+{
+       struct device *dev = &hisi_hba->pdev->dev;
+
+       if (!slot->task)
+               return;
+
+       if (!sas_protocol_ata(task->task_proto))
+               if (slot->n_elem)
+                       dma_unmap_sg(dev, task->scatter, slot->n_elem,
+                                    task->data_dir);
+
+       if (slot->command_table)
+               dma_pool_free(hisi_hba->command_table_pool,
+                             slot->command_table, slot->command_table_dma);
+
+       if (slot->status_buffer)
+               dma_pool_free(hisi_hba->status_buffer_pool,
+                             slot->status_buffer, slot->status_buffer_dma);
+
+       if (slot->sge_page)
+               dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+                             slot->sge_page_dma);
+
+       list_del_init(&slot->entry);
+       task->lldd_task = NULL;
+       slot->task = NULL;
+       slot->port = NULL;
+       hisi_sas_slot_index_free(hisi_hba, slot->idx);
+       memset(slot, 0, sizeof(*slot));
+}
+EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free);
+
+static int hisi_sas_task_prep_smp(struct hisi_hba *hisi_hba,
+                                 struct hisi_sas_slot *slot)
+{
+       return hisi_hba->hw->prep_smp(hisi_hba, slot);
+}
+
+static int hisi_sas_task_prep_ssp(struct hisi_hba *hisi_hba,
+                                 struct hisi_sas_slot *slot, int is_tmf,
+                                 struct hisi_sas_tmf_task *tmf)
+{
+       return hisi_hba->hw->prep_ssp(hisi_hba, slot, is_tmf, tmf);
+}
+
+static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
+                             int is_tmf, struct hisi_sas_tmf_task *tmf,
+                             int *pass)
+{
+       struct domain_device *device = task->dev;
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       struct hisi_sas_port *port;
+       struct hisi_sas_slot *slot;
+       struct hisi_sas_cmd_hdr *cmd_hdr_base;
+       struct device *dev = &hisi_hba->pdev->dev;
+       int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+
+       if (!device->port) {
+               struct task_status_struct *ts = &task->task_status;
+
+               ts->resp = SAS_TASK_UNDELIVERED;
+               ts->stat = SAS_PHY_DOWN;
+               /*
+                * libsas will use dev->port, should
+                * not call task_done for sata
+                */
+               if (device->dev_type != SAS_SATA_DEV)
+                       task->task_done(task);
+               return 0;
+       }
+
+       if (DEV_IS_GONE(sas_dev)) {
+               if (sas_dev)
+                       dev_info(dev, "task prep: device %llu not ready\n",
+                                sas_dev->device_id);
+               else
+                       dev_info(dev, "task prep: device %016llx not ready\n",
+                                SAS_ADDR(device->sas_addr));
+
+               rc = SAS_PHY_DOWN;
+               return rc;
+       }
+       port = device->port->lldd_port;
+       if (port && !port->port_attached && !tmf) {
+               if (sas_protocol_ata(task->task_proto)) {
+                       struct task_status_struct *ts = &task->task_status;
+
+                       dev_info(dev,
+                                "task prep: SATA/STP port%d not attach device\n",
+                                device->port->id);
+                       ts->resp = SAS_TASK_COMPLETE;
+                       ts->stat = SAS_PHY_DOWN;
+                       task->task_done(task);
+               } else {
+                       struct task_status_struct *ts = &task->task_status;
+
+                       dev_info(dev,
+                                "task prep: SAS port%d does not attach device\n",
+                                device->port->id);
+                       ts->resp = SAS_TASK_UNDELIVERED;
+                       ts->stat = SAS_PHY_DOWN;
+                       task->task_done(task);
+               }
+               return 0;
+       }
+
+       if (!sas_protocol_ata(task->task_proto)) {
+               if (task->num_scatter) {
+                       n_elem = dma_map_sg(dev, task->scatter,
+                                           task->num_scatter, task->data_dir);
+                       if (!n_elem) {
+                               rc = -ENOMEM;
+                               goto prep_out;
+                       }
+               }
+       } else
+               n_elem = task->num_scatter;
+
+       rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
+       if (rc)
+               goto err_out;
+       rc = hisi_hba->hw->get_free_slot(hisi_hba, &dlvry_queue,
+                                        &dlvry_queue_slot);
+       if (rc)
+               goto err_out_tag;
+
+       slot = &hisi_hba->slot_info[slot_idx];
+       memset(slot, 0, sizeof(struct hisi_sas_slot));
+
+       slot->idx = slot_idx;
+       slot->n_elem = n_elem;
+       slot->dlvry_queue = dlvry_queue;
+       slot->dlvry_queue_slot = dlvry_queue_slot;
+       cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
+       slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
+       slot->task = task;
+       slot->port = port;
+       task->lldd_task = slot;
+
+       slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool,
+                                            GFP_ATOMIC,
+                                            &slot->status_buffer_dma);
+       if (!slot->status_buffer) {
+               rc = -ENOMEM;
+               goto err_out_slot_buf;
+       }
+       memset(slot->status_buffer, 0, HISI_SAS_STATUS_BUF_SZ);
+
+       slot->command_table = dma_pool_alloc(hisi_hba->command_table_pool,
+                                            GFP_ATOMIC,
+                                            &slot->command_table_dma);
+       if (!slot->command_table) {
+               rc = -ENOMEM;
+               goto err_out_status_buf;
+       }
+       memset(slot->command_table, 0, HISI_SAS_COMMAND_TABLE_SZ);
+       memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
+
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SMP:
+               rc = hisi_sas_task_prep_smp(hisi_hba, slot);
+               break;
+       case SAS_PROTOCOL_SSP:
+               rc = hisi_sas_task_prep_ssp(hisi_hba, slot, is_tmf, tmf);
+               break;
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
+       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+       default:
+               dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n",
+                       task->task_proto);
+               rc = -EINVAL;
+               break;
+       }
+
+       if (rc) {
+               dev_err(dev, "task prep: rc = 0x%x\n", rc);
+               if (slot->sge_page)
+                       goto err_out_sge;
+               goto err_out_command_table;
+       }
+
+       list_add_tail(&slot->entry, &port->list);
+       spin_lock(&task->task_state_lock);
+       task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+       spin_unlock(&task->task_state_lock);
+
+       hisi_hba->slot_prep = slot;
+
+       sas_dev->running_req++;
+       ++(*pass);
+
+       return 0;
+
+err_out_sge:
+       dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+               slot->sge_page_dma);
+err_out_command_table:
+       dma_pool_free(hisi_hba->command_table_pool, slot->command_table,
+               slot->command_table_dma);
+err_out_status_buf:
+       dma_pool_free(hisi_hba->status_buffer_pool, slot->status_buffer,
+               slot->status_buffer_dma);
+err_out_slot_buf:
+       /* Nothing to be done */
+err_out_tag:
+       hisi_sas_slot_index_free(hisi_hba, slot_idx);
+err_out:
+       dev_err(dev, "task prep: failed[%d]!\n", rc);
+       if (!sas_protocol_ata(task->task_proto))
+               if (n_elem)
+                       dma_unmap_sg(dev, task->scatter, n_elem,
+                                    task->data_dir);
+prep_out:
+       return rc;
+}
+
+static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
+                             int is_tmf, struct hisi_sas_tmf_task *tmf)
+{
+       u32 rc;
+       u32 pass = 0;
+       unsigned long flags;
+       struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+       struct device *dev = &hisi_hba->pdev->dev;
+
+       /* protect task_prep and start_delivery sequence */
+       spin_lock_irqsave(&hisi_hba->lock, flags);
+       rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, &pass);
+       if (rc)
+               dev_err(dev, "task exec: failed[%d]!\n", rc);
+
+       if (likely(pass))
+               hisi_hba->hw->start_delivery(hisi_hba);
+       spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+       return rc;
+}
+
+static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no)
+{
+       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;
+
+       if (!phy->phy_attached)
+               return;
+
+       sas_ha = &hisi_hba->sha;
+       sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE);
+
+       if (sas_phy->phy) {
+               struct sas_phy *sphy = sas_phy->phy;
+
+               sphy->negotiated_linkrate = sas_phy->linkrate;
+               sphy->minimum_linkrate = phy->minimum_linkrate;
+               sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+               sphy->maximum_linkrate = phy->maximum_linkrate;
+       }
+
+       if (phy->phy_type & PORT_TYPE_SAS) {
+               struct sas_identify_frame *id;
+
+               id = (struct sas_identify_frame *)phy->frame_rcvd;
+               id->dev_type = phy->identify.device_type;
+               id->initiator_bits = SAS_PROTOCOL_ALL;
+               id->target_bits = phy->identify.target_port_protocols;
+       } else if (phy->phy_type & PORT_TYPE_SATA) {
+               /*Nothing*/
+       }
+
+       sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
+       sas_ha->notify_port_event(sas_phy, PORTE_BYTES_DMAED);
+}
+
+static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
+{
+       struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+       struct hisi_sas_device *sas_dev = NULL;
+       int i;
+
+       spin_lock(&hisi_hba->lock);
+       for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+               if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
+                       hisi_hba->devices[i].device_id = i;
+                       sas_dev = &hisi_hba->devices[i];
+                       sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+                       sas_dev->dev_type = device->dev_type;
+                       sas_dev->hisi_hba = hisi_hba;
+                       sas_dev->sas_device = device;
+                       break;
+               }
+       }
+       spin_unlock(&hisi_hba->lock);
+
+       return sas_dev;
+}
+
+static int hisi_sas_dev_found(struct domain_device *device)
+{
+       struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+       struct domain_device *parent_dev = device->parent;
+       struct hisi_sas_device *sas_dev;
+       struct device *dev = &hisi_hba->pdev->dev;
+
+       sas_dev = hisi_sas_alloc_dev(device);
+       if (!sas_dev) {
+               dev_err(dev, "fail alloc dev: max support %d devices\n",
+                       HISI_SAS_MAX_DEVICES);
+               return -EINVAL;
+       }
+
+       device->lldd_dev = sas_dev;
+       hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
+
+       if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+               int phy_no;
+               u8 phy_num = parent_dev->ex_dev.num_phys;
+               struct ex_phy *phy;
+
+               for (phy_no = 0; phy_no < phy_num; phy_no++) {
+                       phy = &parent_dev->ex_dev.ex_phy[phy_no];
+                       if (SAS_ADDR(phy->attached_sas_addr) ==
+                               SAS_ADDR(device->sas_addr)) {
+                               sas_dev->attached_phy = phy_no;
+                               break;
+                       }
+               }
+
+               if (phy_no == phy_num) {
+                       dev_info(dev, "dev found: no attached "
+                                "dev:%016llx at ex:%016llx\n",
+                                SAS_ADDR(device->sas_addr),
+                                SAS_ADDR(parent_dev->sas_addr));
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void hisi_sas_scan_start(struct Scsi_Host *shost)
+{
+       struct hisi_hba *hisi_hba = shost_priv(shost);
+       int i;
+
+       for (i = 0; i < hisi_hba->n_phy; ++i)
+               hisi_sas_bytes_dmaed(hisi_hba, i);
+
+       hisi_hba->scan_finished = 1;
+}
+
+static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+       struct hisi_hba *hisi_hba = shost_priv(shost);
+       struct sas_ha_struct *sha = &hisi_hba->sha;
+
+       if (hisi_hba->scan_finished == 0)
+               return 0;
+
+       sas_drain_work(sha);
+       return 1;
+}
+
+static void hisi_sas_phyup_work(struct work_struct *work)
+{
+       struct hisi_sas_phy *phy =
+               container_of(work, struct hisi_sas_phy, phyup_ws);
+       struct hisi_hba *hisi_hba = phy->hisi_hba;
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+       int phy_no = sas_phy->id;
+
+       hisi_hba->hw->sl_notify(hisi_hba, phy_no); /* This requires a sleep */
+       hisi_sas_bytes_dmaed(hisi_hba, phy_no);
+}
+
+static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
+{
+       struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+       phy->hisi_hba = hisi_hba;
+       phy->port = NULL;
+       init_timer(&phy->timer);
+       sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0;
+       sas_phy->class = SAS;
+       sas_phy->iproto = SAS_PROTOCOL_ALL;
+       sas_phy->tproto = 0;
+       sas_phy->type = PHY_TYPE_PHYSICAL;
+       sas_phy->role = PHY_ROLE_INITIATOR;
+       sas_phy->oob_mode = OOB_NOT_CONNECTED;
+       sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+       sas_phy->id = phy_no;
+       sas_phy->sas_addr = &hisi_hba->sas_addr[0];
+       sas_phy->frame_rcvd = &phy->frame_rcvd[0];
+       sas_phy->ha = (struct sas_ha_struct *)hisi_hba->shost->hostdata;
+       sas_phy->lldd_phy = phy;
+
+       INIT_WORK(&phy->phyup_ws, hisi_sas_phyup_work);
+}
+
+static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
+{
+       struct sas_ha_struct *sas_ha = sas_phy->ha;
+       struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+       struct hisi_sas_phy *phy = sas_phy->lldd_phy;
+       struct asd_sas_port *sas_port = sas_phy->port;
+       struct hisi_sas_port *port = &hisi_hba->port[sas_phy->id];
+       unsigned long flags;
+
+       if (!sas_port)
+               return;
+
+       spin_lock_irqsave(&hisi_hba->lock, flags);
+       port->port_attached = 1;
+       port->id = phy->port_id;
+       phy->port = port;
+       sas_port->lldd_port = port;
+       spin_unlock_irqrestore(&hisi_hba->lock, flags);
+}
+
+static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, int phy_no,
+                                    struct domain_device *device)
+{
+       struct hisi_sas_phy *phy;
+       struct hisi_sas_port *port;
+       struct hisi_sas_slot *slot, *slot2;
+       struct device *dev = &hisi_hba->pdev->dev;
+
+       phy = &hisi_hba->phy[phy_no];
+       port = phy->port;
+       if (!port)
+               return;
+
+       list_for_each_entry_safe(slot, slot2, &port->list, entry) {
+               struct sas_task *task;
+
+               task = slot->task;
+               if (device && task->dev != device)
+                       continue;
+
+               dev_info(dev, "Release slot [%d:%d], task [%p]:\n",
+                        slot->dlvry_queue, slot->dlvry_queue_slot, task);
+               hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
+       }
+}
+
+static void hisi_sas_port_notify_deformed(struct asd_sas_phy *sas_phy)
+{
+       struct domain_device *device;
+       struct hisi_sas_phy *phy = sas_phy->lldd_phy;
+       struct asd_sas_port *sas_port = sas_phy->port;
+
+       list_for_each_entry(device, &sas_port->dev_list, dev_list_node)
+               hisi_sas_do_release_task(phy->hisi_hba, sas_phy->id, device);
+}
+
+static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
+                       struct domain_device *device)
+{
+       struct asd_sas_port *port = device->port;
+       struct asd_sas_phy *sas_phy;
+
+       list_for_each_entry(sas_phy, &port->phy_list, port_phy_el)
+               hisi_sas_do_release_task(hisi_hba, sas_phy->id, device);
+}
+
+static void hisi_sas_dev_gone(struct domain_device *device)
+{
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+       struct device *dev = &hisi_hba->pdev->dev;
+       u64 dev_id = sas_dev->device_id;
+
+       dev_info(dev, "found dev[%lld:%x] is gone\n",
+                sas_dev->device_id, sas_dev->dev_type);
+
+       hisi_hba->hw->free_device(hisi_hba, sas_dev);
+       device->lldd_dev = NULL;
+       memset(sas_dev, 0, sizeof(*sas_dev));
+       sas_dev->device_id = dev_id;
+       sas_dev->dev_type = SAS_PHY_UNUSED;
+       sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+}
+
+static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
+{
+       return hisi_sas_task_exec(task, gfp_flags, 0, NULL);
+}
+
+static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
+                               void *funcdata)
+{
+       struct sas_ha_struct *sas_ha = sas_phy->ha;
+       struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+       int phy_no = sas_phy->id;
+
+       switch (func) {
+       case PHY_FUNC_HARD_RESET:
+               hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no);
+               break;
+
+       case PHY_FUNC_LINK_RESET:
+               hisi_hba->hw->phy_enable(hisi_hba, phy_no);
+               hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no);
+               break;
+
+       case PHY_FUNC_DISABLE:
+               hisi_hba->hw->phy_disable(hisi_hba, phy_no);
+               break;
+
+       case PHY_FUNC_SET_LINK_RATE:
+       case PHY_FUNC_RELEASE_SPINUP_HOLD:
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static void hisi_sas_task_done(struct sas_task *task)
+{
+       if (!del_timer(&task->slow_task->timer))
+               return;
+       complete(&task->slow_task->completion);
+}
+
+static void hisi_sas_tmf_timedout(unsigned long data)
+{
+       struct sas_task *task = (struct sas_task *)data;
+
+       task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+       complete(&task->slow_task->completion);
+}
+
+#define TASK_TIMEOUT 20
+#define TASK_RETRY 3
+static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
+                                          void *parameter, u32 para_len,
+                                          struct hisi_sas_tmf_task *tmf)
+{
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
+       struct device *dev = &hisi_hba->pdev->dev;
+       struct sas_task *task;
+       int res, retry;
+
+       for (retry = 0; retry < TASK_RETRY; retry++) {
+               task = sas_alloc_slow_task(GFP_KERNEL);
+               if (!task)
+                       return -ENOMEM;
+
+               task->dev = device;
+               task->task_proto = device->tproto;
+
+               memcpy(&task->ssp_task, parameter, para_len);
+               task->task_done = hisi_sas_task_done;
+
+               task->slow_task->timer.data = (unsigned long) task;
+               task->slow_task->timer.function = hisi_sas_tmf_timedout;
+               task->slow_task->timer.expires = jiffies + TASK_TIMEOUT*HZ;
+               add_timer(&task->slow_task->timer);
+
+               res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf);
+
+               if (res) {
+                       del_timer(&task->slow_task->timer);
+                       dev_err(dev, "abort tmf: executing internal task failed: %d\n",
+                               res);
+                       goto ex_err;
+               }
+
+               wait_for_completion(&task->slow_task->completion);
+               res = TMF_RESP_FUNC_FAILED;
+               /* Even TMF timed out, return direct. */
+               if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+                       if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+                               dev_err(dev, "abort tmf: TMF task[%d] timeout\n",
+                                       tmf->tag_of_task_to_be_managed);
+                               if (task->lldd_task) {
+                                       struct hisi_sas_slot *slot =
+                                               task->lldd_task;
+
+                                       hisi_sas_slot_task_free(hisi_hba,
+                                                               task, slot);
+                               }
+
+                               goto ex_err;
+                       }
+               }
+
+               if (task->task_status.resp == SAS_TASK_COMPLETE &&
+                   task->task_status.stat == SAM_STAT_GOOD) {
+                       res = TMF_RESP_FUNC_COMPLETE;
+                       break;
+               }
+
+               if (task->task_status.resp == SAS_TASK_COMPLETE &&
+                     task->task_status.stat == SAS_DATA_UNDERRUN) {
+                       /* no error, but return the number of bytes of
+                        * underrun
+                        */
+                       dev_warn(dev, "abort tmf: task to dev %016llx "
+                                "resp: 0x%x sts 0x%x underrun\n",
+                                SAS_ADDR(device->sas_addr),
+                                task->task_status.resp,
+                                task->task_status.stat);
+                       res = task->task_status.residual;
+                       break;
+               }
+
+               if (task->task_status.resp == SAS_TASK_COMPLETE &&
+                       task->task_status.stat == SAS_DATA_OVERRUN) {
+                       dev_warn(dev, "abort tmf: blocked task error\n");
+                       res = -EMSGSIZE;
+                       break;
+               }
+
+               dev_warn(dev, "abort tmf: task to dev "
+                        "%016llx resp: 0x%x status 0x%x\n",
+                        SAS_ADDR(device->sas_addr), task->task_status.resp,
+                        task->task_status.stat);
+               sas_free_task(task);
+               task = NULL;
+       }
+ex_err:
+       WARN_ON(retry == TASK_RETRY);
+       sas_free_task(task);
+       return res;
+}
+
+static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
+                               u8 *lun, struct hisi_sas_tmf_task *tmf)
+{
+       struct sas_ssp_task ssp_task;
+
+       if (!(device->tproto & SAS_PROTOCOL_SSP))
+               return TMF_RESP_FUNC_ESUPP;
+
+       memcpy(ssp_task.LUN, lun, 8);
+
+       return hisi_sas_exec_internal_tmf_task(device, &ssp_task,
+                               sizeof(ssp_task), tmf);
+}
+
+static int hisi_sas_abort_task(struct sas_task *task)
+{
+       struct scsi_lun lun;
+       struct hisi_sas_tmf_task tmf_task;
+       struct domain_device *device = task->dev;
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+       struct device *dev = &hisi_hba->pdev->dev;
+       int rc = TMF_RESP_FUNC_FAILED;
+       unsigned long flags;
+
+       if (!sas_dev) {
+               dev_warn(dev, "Device has been removed\n");
+               return TMF_RESP_FUNC_FAILED;
+       }
+
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+               spin_unlock_irqrestore(&task->task_state_lock, flags);
+               rc = TMF_RESP_FUNC_COMPLETE;
+               goto out;
+       }
+
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
+       sas_dev->dev_status = HISI_SAS_DEV_EH;
+       if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+               struct scsi_cmnd *cmnd = task->uldd_task;
+               struct hisi_sas_slot *slot = task->lldd_task;
+               u32 tag = slot->idx;
+
+               int_to_scsilun(cmnd->device->lun, &lun);
+               tmf_task.tmf = TMF_ABORT_TASK;
+               tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+               rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun,
+                                                 &tmf_task);
+
+               /* if successful, clear the task and callback forwards.*/
+               if (rc == TMF_RESP_FUNC_COMPLETE) {
+                       if (task->lldd_task) {
+                               struct hisi_sas_slot *slot;
+
+                               slot = &hisi_hba->slot_info
+                                       [tmf_task.tag_of_task_to_be_managed];
+                               spin_lock_irqsave(&hisi_hba->lock, flags);
+                               hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
+                               spin_unlock_irqrestore(&hisi_hba->lock, flags);
+                       }
+               }
+
+       } else if (task->task_proto & SAS_PROTOCOL_SATA ||
+               task->task_proto & SAS_PROTOCOL_STP) {
+               if (task->dev->dev_type == SAS_SATA_DEV) {
+                       struct hisi_slot_info *slot = task->lldd_task;
+
+                       dev_notice(dev, "abort task: hba=%p task=%p slot=%p\n",
+                                  hisi_hba, task, slot);
+                       task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+                       rc = TMF_RESP_FUNC_COMPLETE;
+                       goto out;
+               }
+
+       }
+
+out:
+       if (rc != TMF_RESP_FUNC_COMPLETE)
+               dev_notice(dev, "abort task: rc=%d\n", rc);
+       return rc;
+}
+
+static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
+{
+       struct hisi_sas_tmf_task tmf_task;
+       int rc = TMF_RESP_FUNC_FAILED;
+
+       tmf_task.tmf = TMF_ABORT_TASK_SET;
+       rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+
+       return rc;
+}
+
+static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun)
+{
+       int rc = TMF_RESP_FUNC_FAILED;
+       struct hisi_sas_tmf_task tmf_task;
+
+       tmf_task.tmf = TMF_CLEAR_ACA;
+       rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+
+       return rc;
+}
+
+static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
+{
+       struct sas_phy *phy = sas_get_local_phy(device);
+       int rc, reset_type = (device->dev_type == SAS_SATA_DEV ||
+                       (device->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
+       rc = sas_phy_reset(phy, reset_type);
+       sas_put_local_phy(phy);
+       msleep(2000);
+       return rc;
+}
+
+static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
+{
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+       unsigned long flags;
+       int rc = TMF_RESP_FUNC_FAILED;
+
+       if (sas_dev->dev_status != HISI_SAS_DEV_EH)
+               return TMF_RESP_FUNC_FAILED;
+       sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+
+       rc = hisi_sas_debug_I_T_nexus_reset(device);
+
+       spin_lock_irqsave(&hisi_hba->lock, flags);
+       hisi_sas_release_task(hisi_hba, device);
+       spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+       return 0;
+}
+
+static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
+{
+       struct hisi_sas_tmf_task tmf_task;
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+       struct device *dev = &hisi_hba->pdev->dev;
+       unsigned long flags;
+       int rc = TMF_RESP_FUNC_FAILED;
+
+       tmf_task.tmf = TMF_LU_RESET;
+       sas_dev->dev_status = HISI_SAS_DEV_EH;
+       rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+       if (rc == TMF_RESP_FUNC_COMPLETE) {
+               spin_lock_irqsave(&hisi_hba->lock, flags);
+               hisi_sas_release_task(hisi_hba, device);
+               spin_unlock_irqrestore(&hisi_hba->lock, flags);
+       }
+
+       /* If failed, fall-through I_T_Nexus reset */
+       dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n",
+               sas_dev->device_id, rc);
+       return rc;
+}
+
+static int hisi_sas_query_task(struct sas_task *task)
+{
+       struct scsi_lun lun;
+       struct hisi_sas_tmf_task tmf_task;
+       int rc = TMF_RESP_FUNC_FAILED;
+
+       if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+               struct scsi_cmnd *cmnd = task->uldd_task;
+               struct domain_device *device = task->dev;
+               struct hisi_sas_slot *slot = task->lldd_task;
+               u32 tag = slot->idx;
+
+               int_to_scsilun(cmnd->device->lun, &lun);
+               tmf_task.tmf = TMF_QUERY_TASK;
+               tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+               rc = hisi_sas_debug_issue_ssp_tmf(device,
+                                                 lun.scsi_lun,
+                                                 &tmf_task);
+               switch (rc) {
+               /* The task is still in Lun, release it then */
+               case TMF_RESP_FUNC_SUCC:
+               /* The task is not in Lun or failed, reset the phy */
+               case TMF_RESP_FUNC_FAILED:
+               case TMF_RESP_FUNC_COMPLETE:
+                       break;
+               }
+       }
+       return rc;
+}
+
+static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
+{
+       hisi_sas_port_notify_formed(sas_phy);
+}
+
+static void hisi_sas_port_deformed(struct asd_sas_phy *sas_phy)
+{
+       hisi_sas_port_notify_deformed(sas_phy);
+}
+
+static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
+{
+       phy->phy_attached = 0;
+       phy->phy_type = 0;
+       phy->port = NULL;
+}
+
+void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
+{
+       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;
+
+       if (rdy) {
+               /* Phy down but ready */
+               hisi_sas_bytes_dmaed(hisi_hba, phy_no);
+               hisi_sas_port_notify_formed(sas_phy);
+       } else {
+               struct hisi_sas_port *port  = phy->port;
+
+               /* Phy down and not ready */
+               sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
+               sas_phy_disconnected(sas_phy);
+
+               if (port) {
+                       if (phy->phy_type & PORT_TYPE_SAS) {
+                               int port_id = port->id;
+
+                               if (!hisi_hba->hw->get_wideport_bitmap(hisi_hba,
+                                                                      port_id))
+                                       port->port_attached = 0;
+                       } else if (phy->phy_type & PORT_TYPE_SATA)
+                               port->port_attached = 0;
+               }
+               hisi_sas_phy_disconnected(phy);
+       }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
+
+static struct scsi_transport_template *hisi_sas_stt;
+
+static struct scsi_host_template hisi_sas_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = DRV_NAME,
+       .queuecommand           = sas_queuecommand,
+       .target_alloc           = sas_target_alloc,
+       .slave_configure        = sas_slave_configure,
+       .scan_finished          = hisi_sas_scan_finished,
+       .scan_start             = hisi_sas_scan_start,
+       .change_queue_depth     = sas_change_queue_depth,
+       .bios_param             = sas_bios_param,
+       .can_queue              = 1,
+       .this_id                = -1,
+       .sg_tablesize           = SG_ALL,
+       .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
+       .use_clustering         = ENABLE_CLUSTERING,
+       .eh_device_reset_handler = sas_eh_device_reset_handler,
+       .eh_bus_reset_handler   = sas_eh_bus_reset_handler,
+       .target_destroy         = sas_target_destroy,
+       .ioctl                  = sas_ioctl,
+};
+
+static struct sas_domain_function_template hisi_sas_transport_ops = {
+       .lldd_dev_found         = hisi_sas_dev_found,
+       .lldd_dev_gone          = hisi_sas_dev_gone,
+       .lldd_execute_task      = hisi_sas_queue_command,
+       .lldd_control_phy       = hisi_sas_control_phy,
+       .lldd_abort_task        = hisi_sas_abort_task,
+       .lldd_abort_task_set    = hisi_sas_abort_task_set,
+       .lldd_clear_aca         = hisi_sas_clear_aca,
+       .lldd_I_T_nexus_reset   = hisi_sas_I_T_nexus_reset,
+       .lldd_lu_reset          = hisi_sas_lu_reset,
+       .lldd_query_task        = hisi_sas_query_task,
+       .lldd_port_formed       = hisi_sas_port_formed,
+       .lldd_port_deformed     = hisi_sas_port_deformed,
+};
+
+static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+{
+       int i, s;
+       struct platform_device *pdev = hisi_hba->pdev;
+       struct device *dev = &pdev->dev;
+
+       spin_lock_init(&hisi_hba->lock);
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               hisi_sas_phy_init(hisi_hba, i);
+               hisi_hba->port[i].port_attached = 0;
+               hisi_hba->port[i].id = -1;
+               INIT_LIST_HEAD(&hisi_hba->port[i].list);
+       }
+
+       for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+               hisi_hba->devices[i].dev_type = SAS_PHY_UNUSED;
+               hisi_hba->devices[i].device_id = i;
+               hisi_hba->devices[i].dev_status = HISI_SAS_DEV_NORMAL;
+       }
+
+       for (i = 0; i < hisi_hba->queue_count; i++) {
+               struct hisi_sas_cq *cq = &hisi_hba->cq[i];
+
+               /* Completion queue structure */
+               cq->id = i;
+               cq->hisi_hba = hisi_hba;
+
+               /* Delivery queue */
+               s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+               hisi_hba->cmd_hdr[i] = dma_alloc_coherent(dev, s,
+                                       &hisi_hba->cmd_hdr_dma[i], GFP_KERNEL);
+               if (!hisi_hba->cmd_hdr[i])
+                       goto err_out;
+               memset(hisi_hba->cmd_hdr[i], 0, s);
+
+               /* Completion queue */
+               s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+               hisi_hba->complete_hdr[i] = dma_alloc_coherent(dev, s,
+                               &hisi_hba->complete_hdr_dma[i], GFP_KERNEL);
+               if (!hisi_hba->complete_hdr[i])
+                       goto err_out;
+               memset(hisi_hba->complete_hdr[i], 0, s);
+       }
+
+       s = HISI_SAS_STATUS_BUF_SZ;
+       hisi_hba->status_buffer_pool = dma_pool_create("status_buffer",
+                                                      dev, s, 16, 0);
+       if (!hisi_hba->status_buffer_pool)
+               goto err_out;
+
+       s = HISI_SAS_COMMAND_TABLE_SZ;
+       hisi_hba->command_table_pool = dma_pool_create("command_table",
+                                                      dev, s, 16, 0);
+       if (!hisi_hba->command_table_pool)
+               goto err_out;
+
+       s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+       hisi_hba->itct = dma_alloc_coherent(dev, s, &hisi_hba->itct_dma,
+                                           GFP_KERNEL);
+       if (!hisi_hba->itct)
+               goto err_out;
+
+       memset(hisi_hba->itct, 0, s);
+
+       hisi_hba->slot_info = devm_kcalloc(dev, HISI_SAS_COMMAND_ENTRIES,
+                                          sizeof(struct hisi_sas_slot),
+                                          GFP_KERNEL);
+       if (!hisi_hba->slot_info)
+               goto err_out;
+
+       s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost);
+       hisi_hba->iost = dma_alloc_coherent(dev, s, &hisi_hba->iost_dma,
+                                           GFP_KERNEL);
+       if (!hisi_hba->iost)
+               goto err_out;
+
+       memset(hisi_hba->iost, 0, s);
+
+       s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+       hisi_hba->breakpoint = dma_alloc_coherent(dev, s,
+                               &hisi_hba->breakpoint_dma, GFP_KERNEL);
+       if (!hisi_hba->breakpoint)
+               goto err_out;
+
+       memset(hisi_hba->breakpoint, 0, s);
+
+       hisi_hba->slot_index_count = HISI_SAS_COMMAND_ENTRIES;
+       s = hisi_hba->slot_index_count / sizeof(unsigned long);
+       hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL);
+       if (!hisi_hba->slot_index_tags)
+               goto err_out;
+
+       hisi_hba->sge_page_pool = dma_pool_create("status_sge", dev,
+                               sizeof(struct hisi_sas_sge_page), 16, 0);
+       if (!hisi_hba->sge_page_pool)
+               goto err_out;
+
+       s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
+       hisi_hba->initial_fis = dma_alloc_coherent(dev, s,
+                               &hisi_hba->initial_fis_dma, GFP_KERNEL);
+       if (!hisi_hba->initial_fis)
+               goto err_out;
+       memset(hisi_hba->initial_fis, 0, s);
+
+       s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2;
+       hisi_hba->sata_breakpoint = dma_alloc_coherent(dev, s,
+                               &hisi_hba->sata_breakpoint_dma, GFP_KERNEL);
+       if (!hisi_hba->sata_breakpoint)
+               goto err_out;
+       memset(hisi_hba->sata_breakpoint, 0, s);
+
+       hisi_sas_slot_index_init(hisi_hba);
+
+       hisi_hba->wq = create_singlethread_workqueue(dev_name(dev));
+       if (!hisi_hba->wq) {
+               dev_err(dev, "sas_alloc: failed to create workqueue\n");
+               goto err_out;
+       }
+
+       return 0;
+err_out:
+       return -ENOMEM;
+}
+
+static void hisi_sas_free(struct hisi_hba *hisi_hba)
+{
+       struct device *dev = &hisi_hba->pdev->dev;
+       int i, s;
+
+       for (i = 0; i < hisi_hba->queue_count; i++) {
+               s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+               if (hisi_hba->cmd_hdr[i])
+                       dma_free_coherent(dev, s,
+                                         hisi_hba->cmd_hdr[i],
+                                         hisi_hba->cmd_hdr_dma[i]);
+
+               s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+               if (hisi_hba->complete_hdr[i])
+                       dma_free_coherent(dev, s,
+                                         hisi_hba->complete_hdr[i],
+                                         hisi_hba->complete_hdr_dma[i]);
+       }
+
+       dma_pool_destroy(hisi_hba->status_buffer_pool);
+       dma_pool_destroy(hisi_hba->command_table_pool);
+       dma_pool_destroy(hisi_hba->sge_page_pool);
+
+       s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+       if (hisi_hba->itct)
+               dma_free_coherent(dev, s,
+                                 hisi_hba->itct, hisi_hba->itct_dma);
+
+       s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost);
+       if (hisi_hba->iost)
+               dma_free_coherent(dev, s,
+                                 hisi_hba->iost, hisi_hba->iost_dma);
+
+       s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+       if (hisi_hba->breakpoint)
+               dma_free_coherent(dev, s,
+                                 hisi_hba->breakpoint,
+                                 hisi_hba->breakpoint_dma);
+
+
+       s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
+       if (hisi_hba->initial_fis)
+               dma_free_coherent(dev, s,
+                                 hisi_hba->initial_fis,
+                                 hisi_hba->initial_fis_dma);
+
+       s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2;
+       if (hisi_hba->sata_breakpoint)
+               dma_free_coherent(dev, s,
+                                 hisi_hba->sata_breakpoint,
+                                 hisi_hba->sata_breakpoint_dma);
+
+       if (hisi_hba->wq)
+               destroy_workqueue(hisi_hba->wq);
+}
+
+static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
+                                             const struct hisi_sas_hw *hw)
+{
+       struct resource *res;
+       struct Scsi_Host *shost;
+       struct hisi_hba *hisi_hba;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = pdev->dev.of_node;
+       struct property *sas_addr_prop;
+
+       shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba));
+       if (!shost)
+               goto err_out;
+       hisi_hba = shost_priv(shost);
+
+       hisi_hba->hw = hw;
+       hisi_hba->pdev = pdev;
+       hisi_hba->shost = shost;
+       SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
+
+       init_timer(&hisi_hba->timer);
+
+       sas_addr_prop = of_find_property(np, "sas-addr", NULL);
+       if (!sas_addr_prop || (sas_addr_prop->length != SAS_ADDR_SIZE))
+               goto err_out;
+       memcpy(hisi_hba->sas_addr, sas_addr_prop->value, SAS_ADDR_SIZE);
+
+       if (of_property_read_u32(np, "ctrl-reset-reg",
+                                &hisi_hba->ctrl_reset_reg))
+               goto err_out;
+
+       if (of_property_read_u32(np, "ctrl-reset-sts-reg",
+                                &hisi_hba->ctrl_reset_sts_reg))
+               goto err_out;
+
+       if (of_property_read_u32(np, "ctrl-clock-ena-reg",
+                                &hisi_hba->ctrl_clock_ena_reg))
+               goto err_out;
+
+       if (of_property_read_u32(np, "phy-count", &hisi_hba->n_phy))
+               goto err_out;
+
+       if (of_property_read_u32(np, "queue-count", &hisi_hba->queue_count))
+               goto err_out;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hisi_hba->regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(hisi_hba->regs))
+               goto err_out;
+
+       hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(
+                               np, "hisilicon,sas-syscon");
+       if (IS_ERR(hisi_hba->ctrl))
+               goto err_out;
+
+       if (hisi_sas_alloc(hisi_hba, shost)) {
+               hisi_sas_free(hisi_hba);
+               goto err_out;
+       }
+
+       return shost;
+err_out:
+       dev_err(dev, "shost alloc failed\n");
+       return NULL;
+}
+
+static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
+{
+       int i;
+
+       for (i = 0; i < hisi_hba->n_phy; i++)
+               memcpy(&hisi_hba->phy[i].dev_sas_addr,
+                      hisi_hba->sas_addr,
+                      SAS_ADDR_SIZE);
+}
+
+int hisi_sas_probe(struct platform_device *pdev,
+                        const struct hisi_sas_hw *hw)
+{
+       struct Scsi_Host *shost;
+       struct hisi_hba *hisi_hba;
+       struct device *dev = &pdev->dev;
+       struct asd_sas_phy **arr_phy;
+       struct asd_sas_port **arr_port;
+       struct sas_ha_struct *sha;
+       int rc, phy_nr, port_nr, i;
+
+       shost = hisi_sas_shost_alloc(pdev, hw);
+       if (!shost) {
+               rc = -ENOMEM;
+               goto err_out_ha;
+       }
+
+       sha = SHOST_TO_SAS_HA(shost);
+       hisi_hba = shost_priv(shost);
+       platform_set_drvdata(pdev, sha);
+
+       if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) &&
+           dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
+               dev_err(dev, "No usable DMA addressing method\n");
+               rc = -EIO;
+               goto err_out_ha;
+       }
+
+       phy_nr = port_nr = hisi_hba->n_phy;
+
+       arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL);
+       arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL);
+       if (!arr_phy || !arr_port)
+               return -ENOMEM;
+
+       sha->sas_phy = arr_phy;
+       sha->sas_port = arr_port;
+       sha->core.shost = shost;
+       sha->lldd_ha = hisi_hba;
+
+       shost->transportt = hisi_sas_stt;
+       shost->max_id = HISI_SAS_MAX_DEVICES;
+       shost->max_lun = ~0;
+       shost->max_channel = 1;
+       shost->max_cmd_len = 16;
+       shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
+       shost->can_queue = HISI_SAS_COMMAND_ENTRIES;
+       shost->cmd_per_lun = HISI_SAS_COMMAND_ENTRIES;
+
+       sha->sas_ha_name = DRV_NAME;
+       sha->dev = &hisi_hba->pdev->dev;
+       sha->lldd_module = THIS_MODULE;
+       sha->sas_addr = &hisi_hba->sas_addr[0];
+       sha->num_phys = hisi_hba->n_phy;
+       sha->core.shost = hisi_hba->shost;
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy;
+               sha->sas_port[i] = &hisi_hba->port[i].sas_port;
+       }
+
+       hisi_sas_init_add(hisi_hba);
+
+       rc = hisi_hba->hw->hw_init(hisi_hba);
+       if (rc)
+               goto err_out_ha;
+
+       rc = scsi_add_host(shost, &pdev->dev);
+       if (rc)
+               goto err_out_ha;
+
+       rc = sas_register_ha(sha);
+       if (rc)
+               goto err_out_register_ha;
+
+       scsi_scan_host(shost);
+
+       return 0;
+
+err_out_register_ha:
+       scsi_remove_host(shost);
+err_out_ha:
+       kfree(shost);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_probe);
+
+int hisi_sas_remove(struct platform_device *pdev)
+{
+       struct sas_ha_struct *sha = platform_get_drvdata(pdev);
+       struct hisi_hba *hisi_hba = sha->lldd_ha;
+
+       scsi_remove_host(sha->core.shost);
+       sas_unregister_ha(sha);
+       sas_remove_host(sha->core.shost);
+
+       hisi_sas_free(hisi_hba);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_remove);
+
+static __init int hisi_sas_init(void)
+{
+       pr_info("hisi_sas: driver version %s\n", DRV_VERSION);
+
+       hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops);
+       if (!hisi_sas_stt)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static __exit void hisi_sas_exit(void)
+{
+       sas_release_transport(hisi_sas_stt);
+}
+
+module_init(hisi_sas_init);
+module_exit(hisi_sas_exit);
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
new file mode 100644 (file)
index 0000000..d543811
--- /dev/null
@@ -0,0 +1,1839 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hisi_sas.h"
+#define DRV_NAME "hisi_sas_v1_hw"
+
+/* global registers need init*/
+#define DLVRY_QUEUE_ENABLE             0x0
+#define IOST_BASE_ADDR_LO              0x8
+#define IOST_BASE_ADDR_HI              0xc
+#define ITCT_BASE_ADDR_LO              0x10
+#define ITCT_BASE_ADDR_HI              0x14
+#define BROKEN_MSG_ADDR_LO             0x18
+#define BROKEN_MSG_ADDR_HI             0x1c
+#define PHY_CONTEXT                    0x20
+#define PHY_STATE                      0x24
+#define PHY_PORT_NUM_MA                        0x28
+#define PORT_STATE                     0x2c
+#define PHY_CONN_RATE                  0x30
+#define HGC_TRANS_TASK_CNT_LIMIT       0x38
+#define AXI_AHB_CLK_CFG                        0x3c
+#define HGC_SAS_TXFAIL_RETRY_CTRL      0x84
+#define HGC_GET_ITV_TIME               0x90
+#define DEVICE_MSG_WORK_MODE           0x94
+#define I_T_NEXUS_LOSS_TIME            0xa0
+#define BUS_INACTIVE_LIMIT_TIME                0xa8
+#define REJECT_TO_OPEN_LIMIT_TIME      0xac
+#define CFG_AGING_TIME                 0xbc
+#define CFG_AGING_TIME_ITCT_REL_OFF    0
+#define CFG_AGING_TIME_ITCT_REL_MSK    (0x1 << CFG_AGING_TIME_ITCT_REL_OFF)
+#define HGC_DFX_CFG2                   0xc0
+#define FIS_LIST_BADDR_L               0xc4
+#define CFG_1US_TIMER_TRSH             0xcc
+#define CFG_SAS_CONFIG                 0xd4
+#define HGC_IOST_ECC_ADDR              0x140
+#define HGC_IOST_ECC_ADDR_BAD_OFF      16
+#define HGC_IOST_ECC_ADDR_BAD_MSK      (0x3ff << HGC_IOST_ECC_ADDR_BAD_OFF)
+#define HGC_DQ_ECC_ADDR                        0x144
+#define HGC_DQ_ECC_ADDR_BAD_OFF                16
+#define HGC_DQ_ECC_ADDR_BAD_MSK                (0xfff << HGC_DQ_ECC_ADDR_BAD_OFF)
+#define HGC_INVLD_DQE_INFO             0x148
+#define HGC_INVLD_DQE_INFO_DQ_OFF      0
+#define HGC_INVLD_DQE_INFO_DQ_MSK      (0xffff << HGC_INVLD_DQE_INFO_DQ_OFF)
+#define HGC_INVLD_DQE_INFO_TYPE_OFF    16
+#define HGC_INVLD_DQE_INFO_TYPE_MSK    (0x1 << HGC_INVLD_DQE_INFO_TYPE_OFF)
+#define HGC_INVLD_DQE_INFO_FORCE_OFF   17
+#define HGC_INVLD_DQE_INFO_FORCE_MSK   (0x1 << HGC_INVLD_DQE_INFO_FORCE_OFF)
+#define HGC_INVLD_DQE_INFO_PHY_OFF     18
+#define HGC_INVLD_DQE_INFO_PHY_MSK     (0x1 << HGC_INVLD_DQE_INFO_PHY_OFF)
+#define HGC_INVLD_DQE_INFO_ABORT_OFF   19
+#define HGC_INVLD_DQE_INFO_ABORT_MSK   (0x1 << HGC_INVLD_DQE_INFO_ABORT_OFF)
+#define HGC_INVLD_DQE_INFO_IPTT_OF_OFF 20
+#define HGC_INVLD_DQE_INFO_IPTT_OF_MSK (0x1 << HGC_INVLD_DQE_INFO_IPTT_OF_OFF)
+#define HGC_INVLD_DQE_INFO_SSP_ERR_OFF 21
+#define HGC_INVLD_DQE_INFO_SSP_ERR_MSK (0x1 << HGC_INVLD_DQE_INFO_SSP_ERR_OFF)
+#define HGC_INVLD_DQE_INFO_OFL_OFF     22
+#define HGC_INVLD_DQE_INFO_OFL_MSK     (0x1 << HGC_INVLD_DQE_INFO_OFL_OFF)
+#define HGC_ITCT_ECC_ADDR              0x150
+#define HGC_ITCT_ECC_ADDR_BAD_OFF      16
+#define HGC_ITCT_ECC_ADDR_BAD_MSK      (0x3ff << HGC_ITCT_ECC_ADDR_BAD_OFF)
+#define HGC_AXI_FIFO_ERR_INFO          0x154
+#define INT_COAL_EN                    0x1bc
+#define OQ_INT_COAL_TIME               0x1c0
+#define OQ_INT_COAL_CNT                        0x1c4
+#define ENT_INT_COAL_TIME              0x1c8
+#define ENT_INT_COAL_CNT               0x1cc
+#define OQ_INT_SRC                     0x1d0
+#define OQ_INT_SRC_MSK                 0x1d4
+#define ENT_INT_SRC1                   0x1d8
+#define ENT_INT_SRC2                   0x1dc
+#define ENT_INT_SRC2_DQ_CFG_ERR_OFF    25
+#define ENT_INT_SRC2_DQ_CFG_ERR_MSK    (0x1 << ENT_INT_SRC2_DQ_CFG_ERR_OFF)
+#define ENT_INT_SRC2_CQ_CFG_ERR_OFF    27
+#define ENT_INT_SRC2_CQ_CFG_ERR_MSK    (0x1 << ENT_INT_SRC2_CQ_CFG_ERR_OFF)
+#define ENT_INT_SRC2_AXI_WRONG_INT_OFF 28
+#define ENT_INT_SRC2_AXI_WRONG_INT_MSK (0x1 << ENT_INT_SRC2_AXI_WRONG_INT_OFF)
+#define ENT_INT_SRC2_AXI_OVERLF_INT_OFF        29
+#define ENT_INT_SRC2_AXI_OVERLF_INT_MSK        (0x1 << ENT_INT_SRC2_AXI_OVERLF_INT_OFF)
+#define ENT_INT_SRC_MSK1               0x1e0
+#define ENT_INT_SRC_MSK2               0x1e4
+#define SAS_ECC_INTR                   0x1e8
+#define SAS_ECC_INTR_DQ_ECC1B_OFF      0
+#define SAS_ECC_INTR_DQ_ECC1B_MSK      (0x1 << SAS_ECC_INTR_DQ_ECC1B_OFF)
+#define SAS_ECC_INTR_DQ_ECCBAD_OFF     1
+#define SAS_ECC_INTR_DQ_ECCBAD_MSK     (0x1 << SAS_ECC_INTR_DQ_ECCBAD_OFF)
+#define SAS_ECC_INTR_IOST_ECC1B_OFF    2
+#define SAS_ECC_INTR_IOST_ECC1B_MSK    (0x1 << SAS_ECC_INTR_IOST_ECC1B_OFF)
+#define SAS_ECC_INTR_IOST_ECCBAD_OFF   3
+#define SAS_ECC_INTR_IOST_ECCBAD_MSK   (0x1 << SAS_ECC_INTR_IOST_ECCBAD_OFF)
+#define SAS_ECC_INTR_ITCT_ECC1B_OFF    4
+#define SAS_ECC_INTR_ITCT_ECC1B_MSK    (0x1 << SAS_ECC_INTR_ITCT_ECC1B_OFF)
+#define SAS_ECC_INTR_ITCT_ECCBAD_OFF   5
+#define SAS_ECC_INTR_ITCT_ECCBAD_MSK   (0x1 << SAS_ECC_INTR_ITCT_ECCBAD_OFF)
+#define SAS_ECC_INTR_MSK               0x1ec
+#define HGC_ERR_STAT_EN                        0x238
+#define DLVRY_Q_0_BASE_ADDR_LO         0x260
+#define DLVRY_Q_0_BASE_ADDR_HI         0x264
+#define DLVRY_Q_0_DEPTH                        0x268
+#define DLVRY_Q_0_WR_PTR               0x26c
+#define DLVRY_Q_0_RD_PTR               0x270
+#define COMPL_Q_0_BASE_ADDR_LO         0x4e0
+#define COMPL_Q_0_BASE_ADDR_HI         0x4e4
+#define COMPL_Q_0_DEPTH                        0x4e8
+#define COMPL_Q_0_WR_PTR               0x4ec
+#define COMPL_Q_0_RD_PTR               0x4f0
+#define HGC_ECC_ERR                    0x7d0
+
+/* phy registers need init */
+#define PORT_BASE                      (0x800)
+
+#define PHY_CFG                                (PORT_BASE + 0x0)
+#define PHY_CFG_ENA_OFF                        0
+#define PHY_CFG_ENA_MSK                        (0x1 << PHY_CFG_ENA_OFF)
+#define PHY_CFG_DC_OPT_OFF             2
+#define PHY_CFG_DC_OPT_MSK             (0x1 << PHY_CFG_DC_OPT_OFF)
+#define PROG_PHY_LINK_RATE             (PORT_BASE + 0xc)
+#define PROG_PHY_LINK_RATE_MAX_OFF     0
+#define PROG_PHY_LINK_RATE_MAX_MSK     (0xf << PROG_PHY_LINK_RATE_MAX_OFF)
+#define PROG_PHY_LINK_RATE_MIN_OFF     4
+#define PROG_PHY_LINK_RATE_MIN_MSK     (0xf << PROG_PHY_LINK_RATE_MIN_OFF)
+#define PROG_PHY_LINK_RATE_OOB_OFF     8
+#define PROG_PHY_LINK_RATE_OOB_MSK     (0xf << PROG_PHY_LINK_RATE_OOB_OFF)
+#define PHY_CTRL                       (PORT_BASE + 0x14)
+#define PHY_CTRL_RESET_OFF             0
+#define PHY_CTRL_RESET_MSK             (0x1 << PHY_CTRL_RESET_OFF)
+#define PHY_RATE_NEGO                  (PORT_BASE + 0x30)
+#define PHY_PCN                                (PORT_BASE + 0x44)
+#define SL_TOUT_CFG                    (PORT_BASE + 0x8c)
+#define SL_CONTROL                     (PORT_BASE + 0x94)
+#define SL_CONTROL_NOTIFY_EN_OFF       0
+#define SL_CONTROL_NOTIFY_EN_MSK       (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
+#define TX_ID_DWORD0                   (PORT_BASE + 0x9c)
+#define TX_ID_DWORD1                   (PORT_BASE + 0xa0)
+#define TX_ID_DWORD2                   (PORT_BASE + 0xa4)
+#define TX_ID_DWORD3                   (PORT_BASE + 0xa8)
+#define TX_ID_DWORD4                   (PORT_BASE + 0xaC)
+#define TX_ID_DWORD5                   (PORT_BASE + 0xb0)
+#define TX_ID_DWORD6                   (PORT_BASE + 0xb4)
+#define RX_IDAF_DWORD0                 (PORT_BASE + 0xc4)
+#define RX_IDAF_DWORD1                 (PORT_BASE + 0xc8)
+#define RX_IDAF_DWORD2                 (PORT_BASE + 0xcc)
+#define RX_IDAF_DWORD3                 (PORT_BASE + 0xd0)
+#define RX_IDAF_DWORD4                 (PORT_BASE + 0xd4)
+#define RX_IDAF_DWORD5                 (PORT_BASE + 0xd8)
+#define RX_IDAF_DWORD6                 (PORT_BASE + 0xdc)
+#define RXOP_CHECK_CFG_H               (PORT_BASE + 0xfc)
+#define DONE_RECEIVED_TIME             (PORT_BASE + 0x12c)
+#define CON_CFG_DRIVER                 (PORT_BASE + 0x130)
+#define PHY_CONFIG2                    (PORT_BASE + 0x1a8)
+#define PHY_CONFIG2_FORCE_TXDEEMPH_OFF 3
+#define PHY_CONFIG2_FORCE_TXDEEMPH_MSK (0x1 << PHY_CONFIG2_FORCE_TXDEEMPH_OFF)
+#define PHY_CONFIG2_TX_TRAIN_COMP_OFF  24
+#define PHY_CONFIG2_TX_TRAIN_COMP_MSK  (0x1 << PHY_CONFIG2_TX_TRAIN_COMP_OFF)
+#define CHL_INT0                       (PORT_BASE + 0x1b0)
+#define CHL_INT0_PHYCTRL_NOTRDY_OFF    0
+#define CHL_INT0_PHYCTRL_NOTRDY_MSK    (0x1 << CHL_INT0_PHYCTRL_NOTRDY_OFF)
+#define CHL_INT0_SN_FAIL_NGR_OFF       2
+#define CHL_INT0_SN_FAIL_NGR_MSK       (0x1 << CHL_INT0_SN_FAIL_NGR_OFF)
+#define CHL_INT0_DWS_LOST_OFF          4
+#define CHL_INT0_DWS_LOST_MSK          (0x1 << CHL_INT0_DWS_LOST_OFF)
+#define CHL_INT0_SL_IDAF_FAIL_OFF      10
+#define CHL_INT0_SL_IDAF_FAIL_MSK      (0x1 << CHL_INT0_SL_IDAF_FAIL_OFF)
+#define CHL_INT0_ID_TIMEOUT_OFF                11
+#define CHL_INT0_ID_TIMEOUT_MSK                (0x1 << CHL_INT0_ID_TIMEOUT_OFF)
+#define CHL_INT0_SL_OPAF_FAIL_OFF      12
+#define CHL_INT0_SL_OPAF_FAIL_MSK      (0x1 << CHL_INT0_SL_OPAF_FAIL_OFF)
+#define CHL_INT0_SL_PS_FAIL_OFF                21
+#define CHL_INT0_SL_PS_FAIL_MSK                (0x1 << CHL_INT0_SL_PS_FAIL_OFF)
+#define CHL_INT1                       (PORT_BASE + 0x1b4)
+#define CHL_INT2                       (PORT_BASE + 0x1b8)
+#define CHL_INT2_SL_RX_BC_ACK_OFF      2
+#define CHL_INT2_SL_RX_BC_ACK_MSK      (0x1 << CHL_INT2_SL_RX_BC_ACK_OFF)
+#define CHL_INT2_SL_PHY_ENA_OFF                6
+#define CHL_INT2_SL_PHY_ENA_MSK                (0x1 << CHL_INT2_SL_PHY_ENA_OFF)
+#define CHL_INT0_MSK                   (PORT_BASE + 0x1bc)
+#define CHL_INT0_MSK_PHYCTRL_NOTRDY_OFF        0
+#define CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK        (0x1 << CHL_INT0_MSK_PHYCTRL_NOTRDY_OFF)
+#define CHL_INT1_MSK                   (PORT_BASE + 0x1c0)
+#define CHL_INT2_MSK                   (PORT_BASE + 0x1c4)
+#define CHL_INT_COAL_EN                        (PORT_BASE + 0x1d0)
+#define DMA_TX_STATUS                  (PORT_BASE + 0x2d0)
+#define DMA_TX_STATUS_BUSY_OFF         0
+#define DMA_TX_STATUS_BUSY_MSK         (0x1 << DMA_TX_STATUS_BUSY_OFF)
+#define DMA_RX_STATUS                  (PORT_BASE + 0x2e8)
+#define DMA_RX_STATUS_BUSY_OFF         0
+#define DMA_RX_STATUS_BUSY_MSK         (0x1 << DMA_RX_STATUS_BUSY_OFF)
+
+#define AXI_CFG                                0x5100
+#define RESET_VALUE                    0x7ffff
+
+/* HW dma structures */
+/* Delivery queue header */
+/* dw0 */
+#define CMD_HDR_RESP_REPORT_OFF                5
+#define CMD_HDR_RESP_REPORT_MSK                0x20
+#define CMD_HDR_TLR_CTRL_OFF           6
+#define CMD_HDR_TLR_CTRL_MSK           0xc0
+#define CMD_HDR_PORT_OFF               17
+#define CMD_HDR_PORT_MSK               0xe0000
+#define CMD_HDR_PRIORITY_OFF           27
+#define CMD_HDR_PRIORITY_MSK           0x8000000
+#define CMD_HDR_MODE_OFF               28
+#define CMD_HDR_MODE_MSK               0x10000000
+#define CMD_HDR_CMD_OFF                        29
+#define CMD_HDR_CMD_MSK                        0xe0000000
+/* dw1 */
+#define CMD_HDR_VERIFY_DTL_OFF         10
+#define CMD_HDR_VERIFY_DTL_MSK         0x400
+#define CMD_HDR_SSP_FRAME_TYPE_OFF     13
+#define CMD_HDR_SSP_FRAME_TYPE_MSK     0xe000
+#define CMD_HDR_DEVICE_ID_OFF          16
+#define CMD_HDR_DEVICE_ID_MSK          0xffff0000
+/* dw2 */
+#define CMD_HDR_CFL_OFF                        0
+#define CMD_HDR_CFL_MSK                        0x1ff
+#define CMD_HDR_MRFL_OFF               15
+#define CMD_HDR_MRFL_MSK               0xff8000
+#define CMD_HDR_FIRST_BURST_OFF                25
+#define CMD_HDR_FIRST_BURST_MSK                0x2000000
+/* dw3 */
+#define CMD_HDR_IPTT_OFF               0
+#define CMD_HDR_IPTT_MSK               0xffff
+/* dw6 */
+#define CMD_HDR_DATA_SGL_LEN_OFF       16
+#define CMD_HDR_DATA_SGL_LEN_MSK       0xffff0000
+
+/* Completion header */
+#define CMPLT_HDR_IPTT_OFF             0
+#define CMPLT_HDR_IPTT_MSK             (0xffff << CMPLT_HDR_IPTT_OFF)
+#define CMPLT_HDR_CMD_CMPLT_OFF                17
+#define CMPLT_HDR_CMD_CMPLT_MSK                (0x1 << CMPLT_HDR_CMD_CMPLT_OFF)
+#define CMPLT_HDR_ERR_RCRD_XFRD_OFF    18
+#define CMPLT_HDR_ERR_RCRD_XFRD_MSK    (0x1 << CMPLT_HDR_ERR_RCRD_XFRD_OFF)
+#define CMPLT_HDR_RSPNS_XFRD_OFF       19
+#define CMPLT_HDR_RSPNS_XFRD_MSK       (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
+#define CMPLT_HDR_IO_CFG_ERR_OFF       27
+#define CMPLT_HDR_IO_CFG_ERR_MSK       (0x1 << CMPLT_HDR_IO_CFG_ERR_OFF)
+
+/* ITCT header */
+/* qw0 */
+#define ITCT_HDR_DEV_TYPE_OFF          0
+#define ITCT_HDR_DEV_TYPE_MSK          (0x3 << ITCT_HDR_DEV_TYPE_OFF)
+#define ITCT_HDR_VALID_OFF             2
+#define ITCT_HDR_VALID_MSK             (0x1 << ITCT_HDR_VALID_OFF)
+#define ITCT_HDR_BREAK_REPLY_ENA_OFF   3
+#define ITCT_HDR_BREAK_REPLY_ENA_MSK   (0x1 << ITCT_HDR_BREAK_REPLY_ENA_OFF)
+#define ITCT_HDR_AWT_CONTROL_OFF       4
+#define ITCT_HDR_AWT_CONTROL_MSK       (0x1 << ITCT_HDR_AWT_CONTROL_OFF)
+#define ITCT_HDR_MAX_CONN_RATE_OFF     5
+#define ITCT_HDR_MAX_CONN_RATE_MSK     (0xf << ITCT_HDR_MAX_CONN_RATE_OFF)
+#define ITCT_HDR_VALID_LINK_NUM_OFF    9
+#define ITCT_HDR_VALID_LINK_NUM_MSK    (0xf << ITCT_HDR_VALID_LINK_NUM_OFF)
+#define ITCT_HDR_PORT_ID_OFF           13
+#define ITCT_HDR_PORT_ID_MSK           (0x7 << ITCT_HDR_PORT_ID_OFF)
+#define ITCT_HDR_SMP_TIMEOUT_OFF       16
+#define ITCT_HDR_SMP_TIMEOUT_MSK       (0xffff << ITCT_HDR_SMP_TIMEOUT_OFF)
+#define ITCT_HDR_MAX_BURST_BYTES_OFF   16
+#define ITCT_HDR_MAX_BURST_BYTES_MSK   (0xffffffff << \
+                                       ITCT_MAX_BURST_BYTES_OFF)
+/* qw1 */
+#define ITCT_HDR_MAX_SAS_ADDR_OFF      0
+#define ITCT_HDR_MAX_SAS_ADDR_MSK      (0xffffffffffffffff << \
+                                       ITCT_HDR_MAX_SAS_ADDR_OFF)
+/* qw2 */
+#define ITCT_HDR_IT_NEXUS_LOSS_TL_OFF  0
+#define ITCT_HDR_IT_NEXUS_LOSS_TL_MSK  (0xffff << \
+                                       ITCT_HDR_IT_NEXUS_LOSS_TL_OFF)
+#define ITCT_HDR_BUS_INACTIVE_TL_OFF   16
+#define ITCT_HDR_BUS_INACTIVE_TL_MSK   (0xffff << \
+                                       ITCT_HDR_BUS_INACTIVE_TL_OFF)
+#define ITCT_HDR_MAX_CONN_TL_OFF       32
+#define ITCT_HDR_MAX_CONN_TL_MSK       (0xffff << \
+                                       ITCT_HDR_MAX_CONN_TL_OFF)
+#define ITCT_HDR_REJ_OPEN_TL_OFF       48
+#define ITCT_HDR_REJ_OPEN_TL_MSK       (0xffff << \
+                                       ITCT_REJ_OPEN_TL_OFF)
+
+/* Err record header */
+#define ERR_HDR_DMA_TX_ERR_TYPE_OFF    0
+#define ERR_HDR_DMA_TX_ERR_TYPE_MSK    (0xffff << ERR_HDR_DMA_TX_ERR_TYPE_OFF)
+#define ERR_HDR_DMA_RX_ERR_TYPE_OFF    16
+#define ERR_HDR_DMA_RX_ERR_TYPE_MSK    (0xffff << ERR_HDR_DMA_RX_ERR_TYPE_OFF)
+
+struct hisi_sas_complete_v1_hdr {
+       __le32 data;
+};
+
+enum {
+       HISI_SAS_PHY_BCAST_ACK = 0,
+       HISI_SAS_PHY_SL_PHY_ENABLED,
+       HISI_SAS_PHY_INT_ABNORMAL,
+       HISI_SAS_PHY_INT_NR
+};
+
+enum {
+       DMA_TX_ERR_BASE = 0x0,
+       DMA_RX_ERR_BASE = 0x100,
+       TRANS_TX_FAIL_BASE = 0x200,
+       TRANS_RX_FAIL_BASE = 0x300,
+
+       /* dma tx */
+       DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x0 */
+       DMA_TX_DIF_APP_ERR, /* 0x1 */
+       DMA_TX_DIF_RPP_ERR, /* 0x2 */
+       DMA_TX_AXI_BUS_ERR, /* 0x3 */
+       DMA_TX_DATA_SGL_OVERFLOW_ERR, /* 0x4 */
+       DMA_TX_DIF_SGL_OVERFLOW_ERR, /* 0x5 */
+       DMA_TX_UNEXP_XFER_RDY_ERR, /* 0x6 */
+       DMA_TX_XFER_RDY_OFFSET_ERR, /* 0x7 */
+       DMA_TX_DATA_UNDERFLOW_ERR, /* 0x8 */
+       DMA_TX_XFER_RDY_LENGTH_OVERFLOW_ERR, /* 0x9 */
+
+       /* dma rx */
+       DMA_RX_BUFFER_ECC_ERR = DMA_RX_ERR_BASE, /* 0x100 */
+       DMA_RX_DIF_CRC_ERR, /* 0x101 */
+       DMA_RX_DIF_APP_ERR, /* 0x102 */
+       DMA_RX_DIF_RPP_ERR, /* 0x103 */
+       DMA_RX_RESP_BUFFER_OVERFLOW_ERR, /* 0x104 */
+       DMA_RX_AXI_BUS_ERR, /* 0x105 */
+       DMA_RX_DATA_SGL_OVERFLOW_ERR, /* 0x106 */
+       DMA_RX_DIF_SGL_OVERFLOW_ERR, /* 0x107 */
+       DMA_RX_DATA_OFFSET_ERR, /* 0x108 */
+       DMA_RX_UNEXP_RX_DATA_ERR, /* 0x109 */
+       DMA_RX_DATA_OVERFLOW_ERR, /* 0x10a */
+       DMA_RX_DATA_UNDERFLOW_ERR, /* 0x10b */
+       DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x10c */
+
+       /* trans tx */
+       TRANS_TX_RSVD0_ERR = TRANS_TX_FAIL_BASE, /* 0x200 */
+       TRANS_TX_PHY_NOT_ENABLE_ERR, /* 0x201 */
+       TRANS_TX_OPEN_REJCT_WRONG_DEST_ERR, /* 0x202 */
+       TRANS_TX_OPEN_REJCT_ZONE_VIOLATION_ERR, /* 0x203 */
+       TRANS_TX_OPEN_REJCT_BY_OTHER_ERR, /* 0x204 */
+       TRANS_TX_RSVD1_ERR, /* 0x205 */
+       TRANS_TX_OPEN_REJCT_AIP_TIMEOUT_ERR, /* 0x206 */
+       TRANS_TX_OPEN_REJCT_STP_BUSY_ERR, /* 0x207 */
+       TRANS_TX_OPEN_REJCT_PROTOCOL_NOT_SUPPORT_ERR, /* 0x208 */
+       TRANS_TX_OPEN_REJCT_RATE_NOT_SUPPORT_ERR, /* 0x209 */
+       TRANS_TX_OPEN_REJCT_BAD_DEST_ERR, /* 0x20a */
+       TRANS_TX_OPEN_BREAK_RECEIVE_ERR, /* 0x20b */
+       TRANS_TX_LOW_PHY_POWER_ERR, /* 0x20c */
+       TRANS_TX_OPEN_REJCT_PATHWAY_BLOCKED_ERR, /* 0x20d */
+       TRANS_TX_OPEN_TIMEOUT_ERR, /* 0x20e */
+       TRANS_TX_OPEN_REJCT_NO_DEST_ERR, /* 0x20f */
+       TRANS_TX_OPEN_RETRY_ERR, /* 0x210 */
+       TRANS_TX_RSVD2_ERR, /* 0x211 */
+       TRANS_TX_BREAK_TIMEOUT_ERR, /* 0x212 */
+       TRANS_TX_BREAK_REQUEST_ERR, /* 0x213 */
+       TRANS_TX_BREAK_RECEIVE_ERR, /* 0x214 */
+       TRANS_TX_CLOSE_TIMEOUT_ERR, /* 0x215 */
+       TRANS_TX_CLOSE_NORMAL_ERR, /* 0x216 */
+       TRANS_TX_CLOSE_PHYRESET_ERR, /* 0x217 */
+       TRANS_TX_WITH_CLOSE_DWS_TIMEOUT_ERR, /* 0x218 */
+       TRANS_TX_WITH_CLOSE_COMINIT_ERR, /* 0x219 */
+       TRANS_TX_NAK_RECEIVE_ERR, /* 0x21a */
+       TRANS_TX_ACK_NAK_TIMEOUT_ERR, /* 0x21b */
+       TRANS_TX_CREDIT_TIMEOUT_ERR, /* 0x21c */
+       TRANS_TX_IPTT_CONFLICT_ERR, /* 0x21d */
+       TRANS_TX_TXFRM_TYPE_ERR, /* 0x21e */
+       TRANS_TX_TXSMP_LENGTH_ERR, /* 0x21f */
+
+       /* trans rx */
+       TRANS_RX_FRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x300 */
+       TRANS_RX_FRAME_DONE_ERR, /* 0x301 */
+       TRANS_RX_FRAME_ERRPRM_ERR, /* 0x302 */
+       TRANS_RX_FRAME_NO_CREDIT_ERR, /* 0x303 */
+       TRANS_RX_RSVD0_ERR, /* 0x304 */
+       TRANS_RX_FRAME_OVERRUN_ERR, /* 0x305 */
+       TRANS_RX_FRAME_NO_EOF_ERR, /* 0x306 */
+       TRANS_RX_LINK_BUF_OVERRUN_ERR, /* 0x307 */
+       TRANS_RX_BREAK_TIMEOUT_ERR, /* 0x308 */
+       TRANS_RX_BREAK_REQUEST_ERR, /* 0x309 */
+       TRANS_RX_BREAK_RECEIVE_ERR, /* 0x30a */
+       TRANS_RX_CLOSE_TIMEOUT_ERR, /* 0x30b */
+       TRANS_RX_CLOSE_NORMAL_ERR, /* 0x30c */
+       TRANS_RX_CLOSE_PHYRESET_ERR, /* 0x30d */
+       TRANS_RX_WITH_CLOSE_DWS_TIMEOUT_ERR, /* 0x30e */
+       TRANS_RX_WITH_CLOSE_COMINIT_ERR, /* 0x30f */
+       TRANS_RX_DATA_LENGTH0_ERR, /* 0x310 */
+       TRANS_RX_BAD_HASH_ERR, /* 0x311 */
+       TRANS_RX_XRDY_ZERO_ERR, /* 0x312 */
+       TRANS_RX_SSP_FRAME_LEN_ERR, /* 0x313 */
+       TRANS_RX_TRANS_RX_RSVD1_ERR, /* 0x314 */
+       TRANS_RX_NO_BALANCE_ERR, /* 0x315 */
+       TRANS_RX_TRANS_RX_RSVD2_ERR, /* 0x316 */
+       TRANS_RX_TRANS_RX_RSVD3_ERR, /* 0x317 */
+       TRANS_RX_BAD_FRAME_TYPE_ERR, /* 0x318 */
+       TRANS_RX_SMP_FRAME_LEN_ERR, /* 0x319 */
+       TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x31a */
+};
+
+#define HISI_SAS_PHY_MAX_INT_NR (HISI_SAS_PHY_INT_NR * HISI_SAS_MAX_PHYS)
+#define HISI_SAS_CQ_MAX_INT_NR (HISI_SAS_MAX_QUEUES)
+#define HISI_SAS_FATAL_INT_NR (2)
+
+#define HISI_SAS_MAX_INT_NR \
+       (HISI_SAS_PHY_MAX_INT_NR + HISI_SAS_CQ_MAX_INT_NR +\
+       HISI_SAS_FATAL_INT_NR)
+
+static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+{
+       void __iomem *regs = hisi_hba->regs + off;
+
+       return readl(regs);
+}
+
+static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
+{
+       void __iomem *regs = hisi_hba->regs + off;
+
+       return readl_relaxed(regs);
+}
+
+static void hisi_sas_write32(struct hisi_hba *hisi_hba,
+                                   u32 off, u32 val)
+{
+       void __iomem *regs = hisi_hba->regs + off;
+
+       writel(val, regs);
+}
+
+static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba,
+                                       int phy_no, u32 off, u32 val)
+{
+       void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+       writel(val, regs);
+}
+
+static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
+                                     int phy_no, u32 off)
+{
+       void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+       return readl(regs);
+}
+
+static void config_phy_opt_mode_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+       cfg &= ~PHY_CFG_DC_OPT_MSK;
+       cfg |= 1 << PHY_CFG_DC_OPT_OFF;
+       hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void config_tx_tfe_autoneg_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CONFIG2);
+
+       cfg &= ~PHY_CONFIG2_FORCE_TXDEEMPH_MSK;
+       hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CONFIG2, cfg);
+}
+
+static void config_id_frame_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       struct sas_identify_frame identify_frame;
+       u32 *identify_buffer;
+
+       memset(&identify_frame, 0, sizeof(identify_frame));
+       identify_frame.dev_type = SAS_END_DEVICE;
+       identify_frame.frame_type = 0;
+       identify_frame._un1 = 1;
+       identify_frame.initiator_bits = SAS_PROTOCOL_ALL;
+       identify_frame.target_bits = SAS_PROTOCOL_NONE;
+       memcpy(&identify_frame._un4_11[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+       memcpy(&identify_frame.sas_addr[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+       identify_frame.phy_id = phy_no;
+       identify_buffer = (u32 *)(&identify_frame);
+
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
+                       __swab32(identify_buffer[0]));
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
+                       identify_buffer[2]);
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
+                       identify_buffer[1]);
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
+                       identify_buffer[4]);
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
+                       identify_buffer[3]);
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
+                       __swab32(identify_buffer[5]));
+}
+
+static void init_id_frame_v1_hw(struct hisi_hba *hisi_hba)
+{
+       int i;
+
+       for (i = 0; i < hisi_hba->n_phy; i++)
+               config_id_frame_v1_hw(hisi_hba, i);
+}
+
+static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
+                            struct hisi_sas_device *sas_dev)
+{
+       struct domain_device *device = sas_dev->sas_device;
+       struct device *dev = &hisi_hba->pdev->dev;
+       u64 qw0, device_id = sas_dev->device_id;
+       struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
+
+       memset(itct, 0, sizeof(*itct));
+
+       /* qw0 */
+       qw0 = 0;
+       switch (sas_dev->dev_type) {
+       case SAS_END_DEVICE:
+       case SAS_EDGE_EXPANDER_DEVICE:
+       case SAS_FANOUT_EXPANDER_DEVICE:
+               qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
+               break;
+       default:
+               dev_warn(dev, "setup itct: unsupported dev type (%d)\n",
+                        sas_dev->dev_type);
+       }
+
+       qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
+               (1 << ITCT_HDR_AWT_CONTROL_OFF) |
+               (device->max_linkrate << ITCT_HDR_MAX_CONN_RATE_OFF) |
+               (1 << ITCT_HDR_VALID_LINK_NUM_OFF) |
+               (device->port->id << ITCT_HDR_PORT_ID_OFF));
+       itct->qw0 = cpu_to_le64(qw0);
+
+       /* qw1 */
+       memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+       itct->sas_addr = __swab64(itct->sas_addr);
+
+       /* qw2 */
+       itct->qw2 = cpu_to_le64((500 < ITCT_HDR_IT_NEXUS_LOSS_TL_OFF) |
+                               (0xff00 < ITCT_HDR_BUS_INACTIVE_TL_OFF) |
+                               (0xff00 < ITCT_HDR_MAX_CONN_TL_OFF) |
+                               (0xff00 < ITCT_HDR_REJ_OPEN_TL_OFF));
+}
+
+static void free_device_v1_hw(struct hisi_hba *hisi_hba,
+                             struct hisi_sas_device *sas_dev)
+{
+       u64 dev_id = sas_dev->device_id;
+       struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
+       u32 qw0, reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
+
+       reg_val |= CFG_AGING_TIME_ITCT_REL_MSK;
+       hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
+
+       /* free itct */
+       udelay(1);
+       reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
+       reg_val &= ~CFG_AGING_TIME_ITCT_REL_MSK;
+       hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
+
+       qw0 = cpu_to_le64(itct->qw0);
+       qw0 &= ~ITCT_HDR_VALID_MSK;
+       itct->qw0 = cpu_to_le64(qw0);
+}
+
+static int reset_hw_v1_hw(struct hisi_hba *hisi_hba)
+{
+       int i;
+       unsigned long end_time;
+       u32 val;
+       struct device *dev = &hisi_hba->pdev->dev;
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               u32 phy_ctrl = hisi_sas_phy_read32(hisi_hba, i, PHY_CTRL);
+
+               phy_ctrl |= PHY_CTRL_RESET_MSK;
+               hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, phy_ctrl);
+       }
+       msleep(1); /* It is safe to wait for 50us */
+
+       /* Ensure DMA tx & rx idle */
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               u32 dma_tx_status, dma_rx_status;
+
+               end_time = jiffies + msecs_to_jiffies(1000);
+
+               while (1) {
+                       dma_tx_status = hisi_sas_phy_read32(hisi_hba, i,
+                                                           DMA_TX_STATUS);
+                       dma_rx_status = hisi_sas_phy_read32(hisi_hba, i,
+                                                           DMA_RX_STATUS);
+
+                       if (!(dma_tx_status & DMA_TX_STATUS_BUSY_MSK) &&
+                               !(dma_rx_status & DMA_RX_STATUS_BUSY_MSK))
+                               break;
+
+                       msleep(20);
+                       if (time_after(jiffies, end_time))
+                               return -EIO;
+               }
+       }
+
+       /* Ensure axi bus idle */
+       end_time = jiffies + msecs_to_jiffies(1000);
+       while (1) {
+               u32 axi_status =
+                       hisi_sas_read32(hisi_hba, AXI_CFG);
+
+               if (axi_status == 0)
+                       break;
+
+               msleep(20);
+               if (time_after(jiffies, end_time))
+                       return -EIO;
+       }
+
+       /* Apply reset and disable clock */
+       /* clk disable reg is offset by +4 bytes from clk enable reg */
+       regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
+                    RESET_VALUE);
+       regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
+                    RESET_VALUE);
+       msleep(1);
+       regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+       if (RESET_VALUE != (val & RESET_VALUE)) {
+               dev_err(dev, "Reset failed\n");
+               return -EIO;
+       }
+
+       /* De-reset and enable clock */
+       /* deassert rst reg is offset by +4 bytes from assert reg */
+       regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
+                    RESET_VALUE);
+       regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
+                    RESET_VALUE);
+       msleep(1);
+       regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+       if (val & RESET_VALUE) {
+               dev_err(dev, "De-reset failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void init_reg_v1_hw(struct hisi_hba *hisi_hba)
+{
+       int i;
+
+       /* Global registers init*/
+       hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
+                        (u32)((1ULL << hisi_hba->queue_count) - 1));
+       hisi_sas_write32(hisi_hba, HGC_TRANS_TASK_CNT_LIMIT, 0x11);
+       hisi_sas_write32(hisi_hba, DEVICE_MSG_WORK_MODE, 0x1);
+       hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x1ff);
+       hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x401);
+       hisi_sas_write32(hisi_hba, CFG_1US_TIMER_TRSH, 0x64);
+       hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1);
+       hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x64);
+       hisi_sas_write32(hisi_hba, BUS_INACTIVE_LIMIT_TIME, 0x2710);
+       hisi_sas_write32(hisi_hba, REJECT_TO_OPEN_LIMIT_TIME, 0x1);
+       hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x7a12);
+       hisi_sas_write32(hisi_hba, HGC_DFX_CFG2, 0x9c40);
+       hisi_sas_write32(hisi_hba, FIS_LIST_BADDR_L, 0x2);
+       hisi_sas_write32(hisi_hba, INT_COAL_EN, 0xc);
+       hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x186a0);
+       hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 1);
+       hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1);
+       hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1);
+       hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0xffffffff);
+       hisi_sas_write32(hisi_hba, OQ_INT_SRC_MSK, 0);
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC1, 0xffffffff);
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0);
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC2, 0xffffffff);
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0);
+       hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0);
+       hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 0x2);
+       hisi_sas_write32(hisi_hba, CFG_SAS_CONFIG, 0x22000000);
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x88a);
+               hisi_sas_phy_write32(hisi_hba, i, PHY_CONFIG2, 0x7c080);
+               hisi_sas_phy_write32(hisi_hba, i, PHY_RATE_NEGO, 0x415ee00);
+               hisi_sas_phy_write32(hisi_hba, i, PHY_PCN, 0x80a80000);
+               hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
+               hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x0);
+               hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
+               hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0);
+               hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, 0x13f0a);
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT_COAL_EN, 3);
+               hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 8);
+       }
+
+       for (i = 0; i < hisi_hba->queue_count; i++) {
+               /* Delivery queue */
+               hisi_sas_write32(hisi_hba,
+                                DLVRY_Q_0_BASE_ADDR_HI + (i * 0x14),
+                                upper_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+               hisi_sas_write32(hisi_hba,
+                                DLVRY_Q_0_BASE_ADDR_LO + (i * 0x14),
+                                lower_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+               hisi_sas_write32(hisi_hba,
+                                DLVRY_Q_0_DEPTH + (i * 0x14),
+                                HISI_SAS_QUEUE_SLOTS);
+
+               /* Completion queue */
+               hisi_sas_write32(hisi_hba,
+                                COMPL_Q_0_BASE_ADDR_HI + (i * 0x14),
+                                upper_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+               hisi_sas_write32(hisi_hba,
+                                COMPL_Q_0_BASE_ADDR_LO + (i * 0x14),
+                                lower_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+               hisi_sas_write32(hisi_hba, COMPL_Q_0_DEPTH + (i * 0x14),
+                                HISI_SAS_QUEUE_SLOTS);
+       }
+
+       /* itct */
+       hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_LO,
+                        lower_32_bits(hisi_hba->itct_dma));
+
+       hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_HI,
+                        upper_32_bits(hisi_hba->itct_dma));
+
+       /* iost */
+       hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_LO,
+                        lower_32_bits(hisi_hba->iost_dma));
+
+       hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_HI,
+                        upper_32_bits(hisi_hba->iost_dma));
+
+       /* breakpoint */
+       hisi_sas_write32(hisi_hba, BROKEN_MSG_ADDR_LO,
+                        lower_32_bits(hisi_hba->breakpoint_dma));
+
+       hisi_sas_write32(hisi_hba, BROKEN_MSG_ADDR_HI,
+                        upper_32_bits(hisi_hba->breakpoint_dma));
+}
+
+static int hw_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+       struct device *dev = &hisi_hba->pdev->dev;
+       int rc;
+
+       rc = reset_hw_v1_hw(hisi_hba);
+       if (rc) {
+               dev_err(dev, "hisi_sas_reset_hw failed, rc=%d", rc);
+               return rc;
+       }
+
+       msleep(100);
+       init_reg_v1_hw(hisi_hba);
+
+       init_id_frame_v1_hw(hisi_hba);
+
+       return 0;
+}
+
+static void enable_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+       cfg |= PHY_CFG_ENA_MSK;
+       hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void disable_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+       cfg &= ~PHY_CFG_ENA_MSK;
+       hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void start_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       config_id_frame_v1_hw(hisi_hba, phy_no);
+       config_phy_opt_mode_v1_hw(hisi_hba, phy_no);
+       config_tx_tfe_autoneg_v1_hw(hisi_hba, phy_no);
+       enable_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void stop_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       disable_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void phy_hard_reset_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       stop_phy_v1_hw(hisi_hba, phy_no);
+       msleep(100);
+       start_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void start_phys_v1_hw(unsigned long data)
+{
+       struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+       int i;
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x12a);
+               start_phy_v1_hw(hisi_hba, i);
+       }
+}
+
+static void phys_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+       int i;
+       struct timer_list *timer = &hisi_hba->timer;
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x6a);
+               hisi_sas_phy_read32(hisi_hba, i, CHL_INT2_MSK);
+       }
+
+       setup_timer(timer, start_phys_v1_hw, (unsigned long)hisi_hba);
+       mod_timer(timer, jiffies + HZ);
+}
+
+static void sl_notify_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       u32 sl_control;
+
+       sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+       sl_control |= SL_CONTROL_NOTIFY_EN_MSK;
+       hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+       msleep(1);
+       sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+       sl_control &= ~SL_CONTROL_NOTIFY_EN_MSK;
+       hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+}
+
+static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
+{
+       int i, bitmap = 0;
+       u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+
+       for (i = 0; i < hisi_hba->n_phy; i++)
+               if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
+                       bitmap |= 1 << i;
+
+       return bitmap;
+}
+
+/**
+ * This function allocates across all queues to load balance.
+ * Slots are allocated from queues in a round-robin fashion.
+ *
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, int *q, int *s)
+{
+       struct device *dev = &hisi_hba->pdev->dev;
+       u32 r, w;
+       int queue = hisi_hba->queue;
+
+       while (1) {
+               w = hisi_sas_read32_relaxed(hisi_hba,
+                                   DLVRY_Q_0_WR_PTR + (queue * 0x14));
+               r = hisi_sas_read32_relaxed(hisi_hba,
+                                   DLVRY_Q_0_RD_PTR + (queue * 0x14));
+               if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+                       queue = (queue + 1) % hisi_hba->queue_count;
+                       if (queue == hisi_hba->queue) {
+                               dev_warn(dev, "could not find free slot\n");
+                               return -EAGAIN;
+                       }
+                       continue;
+               }
+               break;
+       }
+       hisi_hba->queue = (queue + 1) % hisi_hba->queue_count;
+       *q = queue;
+       *s = w;
+       return 0;
+}
+
+static void start_delivery_v1_hw(struct hisi_hba *hisi_hba)
+{
+       int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
+       int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+
+       hisi_sas_write32(hisi_hba,
+                        DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+                        ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS);
+}
+
+static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba,
+                             struct hisi_sas_slot *slot,
+                             struct hisi_sas_cmd_hdr *hdr,
+                             struct scatterlist *scatter,
+                             int n_elem)
+{
+       struct device *dev = &hisi_hba->pdev->dev;
+       struct scatterlist *sg;
+       int i;
+
+       if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
+               dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
+                       n_elem);
+               return -EINVAL;
+       }
+
+       slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+                                       &slot->sge_page_dma);
+       if (!slot->sge_page)
+               return -ENOMEM;
+
+       for_each_sg(scatter, sg, n_elem, i) {
+               struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
+
+               entry->addr = cpu_to_le64(sg_dma_address(sg));
+               entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+               entry->data_len = cpu_to_le32(sg_dma_len(sg));
+               entry->data_off = 0;
+       }
+
+       hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
+
+       hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+       return 0;
+}
+
+static int prep_smp_v1_hw(struct hisi_hba *hisi_hba,
+                         struct hisi_sas_slot *slot)
+{
+       struct sas_task *task = slot->task;
+       struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+       struct domain_device *device = task->dev;
+       struct device *dev = &hisi_hba->pdev->dev;
+       struct hisi_sas_port *port = slot->port;
+       struct scatterlist *sg_req, *sg_resp;
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       dma_addr_t req_dma_addr;
+       unsigned int req_len, resp_len;
+       int elem, rc;
+
+       /*
+       * DMA-map SMP request, response buffers
+       */
+       /* req */
+       sg_req = &task->smp_task.smp_req;
+       elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
+       if (!elem)
+               return -ENOMEM;
+       req_len = sg_dma_len(sg_req);
+       req_dma_addr = sg_dma_address(sg_req);
+
+       /* resp */
+       sg_resp = &task->smp_task.smp_resp;
+       elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
+       if (!elem) {
+               rc = -ENOMEM;
+               goto err_out_req;
+       }
+       resp_len = sg_dma_len(sg_resp);
+       if ((req_len & 0x3) || (resp_len & 0x3)) {
+               rc = -EINVAL;
+               goto err_out_resp;
+       }
+
+       /* create header */
+       /* dw0 */
+       hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
+                              (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */
+                              (1 << CMD_HDR_MODE_OFF) | /* ini mode */
+                              (2 << CMD_HDR_CMD_OFF)); /* smp */
+
+       /* map itct entry */
+       hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEVICE_ID_OFF);
+
+       /* dw2 */
+       hdr->dw2 = cpu_to_le32((((req_len-4)/4) << CMD_HDR_CFL_OFF) |
+                              (HISI_SAS_MAX_SMP_RESP_SZ/4 <<
+                              CMD_HDR_MRFL_OFF));
+
+       hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+       hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+       hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+       return 0;
+
+err_out_resp:
+       dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
+                    DMA_FROM_DEVICE);
+err_out_req:
+       dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
+                    DMA_TO_DEVICE);
+       return rc;
+}
+
+static int prep_ssp_v1_hw(struct hisi_hba *hisi_hba,
+                         struct hisi_sas_slot *slot, int is_tmf,
+                         struct hisi_sas_tmf_task *tmf)
+{
+       struct sas_task *task = slot->task;
+       struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+       struct domain_device *device = task->dev;
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
+       struct hisi_sas_port *port = slot->port;
+       struct sas_ssp_task *ssp_task = &task->ssp_task;
+       struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
+       int has_data = 0, rc, priority = is_tmf;
+       u8 *buf_cmd, fburst = 0;
+       u32 dw1, dw2;
+
+       /* create header */
+       hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
+                              (0x2 << CMD_HDR_TLR_CTRL_OFF) |
+                              (port->id << CMD_HDR_PORT_OFF) |
+                              (priority << CMD_HDR_PRIORITY_OFF) |
+                              (1 << CMD_HDR_MODE_OFF) | /* ini mode */
+                              (1 << CMD_HDR_CMD_OFF)); /* ssp */
+
+       dw1 = 1 << CMD_HDR_VERIFY_DTL_OFF;
+
+       if (is_tmf) {
+               dw1 |= 3 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+       } else {
+               switch (scsi_cmnd->sc_data_direction) {
+               case DMA_TO_DEVICE:
+                       dw1 |= 2 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+                       has_data = 1;
+                       break;
+               case DMA_FROM_DEVICE:
+                       dw1 |= 1 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+                       has_data = 1;
+                       break;
+               default:
+                       dw1 |= 0 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+               }
+       }
+
+       /* map itct entry */
+       dw1 |= sas_dev->device_id << CMD_HDR_DEVICE_ID_OFF;
+       hdr->dw1 = cpu_to_le32(dw1);
+
+       if (is_tmf) {
+               dw2 = ((sizeof(struct ssp_tmf_iu) +
+                       sizeof(struct ssp_frame_hdr)+3)/4) <<
+                       CMD_HDR_CFL_OFF;
+       } else {
+               dw2 = ((sizeof(struct ssp_command_iu) +
+                       sizeof(struct ssp_frame_hdr)+3)/4) <<
+                       CMD_HDR_CFL_OFF;
+       }
+
+       dw2 |= (HISI_SAS_MAX_SSP_RESP_SZ/4) << CMD_HDR_MRFL_OFF;
+
+       hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+       if (has_data) {
+               rc = prep_prd_sge_v1_hw(hisi_hba, slot, hdr, task->scatter,
+                                       slot->n_elem);
+               if (rc)
+                       return rc;
+       }
+
+       hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+       hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+       hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+       buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
+       if (task->ssp_task.enable_first_burst) {
+               fburst = (1 << 7);
+               dw2 |= 1 << CMD_HDR_FIRST_BURST_OFF;
+       }
+       hdr->dw2 = cpu_to_le32(dw2);
+
+       memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+       if (!is_tmf) {
+               buf_cmd[9] = fburst | task->ssp_task.task_attr |
+                               (task->ssp_task.task_prio << 3);
+               memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
+                               task->ssp_task.cmd->cmd_len);
+       } else {
+               buf_cmd[10] = tmf->tmf;
+               switch (tmf->tmf) {
+               case TMF_ABORT_TASK:
+               case TMF_QUERY_TASK:
+                       buf_cmd[12] =
+                               (tmf->tag_of_task_to_be_managed >> 8) & 0xff;
+                       buf_cmd[13] =
+                               tmf->tag_of_task_to_be_managed & 0xff;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/* by default, task resp is complete */
+static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
+                          struct sas_task *task,
+                          struct hisi_sas_slot *slot)
+{
+       struct task_status_struct *ts = &task->task_status;
+       struct hisi_sas_err_record *err_record = slot->status_buffer;
+       struct device *dev = &hisi_hba->pdev->dev;
+
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SSP:
+       {
+               int error = -1;
+               u32 dma_err_type = cpu_to_le32(err_record->dma_err_type);
+               u32 dma_tx_err_type = ((dma_err_type &
+                                       ERR_HDR_DMA_TX_ERR_TYPE_MSK)) >>
+                                       ERR_HDR_DMA_TX_ERR_TYPE_OFF;
+               u32 dma_rx_err_type = ((dma_err_type &
+                                       ERR_HDR_DMA_RX_ERR_TYPE_MSK)) >>
+                                       ERR_HDR_DMA_RX_ERR_TYPE_OFF;
+               u32 trans_tx_fail_type =
+                               cpu_to_le32(err_record->trans_tx_fail_type);
+               u32 trans_rx_fail_type =
+                               cpu_to_le32(err_record->trans_rx_fail_type);
+
+               if (dma_tx_err_type) {
+                       /* dma tx err */
+                       error = ffs(dma_tx_err_type)
+                               - 1 + DMA_TX_ERR_BASE;
+               } else if (dma_rx_err_type) {
+                       /* dma rx err */
+                       error = ffs(dma_rx_err_type)
+                               - 1 + DMA_RX_ERR_BASE;
+               } else if (trans_tx_fail_type) {
+                       /* trans tx err */
+                       error = ffs(trans_tx_fail_type)
+                               - 1 + TRANS_TX_FAIL_BASE;
+               } else if (trans_rx_fail_type) {
+                       /* trans rx err */
+                       error = ffs(trans_rx_fail_type)
+                               - 1 + TRANS_RX_FAIL_BASE;
+               }
+
+               switch (error) {
+               case DMA_TX_DATA_UNDERFLOW_ERR:
+               case DMA_RX_DATA_UNDERFLOW_ERR:
+               {
+                       ts->residual = 0;
+                       ts->stat = SAS_DATA_UNDERRUN;
+                       break;
+               }
+               case DMA_TX_DATA_SGL_OVERFLOW_ERR:
+               case DMA_TX_DIF_SGL_OVERFLOW_ERR:
+               case DMA_TX_XFER_RDY_LENGTH_OVERFLOW_ERR:
+               case DMA_RX_DATA_OVERFLOW_ERR:
+               case TRANS_RX_FRAME_OVERRUN_ERR:
+               case TRANS_RX_LINK_BUF_OVERRUN_ERR:
+               {
+                       ts->stat = SAS_DATA_OVERRUN;
+                       ts->residual = 0;
+                       break;
+               }
+               case TRANS_TX_PHY_NOT_ENABLE_ERR:
+               {
+                       ts->stat = SAS_PHY_DOWN;
+                       break;
+               }
+               case TRANS_TX_OPEN_REJCT_WRONG_DEST_ERR:
+               case TRANS_TX_OPEN_REJCT_ZONE_VIOLATION_ERR:
+               case TRANS_TX_OPEN_REJCT_BY_OTHER_ERR:
+               case TRANS_TX_OPEN_REJCT_AIP_TIMEOUT_ERR:
+               case TRANS_TX_OPEN_REJCT_STP_BUSY_ERR:
+               case TRANS_TX_OPEN_REJCT_PROTOCOL_NOT_SUPPORT_ERR:
+               case TRANS_TX_OPEN_REJCT_RATE_NOT_SUPPORT_ERR:
+               case TRANS_TX_OPEN_REJCT_BAD_DEST_ERR:
+               case TRANS_TX_OPEN_BREAK_RECEIVE_ERR:
+               case TRANS_TX_OPEN_REJCT_PATHWAY_BLOCKED_ERR:
+               case TRANS_TX_OPEN_REJCT_NO_DEST_ERR:
+               case TRANS_TX_OPEN_RETRY_ERR:
+               {
+                       ts->stat = SAS_OPEN_REJECT;
+                       ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+                       break;
+               }
+               case TRANS_TX_OPEN_TIMEOUT_ERR:
+               {
+                       ts->stat = SAS_OPEN_TO;
+                       break;
+               }
+               case TRANS_TX_NAK_RECEIVE_ERR:
+               case TRANS_TX_ACK_NAK_TIMEOUT_ERR:
+               {
+                       ts->stat = SAS_NAK_R_ERR;
+                       break;
+               }
+               default:
+               {
+                       ts->stat = SAM_STAT_CHECK_CONDITION;
+                       break;
+               }
+               }
+       }
+               break;
+       case SAS_PROTOCOL_SMP:
+               ts->stat = SAM_STAT_CHECK_CONDITION;
+               break;
+
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
+       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+       {
+               dev_err(dev, "slot err: SATA/STP not supported");
+       }
+               break;
+       default:
+               break;
+       }
+
+}
+
+static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
+                              struct hisi_sas_slot *slot, int abort)
+{
+       struct sas_task *task = slot->task;
+       struct hisi_sas_device *sas_dev;
+       struct device *dev = &hisi_hba->pdev->dev;
+       struct task_status_struct *ts;
+       struct domain_device *device;
+       enum exec_status sts;
+       struct hisi_sas_complete_v1_hdr *complete_queue =
+                       (struct hisi_sas_complete_v1_hdr *)
+                       hisi_hba->complete_hdr[slot->cmplt_queue];
+       struct hisi_sas_complete_v1_hdr *complete_hdr;
+       u32 cmplt_hdr_data;
+
+       complete_hdr = &complete_queue[slot->cmplt_queue_slot];
+       cmplt_hdr_data = le32_to_cpu(complete_hdr->data);
+
+       if (unlikely(!task || !task->lldd_task || !task->dev))
+               return -EINVAL;
+
+       ts = &task->task_status;
+       device = task->dev;
+       sas_dev = device->lldd_dev;
+
+       task->task_state_flags &=
+               ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+       task->task_state_flags |= SAS_TASK_STATE_DONE;
+
+       memset(ts, 0, sizeof(*ts));
+       ts->resp = SAS_TASK_COMPLETE;
+
+       if (unlikely(!sas_dev || abort)) {
+               if (!sas_dev)
+                       dev_dbg(dev, "slot complete: port has not device\n");
+               ts->stat = SAS_PHY_DOWN;
+               goto out;
+       }
+
+       if (cmplt_hdr_data & CMPLT_HDR_IO_CFG_ERR_MSK) {
+               u32 info_reg = hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO);
+
+               if (info_reg & HGC_INVLD_DQE_INFO_DQ_MSK)
+                       dev_err(dev, "slot complete: [%d:%d] has dq IPTT err",
+                               slot->cmplt_queue, slot->cmplt_queue_slot);
+
+               if (info_reg & HGC_INVLD_DQE_INFO_TYPE_MSK)
+                       dev_err(dev, "slot complete: [%d:%d] has dq type err",
+                               slot->cmplt_queue, slot->cmplt_queue_slot);
+
+               if (info_reg & HGC_INVLD_DQE_INFO_FORCE_MSK)
+                       dev_err(dev, "slot complete: [%d:%d] has dq force phy err",
+                               slot->cmplt_queue, slot->cmplt_queue_slot);
+
+               if (info_reg & HGC_INVLD_DQE_INFO_PHY_MSK)
+                       dev_err(dev, "slot complete: [%d:%d] has dq phy id err",
+                               slot->cmplt_queue, slot->cmplt_queue_slot);
+
+               if (info_reg & HGC_INVLD_DQE_INFO_ABORT_MSK)
+                       dev_err(dev, "slot complete: [%d:%d] has dq abort flag err",
+                               slot->cmplt_queue, slot->cmplt_queue_slot);
+
+               if (info_reg & HGC_INVLD_DQE_INFO_IPTT_OF_MSK)
+                       dev_err(dev, "slot complete: [%d:%d] has dq IPTT or ICT err",
+                               slot->cmplt_queue, slot->cmplt_queue_slot);
+
+               if (info_reg & HGC_INVLD_DQE_INFO_SSP_ERR_MSK)
+                       dev_err(dev, "slot complete: [%d:%d] has dq SSP frame type err",
+                               slot->cmplt_queue, slot->cmplt_queue_slot);
+
+               if (info_reg & HGC_INVLD_DQE_INFO_OFL_MSK)
+                       dev_err(dev, "slot complete: [%d:%d] has dq order frame len err",
+                               slot->cmplt_queue, slot->cmplt_queue_slot);
+
+               ts->stat = SAS_OPEN_REJECT;
+               ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+               goto out;
+       }
+
+       if (cmplt_hdr_data & CMPLT_HDR_ERR_RCRD_XFRD_MSK) {
+               if (!(cmplt_hdr_data & CMPLT_HDR_CMD_CMPLT_MSK) ||
+                   !(cmplt_hdr_data & CMPLT_HDR_RSPNS_XFRD_MSK))
+                       ts->stat = SAS_DATA_OVERRUN;
+               else
+                       slot_err_v1_hw(hisi_hba, task, slot);
+
+               goto out;
+       }
+
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SSP:
+       {
+               struct ssp_response_iu *iu = slot->status_buffer +
+                       sizeof(struct hisi_sas_err_record);
+               sas_ssp_task_response(dev, task, iu);
+               break;
+       }
+       case SAS_PROTOCOL_SMP:
+       {
+               void *to;
+               struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+
+               ts->stat = SAM_STAT_GOOD;
+               to = kmap_atomic(sg_page(sg_resp));
+
+               dma_unmap_sg(dev, &task->smp_task.smp_resp, 1,
+                            DMA_FROM_DEVICE);
+               dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
+                            DMA_TO_DEVICE);
+               memcpy(to + sg_resp->offset,
+                      slot->status_buffer +
+                      sizeof(struct hisi_sas_err_record),
+                      sg_dma_len(sg_resp));
+               kunmap_atomic(to);
+               break;
+       }
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
+       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+               dev_err(dev, "slot complete: SATA/STP not supported");
+               break;
+
+       default:
+               ts->stat = SAM_STAT_CHECK_CONDITION;
+               break;
+       }
+
+       if (!slot->port->port_attached) {
+               dev_err(dev, "slot complete: port %d has removed\n",
+                       slot->port->sas_port.id);
+               ts->stat = SAS_PHY_DOWN;
+       }
+
+out:
+       if (sas_dev && sas_dev->running_req)
+               sas_dev->running_req--;
+
+       hisi_sas_slot_task_free(hisi_hba, task, slot);
+       sts = ts->stat;
+
+       if (task->task_done)
+               task->task_done(task);
+
+       return sts;
+}
+
+/* Interrupts */
+static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
+{
+       struct hisi_sas_phy *phy = p;
+       struct hisi_hba *hisi_hba = phy->hisi_hba;
+       struct device *dev = &hisi_hba->pdev->dev;
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+       int i, phy_no = sas_phy->id;
+       u32 irq_value, context, port_id, link_rate;
+       u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
+       struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
+       irqreturn_t res = IRQ_HANDLED;
+
+       irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
+       if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) {
+               dev_dbg(dev, "phyup: irq_value = %x not set enable bit\n",
+                       irq_value);
+               res = IRQ_NONE;
+               goto end;
+       }
+
+       context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
+       if (context & 1 << phy_no) {
+               dev_err(dev, "phyup: phy%d SATA attached equipment\n",
+                       phy_no);
+               goto end;
+       }
+
+       port_id = (hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA) >> (4 * phy_no))
+                 & 0xf;
+       if (port_id == 0xf) {
+               dev_err(dev, "phyup: phy%d invalid portid\n", phy_no);
+               res = IRQ_NONE;
+               goto end;
+       }
+
+       for (i = 0; i < 6; i++) {
+               u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no,
+                                       RX_IDAF_DWORD0 + (i * 4));
+               frame_rcvd[i] = __swab32(idaf);
+       }
+
+       /* Get the linkrate */
+       link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+       link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+       sas_phy->linkrate = link_rate;
+       sas_phy->oob_mode = SAS_OOB_MODE;
+       memcpy(sas_phy->attached_sas_addr,
+               &id->sas_addr, SAS_ADDR_SIZE);
+       dev_info(dev, "phyup: phy%d link_rate=%d\n",
+                phy_no, link_rate);
+       phy->port_id = port_id;
+       phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+       phy->phy_type |= PORT_TYPE_SAS;
+       phy->phy_attached = 1;
+       phy->identify.device_type = id->dev_type;
+       phy->frame_rcvd_size =  sizeof(struct sas_identify_frame);
+       if (phy->identify.device_type == SAS_END_DEVICE)
+               phy->identify.target_port_protocols =
+                       SAS_PROTOCOL_SSP;
+       else if (phy->identify.device_type != SAS_PHY_UNUSED)
+               phy->identify.target_port_protocols =
+                       SAS_PROTOCOL_SMP;
+       queue_work(hisi_hba->wq, &phy->phyup_ws);
+
+end:
+       hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
+                            CHL_INT2_SL_PHY_ENA_MSK);
+
+       if (irq_value & CHL_INT2_SL_PHY_ENA_MSK) {
+               u32 chl_int0 = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0);
+
+               chl_int0 &= ~CHL_INT0_PHYCTRL_NOTRDY_MSK;
+               hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, chl_int0);
+               hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3ce3ee);
+       }
+
+       return res;
+}
+
+static irqreturn_t int_bcast_v1_hw(int irq, void *p)
+{
+       struct hisi_sas_phy *phy = p;
+       struct hisi_hba *hisi_hba = phy->hisi_hba;
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+       struct sas_ha_struct *sha = &hisi_hba->sha;
+       struct device *dev = &hisi_hba->pdev->dev;
+       int phy_no = sas_phy->id;
+       u32 irq_value;
+       irqreturn_t res = IRQ_HANDLED;
+
+       irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
+
+       if (!(irq_value & CHL_INT2_SL_RX_BC_ACK_MSK)) {
+               dev_err(dev, "bcast: irq_value = %x not set enable bit",
+                       irq_value);
+               res = IRQ_NONE;
+               goto end;
+       }
+
+       sha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+
+end:
+       hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
+                            CHL_INT2_SL_RX_BC_ACK_MSK);
+
+       return res;
+}
+
+static irqreturn_t int_abnormal_v1_hw(int irq, void *p)
+{
+       struct hisi_sas_phy *phy = p;
+       struct hisi_hba *hisi_hba = phy->hisi_hba;
+       struct device *dev = &hisi_hba->pdev->dev;
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+       u32 irq_value, irq_mask_old;
+       int phy_no = sas_phy->id;
+
+       /* mask_int0 */
+       irq_mask_old = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0_MSK);
+       hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3fffff);
+
+       /* read int0 */
+       irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0);
+
+       if (irq_value & CHL_INT0_PHYCTRL_NOTRDY_MSK) {
+               u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+               hisi_sas_phy_down(hisi_hba, phy_no,
+                                 (phy_state & 1 << phy_no) ? 1 : 0);
+       }
+
+       if (irq_value & CHL_INT0_ID_TIMEOUT_MSK)
+               dev_dbg(dev, "abnormal: ID_TIMEOUT phy%d identify timeout\n",
+                       phy_no);
+
+       if (irq_value & CHL_INT0_DWS_LOST_MSK)
+               dev_dbg(dev, "abnormal: DWS_LOST phy%d dws lost\n", phy_no);
+
+       if (irq_value & CHL_INT0_SN_FAIL_NGR_MSK)
+               dev_dbg(dev, "abnormal: SN_FAIL_NGR phy%d sn fail ngr\n",
+                       phy_no);
+
+       if (irq_value & CHL_INT0_SL_IDAF_FAIL_MSK ||
+               irq_value & CHL_INT0_SL_OPAF_FAIL_MSK)
+               dev_dbg(dev, "abnormal: SL_ID/OPAF_FAIL phy%d check adr frm err\n",
+                       phy_no);
+
+       if (irq_value & CHL_INT0_SL_PS_FAIL_OFF)
+               dev_dbg(dev, "abnormal: SL_PS_FAIL phy%d fail\n", phy_no);
+
+       /* write to zero */
+       hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, irq_value);
+
+       if (irq_value & CHL_INT0_PHYCTRL_NOTRDY_MSK)
+               hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK,
+                               0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK);
+       else
+               hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK,
+                               irq_mask_old);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
+{
+       struct hisi_sas_cq *cq = p;
+       struct hisi_hba *hisi_hba = cq->hisi_hba;
+       struct hisi_sas_slot *slot;
+       int queue = cq->id;
+       struct hisi_sas_complete_v1_hdr *complete_queue =
+                       (struct hisi_sas_complete_v1_hdr *)
+                       hisi_hba->complete_hdr[queue];
+       u32 irq_value, rd_point, wr_point;
+
+       irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC);
+
+       hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
+
+       rd_point = hisi_sas_read32(hisi_hba,
+                       COMPL_Q_0_RD_PTR + (0x14 * queue));
+       wr_point = hisi_sas_read32(hisi_hba,
+                       COMPL_Q_0_WR_PTR + (0x14 * queue));
+
+       while (rd_point != wr_point) {
+               struct hisi_sas_complete_v1_hdr *complete_hdr;
+               int idx;
+               u32 cmplt_hdr_data;
+
+               complete_hdr = &complete_queue[rd_point];
+               cmplt_hdr_data = cpu_to_le32(complete_hdr->data);
+               idx = (cmplt_hdr_data & CMPLT_HDR_IPTT_MSK) >>
+                     CMPLT_HDR_IPTT_OFF;
+               slot = &hisi_hba->slot_info[idx];
+
+               /* The completion queue and queue slot index are not
+                * necessarily the same as the delivery queue and
+                * queue slot index.
+                */
+               slot->cmplt_queue_slot = rd_point;
+               slot->cmplt_queue = queue;
+               slot_complete_v1_hw(hisi_hba, slot, 0);
+
+               if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
+                       rd_point = 0;
+       }
+
+       /* update rd_point */
+       hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t fatal_ecc_int_v1_hw(int irq, void *p)
+{
+       struct hisi_hba *hisi_hba = p;
+       struct device *dev = &hisi_hba->pdev->dev;
+       u32 ecc_int = hisi_sas_read32(hisi_hba, SAS_ECC_INTR);
+
+       if (ecc_int & SAS_ECC_INTR_DQ_ECC1B_MSK) {
+               u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+               panic("%s: Fatal DQ 1b ECC interrupt (0x%x)\n",
+                     dev_name(dev), ecc_err);
+       }
+
+       if (ecc_int & SAS_ECC_INTR_DQ_ECCBAD_MSK) {
+               u32 addr = (hisi_sas_read32(hisi_hba, HGC_DQ_ECC_ADDR) &
+                               HGC_DQ_ECC_ADDR_BAD_MSK) >>
+                               HGC_DQ_ECC_ADDR_BAD_OFF;
+
+               panic("%s: Fatal DQ RAM ECC interrupt @ 0x%08x\n",
+                     dev_name(dev), addr);
+       }
+
+       if (ecc_int & SAS_ECC_INTR_IOST_ECC1B_MSK) {
+               u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+               panic("%s: Fatal IOST 1b ECC interrupt (0x%x)\n",
+                     dev_name(dev), ecc_err);
+       }
+
+       if (ecc_int & SAS_ECC_INTR_IOST_ECCBAD_MSK) {
+               u32 addr = (hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR) &
+                               HGC_IOST_ECC_ADDR_BAD_MSK) >>
+                               HGC_IOST_ECC_ADDR_BAD_OFF;
+
+               panic("%s: Fatal IOST RAM ECC interrupt @ 0x%08x\n",
+                     dev_name(dev), addr);
+       }
+
+       if (ecc_int & SAS_ECC_INTR_ITCT_ECCBAD_MSK) {
+               u32 addr = (hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR) &
+                               HGC_ITCT_ECC_ADDR_BAD_MSK) >>
+                               HGC_ITCT_ECC_ADDR_BAD_OFF;
+
+               panic("%s: Fatal TCT RAM ECC interrupt @ 0x%08x\n",
+                     dev_name(dev), addr);
+       }
+
+       if (ecc_int & SAS_ECC_INTR_ITCT_ECC1B_MSK) {
+               u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+               panic("%s: Fatal ITCT 1b ECC interrupt (0x%x)\n",
+                     dev_name(dev), ecc_err);
+       }
+
+       hisi_sas_write32(hisi_hba, SAS_ECC_INTR, ecc_int | 0x3f);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t fatal_axi_int_v1_hw(int irq, void *p)
+{
+       struct hisi_hba *hisi_hba = p;
+       struct device *dev = &hisi_hba->pdev->dev;
+       u32 axi_int = hisi_sas_read32(hisi_hba, ENT_INT_SRC2);
+       u32 axi_info = hisi_sas_read32(hisi_hba, HGC_AXI_FIFO_ERR_INFO);
+
+       if (axi_int & ENT_INT_SRC2_DQ_CFG_ERR_MSK)
+               panic("%s: Fatal DQ_CFG_ERR interrupt (0x%x)\n",
+                     dev_name(dev), axi_info);
+
+       if (axi_int & ENT_INT_SRC2_CQ_CFG_ERR_MSK)
+               panic("%s: Fatal CQ_CFG_ERR interrupt (0x%x)\n",
+                     dev_name(dev), axi_info);
+
+       if (axi_int & ENT_INT_SRC2_AXI_WRONG_INT_MSK)
+               panic("%s: Fatal AXI_WRONG_INT interrupt (0x%x)\n",
+                     dev_name(dev), axi_info);
+
+       if (axi_int & ENT_INT_SRC2_AXI_OVERLF_INT_MSK)
+               panic("%s: Fatal AXI_OVERLF_INT incorrect interrupt (0x%x)\n",
+                     dev_name(dev), axi_info);
+
+       hisi_sas_write32(hisi_hba, ENT_INT_SRC2, axi_int | 0x30000000);
+
+       return IRQ_HANDLED;
+}
+
+static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = {
+       int_bcast_v1_hw,
+       int_phyup_v1_hw,
+       int_abnormal_v1_hw
+};
+
+static irq_handler_t fatal_interrupts[HISI_SAS_MAX_QUEUES] = {
+       fatal_ecc_int_v1_hw,
+       fatal_axi_int_v1_hw
+};
+
+static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+       struct platform_device *pdev = hisi_hba->pdev;
+       struct device *dev = &pdev->dev;
+       int i, j, irq, rc, idx;
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+
+               idx = i * HISI_SAS_PHY_INT_NR;
+               for (j = 0; j < HISI_SAS_PHY_INT_NR; j++, idx++) {
+                       irq = platform_get_irq(pdev, idx);
+                       if (!irq) {
+                               dev_err(dev,
+                                       "irq init: fail map phy interrupt %d\n",
+                                       idx);
+                               return -ENOENT;
+                       }
+
+                       rc = devm_request_irq(dev, irq, phy_interrupts[j], 0,
+                                             DRV_NAME " phy", phy);
+                       if (rc) {
+                               dev_err(dev, "irq init: could not request "
+                                       "phy interrupt %d, rc=%d\n",
+                                       irq, rc);
+                               return -ENOENT;
+                       }
+               }
+       }
+
+       idx = hisi_hba->n_phy * HISI_SAS_PHY_INT_NR;
+       for (i = 0; i < hisi_hba->queue_count; i++, idx++) {
+               irq = platform_get_irq(pdev, idx);
+               if (!irq) {
+                       dev_err(dev, "irq init: could not map cq interrupt %d\n",
+                               idx);
+                       return -ENOENT;
+               }
+
+               rc = devm_request_irq(dev, irq, cq_interrupt_v1_hw, 0,
+                                     DRV_NAME " cq", &hisi_hba->cq[i]);
+               if (rc) {
+                       dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
+                               irq, rc);
+                       return -ENOENT;
+               }
+       }
+
+       idx = (hisi_hba->n_phy * HISI_SAS_PHY_INT_NR) + hisi_hba->queue_count;
+       for (i = 0; i < HISI_SAS_FATAL_INT_NR; i++, idx++) {
+               irq = platform_get_irq(pdev, idx);
+               if (!irq) {
+                       dev_err(dev, "irq init: could not map fatal interrupt %d\n",
+                               idx);
+                       return -ENOENT;
+               }
+
+               rc = devm_request_irq(dev, irq, fatal_interrupts[i], 0,
+                                     DRV_NAME " fatal", hisi_hba);
+               if (rc) {
+                       dev_err(dev,
+                               "irq init: could not request fatal interrupt %d, rc=%d\n",
+                               irq, rc);
+                       return -ENOENT;
+               }
+       }
+
+       return 0;
+}
+
+static int interrupt_openall_v1_hw(struct hisi_hba *hisi_hba)
+{
+       int i;
+       u32 val;
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               /* Clear interrupt status */
+               val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT0);
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, val);
+               val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT1);
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, val);
+               val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT2);
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, val);
+
+               /* Unmask interrupt */
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK, 0x3ce3ee);
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0x17fff);
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8000012a);
+
+               /* bypass chip bug mask abnormal intr */
+               hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK,
+                               0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK);
+       }
+
+       return 0;
+}
+
+static int hisi_sas_v1_init(struct hisi_hba *hisi_hba)
+{
+       int rc;
+
+       rc = hw_init_v1_hw(hisi_hba);
+       if (rc)
+               return rc;
+
+       rc = interrupt_init_v1_hw(hisi_hba);
+       if (rc)
+               return rc;
+
+       rc = interrupt_openall_v1_hw(hisi_hba);
+       if (rc)
+               return rc;
+
+       phys_init_v1_hw(hisi_hba);
+
+       return 0;
+}
+
+static const struct hisi_sas_hw hisi_sas_v1_hw = {
+       .hw_init = hisi_sas_v1_init,
+       .setup_itct = setup_itct_v1_hw,
+       .sl_notify = sl_notify_v1_hw,
+       .free_device = free_device_v1_hw,
+       .prep_smp = prep_smp_v1_hw,
+       .prep_ssp = prep_ssp_v1_hw,
+       .get_free_slot = get_free_slot_v1_hw,
+       .start_delivery = start_delivery_v1_hw,
+       .slot_complete = slot_complete_v1_hw,
+       .phy_enable = enable_phy_v1_hw,
+       .phy_disable = disable_phy_v1_hw,
+       .phy_hard_reset = phy_hard_reset_v1_hw,
+       .get_wideport_bitmap = get_wideport_bitmap_v1_hw,
+       .complete_hdr_size = sizeof(struct hisi_sas_complete_v1_hdr),
+};
+
+static int hisi_sas_v1_probe(struct platform_device *pdev)
+{
+       return hisi_sas_probe(pdev, &hisi_sas_v1_hw);
+}
+
+static int hisi_sas_v1_remove(struct platform_device *pdev)
+{
+       return hisi_sas_remove(pdev);
+}
+
+static const struct of_device_id sas_v1_of_match[] = {
+       { .compatible = "hisilicon,hip05-sas-v1",},
+       {},
+};
+MODULE_DEVICE_TABLE(of, sas_v1_of_match);
+
+static struct platform_driver hisi_sas_v1_driver = {
+       .probe = hisi_sas_v1_probe,
+       .remove = hisi_sas_v1_remove,
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = sas_v1_of_match,
+       },
+};
+
+module_platform_driver(hisi_sas_v1_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller v1 hw driver");
+MODULE_ALIAS("platform:" DRV_NAME);
index a3860367b568aa06adf4290bf84717458c241e77..38ce0e308fbefee00de3a7ff607cd4ffdcdea83b 100644 (file)
@@ -750,7 +750,6 @@ static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
 }
 
 #define MAX_PATHS 8
-
 static ssize_t path_info_show(struct device *dev,
             struct device_attribute *attr, char *buf)
 {
@@ -792,10 +791,8 @@ static ssize_t path_info_show(struct device *dev,
                                hdev->bus, hdev->target, hdev->lun,
                                scsi_device_type(hdev->devtype));
 
-               if (hdev->external ||
-                       hdev->devtype == TYPE_RAID ||
-                       is_logical_device(hdev)) {
-                       output_len += snprintf(buf + output_len,
+               if (hdev->devtype == TYPE_RAID || is_logical_device(hdev)) {
+                       output_len += scnprintf(buf + output_len,
                                                PAGE_SIZE - output_len,
                                                "%s\n", active);
                        continue;
@@ -808,29 +805,28 @@ static ssize_t path_info_show(struct device *dev,
                        phys_connector[0] = '0';
                if (phys_connector[1] < '0')
                        phys_connector[1] = '0';
-               if (hdev->phys_connector[i] > 0)
-                       output_len += snprintf(buf + output_len,
+               output_len += scnprintf(buf + output_len,
                                PAGE_SIZE - output_len,
                                "PORT: %.2s ",
                                phys_connector);
                if (hdev->devtype == TYPE_DISK && hdev->expose_device) {
                        if (box == 0 || box == 0xFF) {
-                               output_len += snprintf(buf + output_len,
+                               output_len += scnprintf(buf + output_len,
                                        PAGE_SIZE - output_len,
                                        "BAY: %hhu %s\n",
                                        bay, active);
                        } else {
-                               output_len += snprintf(buf + output_len,
+                               output_len += scnprintf(buf + output_len,
                                        PAGE_SIZE - output_len,
                                        "BOX: %hhu BAY: %hhu %s\n",
                                        box, bay, active);
                        }
                } else if (box != 0 && box != 0xFF) {
-                       output_len += snprintf(buf + output_len,
+                       output_len += scnprintf(buf + output_len,
                                PAGE_SIZE - output_len, "BOX: %hhu %s\n",
                                box, active);
                } else
-                       output_len += snprintf(buf + output_len,
+                       output_len += scnprintf(buf + output_len,
                                PAGE_SIZE - output_len, "%s\n", active);
        }
 
@@ -3191,6 +3187,87 @@ out:
        return rc;
 }
 
+/*
+ * get enclosure information
+ * struct ReportExtendedLUNdata *rlep - Used for BMIC drive number
+ * struct hpsa_scsi_dev_t *encl_dev - device entry for enclosure
+ * Uses id_physical_device to determine the box_index.
+ */
+static void hpsa_get_enclosure_info(struct ctlr_info *h,
+                       unsigned char *scsi3addr,
+                       struct ReportExtendedLUNdata *rlep, int rle_index,
+                       struct hpsa_scsi_dev_t *encl_dev)
+{
+       int rc = -1;
+       struct CommandList *c = NULL;
+       struct ErrorInfo *ei = NULL;
+       struct bmic_sense_storage_box_params *bssbp = NULL;
+       struct bmic_identify_physical_device *id_phys = NULL;
+       struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
+       u16 bmic_device_index = 0;
+
+       bmic_device_index = GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]);
+
+       if (bmic_device_index == 0xFF00)
+               goto out;
+
+       bssbp = kzalloc(sizeof(*bssbp), GFP_KERNEL);
+       if (!bssbp)
+               goto out;
+
+       id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+       if (!id_phys)
+               goto out;
+
+       rc = hpsa_bmic_id_physical_device(h, scsi3addr, bmic_device_index,
+                                               id_phys, sizeof(*id_phys));
+       if (rc) {
+               dev_warn(&h->pdev->dev, "%s: id_phys failed %d bdi[0x%x]\n",
+                       __func__, encl_dev->external, bmic_device_index);
+               goto out;
+       }
+
+       c = cmd_alloc(h);
+
+       rc = fill_cmd(c, BMIC_SENSE_STORAGE_BOX_PARAMS, h, bssbp,
+                       sizeof(*bssbp), 0, RAID_CTLR_LUNID, TYPE_CMD);
+
+       if (rc)
+               goto out;
+
+       if (id_phys->phys_connector[1] == 'E')
+               c->Request.CDB[5] = id_phys->box_index;
+       else
+               c->Request.CDB[5] = 0;
+
+       rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE,
+                                               NO_TIMEOUT);
+       if (rc)
+               goto out;
+
+       ei = c->err_info;
+       if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+               rc = -1;
+               goto out;
+       }
+
+       encl_dev->box[id_phys->active_path_number] = bssbp->phys_box_on_port;
+       memcpy(&encl_dev->phys_connector[id_phys->active_path_number],
+               bssbp->phys_connector, sizeof(bssbp->phys_connector));
+
+       rc = IO_OK;
+out:
+       kfree(bssbp);
+       kfree(id_phys);
+
+       if (c)
+               cmd_free(h, c);
+
+       if (rc != IO_OK)
+               hpsa_show_dev_msg(KERN_INFO, h, encl_dev,
+                       "Error, could not get enclosure information\n");
+}
+
 static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h,
                                                unsigned char *scsi3addr)
 {
@@ -4032,7 +4109,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
 
                /* skip masked non-disk devices */
                if (MASKED_DEVICE(lunaddrbytes) && physical_device &&
-                       (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
+                  (physdev_list->LUN[phys_dev_index].device_type != 0x06) &&
+                  (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
                        continue;
 
                /* Get device type, vendor, model, device id */
@@ -4116,7 +4194,12 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
                        break;
                case TYPE_TAPE:
                case TYPE_MEDIUM_CHANGER:
+                       ncurrent++;
+                       break;
                case TYPE_ENCLOSURE:
+                       hpsa_get_enclosure_info(h, lunaddrbytes,
+                                               physdev_list, phys_dev_index,
+                                               this_device);
                        ncurrent++;
                        break;
                case TYPE_RAID:
@@ -6629,6 +6712,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
                        c->Request.CDB[7] = (size >> 16) & 0xFF;
                        c->Request.CDB[8] = (size >> 8) & 0XFF;
                        break;
+               case BMIC_SENSE_STORAGE_BOX_PARAMS:
+                       c->Request.CDBLen = 10;
+                       c->Request.type_attr_dir =
+                               TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+                       c->Request.Timeout = 0;
+                       c->Request.CDB[0] = BMIC_READ;
+                       c->Request.CDB[6] = BMIC_SENSE_STORAGE_BOX_PARAMS;
+                       c->Request.CDB[7] = (size >> 16) & 0xFF;
+                       c->Request.CDB[8] = (size >> 8) & 0XFF;
+                       break;
                case BMIC_IDENTIFY_CONTROLLER:
                        c->Request.CDBLen = 10;
                        c->Request.type_attr_dir =
index ae5beda1bdb517849652a68a900c241057ab3ce2..fdd39fc0b199f9a4eb6374c0031bdbf3c567c4f1 100644 (file)
@@ -400,7 +400,7 @@ struct offline_device_entry {
 #define HPSA_PHYSICAL_DEVICE_BUS       0
 #define HPSA_RAID_VOLUME_BUS           1
 #define HPSA_EXTERNAL_RAID_VOLUME_BUS  2
-#define HPSA_HBA_BUS                   3
+#define HPSA_HBA_BUS                   0
 
 /*
        Send the command to the hardware
index d92ef0d352b55fa6d8d1fb0f9ef6e7c50b5ec3db..6a919ada96b3090f516b99838b1b71a16f8641f1 100644 (file)
@@ -291,6 +291,7 @@ struct SenseSubsystem_info {
 #define BMIC_SENSE_DIAG_OPTIONS 0xF5
 #define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x40000000
 #define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66
+#define BMIC_SENSE_STORAGE_BOX_PARAMS 0x65
 
 /* Command List Structure */
 union SCSI3Addr {
@@ -842,5 +843,17 @@ struct bmic_sense_subsystem_info {
        u8      pad[332];
 };
 
+struct bmic_sense_storage_box_params {
+       u8      reserved[36];
+       u8      inquiry_valid;
+       u8      reserved_1[68];
+       u8      phys_box_on_port;
+       u8      reserved_2[22];
+       u16     connection_info;
+       u8      reserver_3[84];
+       u8      phys_connector[2];
+       u8      reserved_4[296];
+};
+
 #pragma pack()
 #endif /* HPSA_CMD_H */
index 6a926bae76b265cea23e1f5386cfc32fecdb6fef..7a91cf3ff17326bd4973735bee79c82e15bd50ee 100644 (file)
 #define i91u_MAXQUEUE          2
 #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
 
-#define I950_DEVICE_ID 0x9500  /* Initio's inic-950 product ID   */
-#define I940_DEVICE_ID 0x9400  /* Initio's inic-940 product ID   */
-#define I935_DEVICE_ID 0x9401  /* Initio's inic-935 product ID   */
-#define I920_DEVICE_ID 0x0002  /* Initio's other product ID      */
-
 #ifdef DEBUG_i91u
 static unsigned int i91u_debug = DEBUG_DEFAULT;
 #endif
@@ -127,17 +122,6 @@ static int setup_debug = 0;
 
 static void i91uSCBPost(u8 * pHcb, u8 * pScb);
 
-/* PCI Devices supported by this driver */
-static struct pci_device_id i91u_pci_devices[] = {
-       { PCI_VENDOR_ID_INIT,  I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_INIT,  I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_INIT,  I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_INIT,  I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { }
-};
-MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
-
 #define DEBUG_INTERRUPT 0
 #define DEBUG_QUEUE     0
 #define DEBUG_STATE     0
index ceee9a3fd9e52e2d99d3eed2a930082789364e27..90a3ca5a4dbd6d835b110c85330684ee54b41c34 100644 (file)
@@ -386,7 +386,6 @@ struct lpfc_vport {
        uint32_t work_port_events; /* Timeout to be handled  */
 #define WORKER_DISC_TMO                0x1     /* vport: Discovery timeout */
 #define WORKER_ELS_TMO                 0x2     /* vport: ELS timeout */
-#define WORKER_FDMI_TMO                0x4     /* vport: FDMI timeout */
 #define WORKER_DELAYED_DISC_TMO        0x8     /* vport: delayed discovery */
 
 #define WORKER_MBOX_TMO                0x100   /* hba: MBOX timeout */
@@ -396,7 +395,6 @@ struct lpfc_vport {
 #define WORKER_RAMP_UP_QUEUE           0x1000  /* hba: Increase Q depth */
 #define WORKER_SERVICE_TXQ             0x2000  /* hba: IOCBs on the txq */
 
-       struct timer_list fc_fdmitmo;
        struct timer_list els_tmofunc;
        struct timer_list delayed_disc_tmo;
 
@@ -405,6 +403,7 @@ struct lpfc_vport {
        uint8_t load_flag;
 #define FC_LOADING             0x1     /* HBA in process of loading drvr */
 #define FC_UNLOADING           0x2     /* HBA in process of unloading drvr */
+#define FC_ALLOW_FDMI          0x4     /* port is ready for FDMI requests */
        /* Vport Config Parameters */
        uint32_t cfg_scan_down;
        uint32_t cfg_lun_queue_depth;
@@ -414,10 +413,6 @@ struct lpfc_vport {
        uint32_t cfg_peer_port_login;
        uint32_t cfg_fcp_class;
        uint32_t cfg_use_adisc;
-       uint32_t cfg_fdmi_on;
-#define LPFC_FDMI_SUPPORT      1       /* bit 0 - FDMI supported? */
-#define LPFC_FDMI_REG_DELAY    2       /* bit 1 - 60 sec registration delay */
-#define LPFC_FDMI_ALL_ATTRIB   4       /* bit 2 - register ALL attributes? */
        uint32_t cfg_discovery_threads;
        uint32_t cfg_log_verbose;
        uint32_t cfg_max_luns;
@@ -443,6 +438,10 @@ struct lpfc_vport {
        unsigned long rcv_buffer_time_stamp;
        uint32_t vport_flag;
 #define STATIC_VPORT   1
+
+       uint16_t fdmi_num_disc;
+       uint32_t fdmi_hba_mask;
+       uint32_t fdmi_port_mask;
 };
 
 struct hbq_s {
@@ -755,6 +754,11 @@ struct lpfc_hba {
 #define LPFC_DELAY_INIT_LINK              1    /* layered driver hold off */
 #define LPFC_DELAY_INIT_LINK_INDEFINITELY 2    /* wait, manual intervention */
        uint32_t cfg_enable_dss;
+       uint32_t cfg_fdmi_on;
+#define LPFC_FDMI_NO_SUPPORT   0       /* FDMI not supported */
+#define LPFC_FDMI_SUPPORT      1       /* FDMI supported? */
+#define LPFC_FDMI_SMART_SAN    2       /* SmartSAN supported */
+       uint32_t cfg_enable_SmartSAN;
        lpfc_vpd_t vpd;         /* vital product data */
 
        struct pci_dev *pcidev;
index f6446d759d7f9f6fd7dfa1dfb5323e2f5cf825bd..343ae9482891c95cd21c676745db2737c0c094b1 100644 (file)
@@ -4572,19 +4572,27 @@ LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1,
             255, "Identifies TYPE for additional ring configuration");
 
 /*
-# lpfc_fdmi_on: controls FDMI support.
-#               Set                NOT Set
-#       bit 0 = FDMI support       no FDMI support
-#           LPFC_FDMI_SUPPORT just turns basic support on/off
-#       bit 1 = Register delay     no register delay  (60 seconds)
-#           LPFC_FDMI_REG_DELAY        60 sec registration delay after FDMI login
-#       bit 2 = All attributes     Use a attribute subset
-#           LPFC_FDMI_ALL_ATTRIB applies to both port and HBA attributes
-#           Port attrutes subset: 1 thru 6 OR all: 1 thru 0xd 0x101 0x102 0x103
-#           HBA attributes subset: 1 thru 0xb OR all: 1 thru 0xc
-# Value range [0,7]. Default value is 0.
+# lpfc_enable_SmartSAN: Sets up FDMI support for SmartSAN
+#       0  = SmartSAN functionality disabled (default)
+#       1  = SmartSAN functionality enabled
+# This parameter will override the value of lpfc_fdmi_on module parameter.
+# Value range is [0,1]. Default value is 0.
 */
-LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 7, "Enable FDMI support");
+LPFC_ATTR_R(enable_SmartSAN, 0, 0, 1, "Enable SmartSAN functionality");
+
+/*
+# lpfc_fdmi_on: Controls FDMI support.
+#       0       No FDMI support (default)
+#       1       Traditional FDMI support
+#       2       Smart SAN support
+# If lpfc_enable_SmartSAN is set 1, the driver sets lpfc_fdmi_on to value 2
+# overwriting the current value.  If lpfc_enable_SmartSAN is set 0, the
+# driver uses the current value of lpfc_fdmi_on provided it has value 0 or 1.
+# A value of 2 with lpfc_enable_SmartSAN set to 0 causes the driver to
+# set lpfc_fdmi_on back to 1.
+# Value range [0,2]. Default value is 0.
+*/
+LPFC_ATTR_R(fdmi_on, 0, 0, 2, "Enable FDMI support");
 
 /*
 # Specifies the maximum number of ELS cmds we can have outstanding (for
@@ -4815,6 +4823,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_multi_ring_rctl,
        &dev_attr_lpfc_multi_ring_type,
        &dev_attr_lpfc_fdmi_on,
+       &dev_attr_lpfc_enable_SmartSAN,
        &dev_attr_lpfc_max_luns,
        &dev_attr_lpfc_enable_npiv,
        &dev_attr_lpfc_fcf_failover_policy,
@@ -4887,7 +4896,6 @@ struct device_attribute *lpfc_vport_attrs[] = {
        &dev_attr_lpfc_fcp_class,
        &dev_attr_lpfc_use_adisc,
        &dev_attr_lpfc_first_burst_size,
-       &dev_attr_lpfc_fdmi_on,
        &dev_attr_lpfc_max_luns,
        &dev_attr_nport_evt_cnt,
        &dev_attr_npiv_info,
@@ -5247,7 +5255,7 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
 
        spin_lock_irq(shost->host_lock);
 
-       if (lpfc_is_link_up(phba)) {
+       if ((lpfc_is_link_up(phba)) && (!(phba->hba_flag & HBA_FCOE_MODE))) {
                switch(phba->fc_linkspeed) {
                case LPFC_LINK_SPEED_1GHZ:
                        fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
@@ -5826,6 +5834,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
        lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
        lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
+       lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
+       lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
        lpfc_use_msi_init(phba, lpfc_use_msi);
        lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
        lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
@@ -5846,6 +5856,15 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
                phba->cfg_poll = 0;
        else
                phba->cfg_poll = lpfc_poll;
+
+       /* Ensure fdmi_on and enable_SmartSAN don't conflict */
+       if (phba->cfg_enable_SmartSAN) {
+               phba->cfg_fdmi_on = LPFC_FDMI_SMART_SAN;
+       } else {
+               if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+                       phba->cfg_fdmi_on = LPFC_FDMI_SUPPORT;
+       }
+
        phba->cfg_soft_wwnn = 0L;
        phba->cfg_soft_wwpn = 0L;
        lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
@@ -5879,7 +5898,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
        lpfc_use_adisc_init(vport, lpfc_use_adisc);
        lpfc_first_burst_size_init(vport, lpfc_first_burst_size);
        lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
-       lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
        lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
        lpfc_max_luns_init(vport, lpfc_max_luns);
        lpfc_scan_down_init(vport, lpfc_scan_down);
index b0e6fe46448d000f13efc41bdeffd509ee8395de..4e55b35180a4c641b65e23b008e7392051230d58 100644 (file)
@@ -72,6 +72,7 @@ void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
 void lpfc_retry_pport_discovery(struct lpfc_hba *);
 void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
 
+void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -167,9 +168,8 @@ void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
                         struct lpfc_iocbq *);
 int lpfc_ct_handle_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *);
 int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
-int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
-void lpfc_fdmi_tmo(unsigned long);
-void lpfc_fdmi_timeout_handler(struct lpfc_vport *);
+int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, uint32_t);
+void lpfc_fdmi_num_disc_check(struct lpfc_vport *);
 void lpfc_delayed_disc_tmo(unsigned long);
 void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
 
index 8fded1f7605f74a09aeda7fd23d7afb88e200207..79e261d2a0c879bcd7627f6416d103a75a1876e1 100644 (file)
 #include "lpfc_vport.h"
 #include "lpfc_debugfs.h"
 
-/* FDMI Port Speed definitions */
-#define HBA_PORTSPEED_1GBIT            0x0001  /* 1 GBit/sec */
-#define HBA_PORTSPEED_2GBIT            0x0002  /* 2 GBit/sec */
-#define HBA_PORTSPEED_4GBIT            0x0008  /* 4 GBit/sec */
-#define HBA_PORTSPEED_10GBIT           0x0004  /* 10 GBit/sec */
-#define HBA_PORTSPEED_8GBIT            0x0010  /* 8 GBit/sec */
-#define HBA_PORTSPEED_16GBIT           0x0020  /* 16 GBit/sec */
-#define HBA_PORTSPEED_32GBIT           0x0040  /* 32 GBit/sec */
-#define HBA_PORTSPEED_UNKNOWN          0x0800  /* Unknown */
+/* FDMI Port Speed definitions - FC-GS-7 */
+#define HBA_PORTSPEED_1GFC             0x00000001      /* 1G FC */
+#define HBA_PORTSPEED_2GFC             0x00000002      /* 2G FC */
+#define HBA_PORTSPEED_4GFC             0x00000008      /* 4G FC */
+#define HBA_PORTSPEED_10GFC            0x00000004      /* 10G FC */
+#define HBA_PORTSPEED_8GFC             0x00000010      /* 8G FC */
+#define HBA_PORTSPEED_16GFC            0x00000020      /* 16G FC */
+#define HBA_PORTSPEED_32GFC            0x00000040      /* 32G FC */
+#define HBA_PORTSPEED_20GFC            0x00000080      /* 20G FC */
+#define HBA_PORTSPEED_40GFC            0x00000100      /* 40G FC */
+#define HBA_PORTSPEED_128GFC           0x00000200      /* 128G FC */
+#define HBA_PORTSPEED_64GFC            0x00000400      /* 64G FC */
+#define HBA_PORTSPEED_256GFC           0x00000800      /* 256G FC */
+#define HBA_PORTSPEED_UNKNOWN          0x00008000      /* Unknown */
+#define HBA_PORTSPEED_10GE             0x00010000      /* 10G E */
+#define HBA_PORTSPEED_40GE             0x00020000      /* 40G E */
+#define HBA_PORTSPEED_100GE            0x00040000      /* 100G E */
+#define HBA_PORTSPEED_25GE             0x00080000      /* 25G E */
+#define HBA_PORTSPEED_50GE             0x00100000      /* 50G E */
+#define HBA_PORTSPEED_400GE            0x00200000      /* 400G E */
 
 #define FOURBYTES      4
 
@@ -287,6 +298,17 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
        return 0;
 }
 
+/**
+ * lpfc_gen_req - Build and issue a GEN_REQUEST command  to the SLI Layer
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @bmp: Pointer to BPL for SLI command
+ * @inp: Pointer to data buffer for response data.
+ * @outp: Pointer to data buffer that hold the CT command.
+ * @cmpl: completion routine to call when command completes
+ * @ndlp: Destination NPort nodelist entry
+ *
+ * This function as the final part for issuing a CT command.
+ */
 static int
 lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
             struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
@@ -311,7 +333,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
        icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
        icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
        icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
-       icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64));
+       icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
 
        if (usr_flg)
                geniocb->context3 = NULL;
@@ -370,6 +392,16 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
        return 0;
 }
 
+/**
+ * lpfc_ct_cmd - Build and issue a CT command
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @inmp: Pointer to data buffer for response data.
+ * @bmp: Pointer to BPL for SLI command
+ * @ndlp: Destination NPort nodelist entry
+ * @cmpl: completion routine to call when command completes
+ *
+ * This function is called for issuing a CT command.
+ */
 static int
 lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
            struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
@@ -453,7 +485,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                        Cnt -= 16;      /* subtract length of CT header */
 
                /* Loop through entire NameServer list of DIDs */
-               while (Cnt >= sizeof (uint32_t)) {
+               while (Cnt >= sizeof(uint32_t)) {
                        /* Get next DID from NameServer List */
                        CTentry = *ctptr++;
                        Did = ((be32_to_cpu(CTentry)) & Mask_DID);
@@ -558,7 +590,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                        }
                        if (CTentry & (cpu_to_be32(SLI_CT_LAST_ENTRY)))
                                goto nsout1;
-                       Cnt -= sizeof (uint32_t);
+                       Cnt -= sizeof(uint32_t);
                }
                ctptr = NULL;
 
@@ -1146,7 +1178,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 
        /* fill in BDEs for command */
        /* Allocate buffer for command payload */
-       mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+       mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
        if (!mp) {
                rc=2;
                goto ns_cmd_exit;
@@ -1160,7 +1192,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
        }
 
        /* Allocate buffer for Buffer ptr list */
-       bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+       bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
        if (!bmp) {
                rc=4;
                goto ns_cmd_free_mpvirt;
@@ -1204,7 +1236,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
        bpl->tus.w = le32_to_cpu(bpl->tus.w);
 
        CtReq = (struct lpfc_sli_ct_request *) mp->virt;
-       memset(CtReq, 0, sizeof (struct lpfc_sli_ct_request));
+       memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
        CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
        CtReq->RevisionId.bits.InId = 0;
        CtReq->FsType = SLI_CT_DIRECTORY_SERVICE;
@@ -1244,7 +1276,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
                    cpu_to_be16(SLI_CTNS_RNN_ID);
                CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
                memcpy(CtReq->un.rnn.wwnn,  &vport->fc_nodename,
-                      sizeof (struct lpfc_name));
+                      sizeof(struct lpfc_name));
                cmpl = lpfc_cmpl_ct_cmd_rnn_id;
                break;
 
@@ -1264,7 +1296,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
                CtReq->CommandResponse.bits.CmdRsp =
                    cpu_to_be16(SLI_CTNS_RSNN_NN);
                memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
-                      sizeof (struct lpfc_name));
+                      sizeof(struct lpfc_name));
                size = sizeof(CtReq->un.rsnn.symbname);
                CtReq->un.rsnn.len =
                        lpfc_vport_symbolic_node_name(vport,
@@ -1319,20 +1351,29 @@ ns_cmd_exit:
        return 1;
 }
 
+/**
+ * lpfc_cmpl_ct_disc_fdmi - Handle a discovery FDMI completion
+ * @phba: Pointer to HBA context object.
+ * @cmdiocb: Pointer to the command IOCBQ.
+ * @rspiocb: Pointer to the response IOCBQ.
+ *
+ * This function to handle the completion of a driver initiated FDMI
+ * CT command issued during discovery.
+ */
 static void
-lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-                     struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                      struct lpfc_iocbq *rspiocb)
 {
+       struct lpfc_vport *vport = cmdiocb->vport;
        struct lpfc_dmabuf *inp = cmdiocb->context1;
        struct lpfc_dmabuf *outp = cmdiocb->context2;
-       struct lpfc_sli_ct_request *CTrsp = outp->virt;
        struct lpfc_sli_ct_request *CTcmd = inp->virt;
-       struct lpfc_nodelist *ndlp;
+       struct lpfc_sli_ct_request *CTrsp = outp->virt;
        uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
        uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
-       struct lpfc_vport *vport = cmdiocb->vport;
        IOCB_t *irsp = &rspiocb->iocb;
-       uint32_t latt;
+       struct lpfc_nodelist *ndlp;
+       uint32_t latt, cmd, err;
 
        latt = lpfc_els_chk_latt(vport);
        lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
@@ -1340,91 +1381,1115 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                irsp->ulpStatus, irsp->un.ulpWord[4], latt);
 
        if (latt || irsp->ulpStatus) {
+
+               /* Look for a retryable error */
+               if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+                       switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) {
+                       case IOERR_SLI_ABORTED:
+                       case IOERR_ABORT_IN_PROGRESS:
+                       case IOERR_SEQUENCE_TIMEOUT:
+                       case IOERR_ILLEGAL_FRAME:
+                       case IOERR_NO_RESOURCES:
+                       case IOERR_ILLEGAL_COMMAND:
+                               cmdiocb->retry++;
+                               if (cmdiocb->retry >= LPFC_FDMI_MAX_RETRY)
+                                       break;
+
+                               /* Retry the same FDMI command */
+                               err = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING,
+                                                         cmdiocb, 0);
+                               if (err == IOCB_ERROR)
+                                       break;
+                               return;
+                       default:
+                               break;
+                       }
+               }
+
                lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
                                 "0229 FDMI cmd %04x failed, latt = %d "
                                 "ulpStatus: x%x, rid x%x\n",
                                 be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
                                 irsp->un.ulpWord[4]);
-               goto fail_out;
        }
+       lpfc_ct_free_iocb(phba, cmdiocb);
 
        ndlp = lpfc_findnode_did(vport, FDMI_DID);
        if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
-               goto fail_out;
+               return;
 
+       /* Check for a CT LS_RJT response */
+       cmd =  be16_to_cpu(fdmi_cmd);
        if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) {
                /* FDMI rsp failed */
                lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
-                                "0220 FDMI rsp failed Data: x%x\n",
-                                be16_to_cpu(fdmi_cmd));
+                                "0220 FDMI cmd failed FS_RJT Data: x%x", cmd);
+
+               /* Should we fallback to FDMI-2 / FDMI-1 ? */
+               switch (cmd) {
+               case SLI_MGMT_RHBA:
+                       if (vport->fdmi_hba_mask == LPFC_FDMI2_HBA_ATTR) {
+                               /* Fallback to FDMI-1 */
+                               vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+                               vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+                               /* Start over */
+                               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+                       }
+                       return;
+
+               case SLI_MGMT_RPRT:
+                       if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+                               /* Fallback to FDMI-1 */
+                               vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+                               /* Start over */
+                               lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+                       }
+                       if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+                               vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+                               /* Retry the same command */
+                               lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+                       }
+                       return;
+
+               case SLI_MGMT_RPA:
+                       if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+                               /* Fallback to FDMI-1 */
+                               vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+                               vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+                               /* Start over */
+                               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+                       }
+                       if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+                               vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+                               /* Retry the same command */
+                               lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+                       }
+                       return;
+               }
        }
 
-fail_out:
-       lpfc_ct_free_iocb(phba, cmdiocb);
+       /*
+        * On success, need to cycle thru FDMI registration for discovery
+        * DHBA -> DPRT -> RHBA -> RPA  (physical port)
+        * DPRT -> RPRT (vports)
+        */
+       switch (cmd) {
+       case SLI_MGMT_RHBA:
+               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, 0);
+               break;
+
+       case SLI_MGMT_DHBA:
+               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+               break;
+
+       case SLI_MGMT_DPRT:
+               if (vport->port_type == LPFC_PHYSICAL_PORT)
+                       lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA, 0);
+               else
+                       lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+               break;
+       }
+       return;
 }
 
-static void
-lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-                      struct lpfc_iocbq *rspiocb)
+
+/**
+ * lpfc_fdmi_num_disc_check - Check how many mapped NPorts we are connected to
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * Called from hbeat timeout routine to check if the number of discovered
+ * ports has changed. If so, re-register thar port Attribute.
+ */
+void
+lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
 {
-       struct lpfc_vport *vport = cmdiocb->vport;
-       struct lpfc_dmabuf *inp = cmdiocb->context1;
-       struct lpfc_sli_ct_request *CTcmd = inp->virt;
-       uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
+       struct lpfc_hba *phba = vport->phba;
        struct lpfc_nodelist *ndlp;
+       uint16_t cnt;
+
+       if (!lpfc_is_link_up(phba))
+               return;
+
+       if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
+               return;
 
-       lpfc_cmpl_ct_cmd_fdmi(phba, cmdiocb, rspiocb);
+       cnt = lpfc_find_map_node(vport);
+       if (cnt == vport->fdmi_num_disc)
+               return;
 
        ndlp = lpfc_findnode_did(vport, FDMI_DID);
        if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
                return;
 
-       /*
-        * Need to cycle thru FDMI registration for discovery
-        * DHBA -> DPRT -> RHBA -> RPA
-        */
-       switch (be16_to_cpu(fdmi_cmd)) {
-       case SLI_MGMT_RHBA:
-               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA);
-               break;
+       if (vport->port_type == LPFC_PHYSICAL_PORT) {
+               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
+                             LPFC_FDMI_PORT_ATTR_num_disc);
+       } else {
+               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT,
+                             LPFC_FDMI_PORT_ATTR_num_disc);
+       }
+}
 
-       case SLI_MGMT_DHBA:
-               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT);
-               break;
+/* Routines for all individual HBA attributes */
+int
+lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
 
-       case SLI_MGMT_DPRT:
-               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
-               break;
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, sizeof(struct lpfc_name));
+
+       memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+              sizeof(struct lpfc_name));
+       size = FOURBYTES + sizeof(struct lpfc_name);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_NODENAME);
+       return size;
+}
+int
+lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport,
+                               struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       strncpy(ae->un.AttrString,
+               "Emulex Corporation",
+                      sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       strncpy(ae->un.AttrString, phba->SerialNumber,
+               sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport,
+                        struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       strncpy(ae->un.AttrString, phba->ModelName,
+               sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_MODEL);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport,
+                              struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       strncpy(ae->un.AttrString, phba->ModelDesc,
+               sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString,
+                                 sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport,
+                          struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba *phba = vport->phba;
+       lpfc_vpd_t *vp = &phba->vpd;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t i, j, incr, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       /* Convert JEDEC ID to ascii for hardware version */
+       incr = vp->rev.biuRev;
+       for (i = 0; i < 8; i++) {
+               j = (incr & 0xf);
+               if (j <= 9)
+                       ae->un.AttrString[7 - i] =
+                           (char)((uint8_t) 0x30 +
+                                  (uint8_t) j);
+               else
+                       ae->un.AttrString[7 - i] =
+                           (char)((uint8_t) 0x61 +
+                                  (uint8_t) (j - 10));
+               incr = (incr >> 4);
        }
+       size = FOURBYTES + 8;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport,
+                           struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       strncpy(ae->un.AttrString, lpfc_release_version,
+               sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport,
+                          struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+       else
+               strncpy(ae->un.AttrString, phba->OptionROMVersion,
+                       sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport,
+                          struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+       len = strnlen(ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport,
+                         struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s %s %s",
+                init_utsname()->sysname,
+                init_utsname()->release,
+                init_utsname()->version);
+
+       len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport,
+                         struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+       ae->un.AttrInt =  cpu_to_be32(LPFC_MAX_CT_SIZE);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport,
+                                struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       len = lpfc_vport_symbolic_node_name(vport,
+                               ae->un.AttrString, 256);
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport,
+                              struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+       /* Nothing is defined for this currently */
+       ae->un.AttrInt =  cpu_to_be32(0);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_VENDOR_INFO);
+       return size;
 }
 
+int
+lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport,
+                            struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+       /* Each driver instance corresponds to a single port */
+       ae->un.AttrInt =  cpu_to_be32(1);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_NUM_PORTS);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport,
+                              struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, sizeof(struct lpfc_name));
+
+       memcpy(&ae->un.AttrWWN, &vport->fabric_nodename,
+              sizeof(struct lpfc_name));
+       size = FOURBYTES + sizeof(struct lpfc_name);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_FABRIC_WWNN);
+       return size;
+}
 
 int
-lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
+lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport,
+                           struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+       len = strnlen(ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_BIOS_VERSION);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport,
+                             struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+       /* Driver doesn't have access to this information */
+       ae->un.AttrInt =  cpu_to_be32(0);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_BIOS_STATE);
+       return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport,
+                            struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       strncpy(ae->un.AttrString, "EMULEX",
+               sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RHBA_VENDOR_ID);
+       return size;
+}
+
+/* Routines for all individual PORT attributes */
+int
+lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
+                           struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 32);
+
+       ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+       ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+       ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+       size = FOURBYTES + 32;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
+                                 struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba   *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+       ae->un.AttrInt = 0;
+       if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+               if (phba->lmt & LMT_32Gb)
+                       ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
+               if (phba->lmt & LMT_16Gb)
+                       ae->un.AttrInt |= HBA_PORTSPEED_16GFC;
+               if (phba->lmt & LMT_10Gb)
+                       ae->un.AttrInt |= HBA_PORTSPEED_10GFC;
+               if (phba->lmt & LMT_8Gb)
+                       ae->un.AttrInt |= HBA_PORTSPEED_8GFC;
+               if (phba->lmt & LMT_4Gb)
+                       ae->un.AttrInt |= HBA_PORTSPEED_4GFC;
+               if (phba->lmt & LMT_2Gb)
+                       ae->un.AttrInt |= HBA_PORTSPEED_2GFC;
+               if (phba->lmt & LMT_1Gb)
+                       ae->un.AttrInt |= HBA_PORTSPEED_1GFC;
+       } else {
+               /* FCoE links support only one speed */
+               switch (phba->fc_linkspeed) {
+               case LPFC_ASYNC_LINK_SPEED_10GBPS:
+                       ae->un.AttrInt = HBA_PORTSPEED_10GE;
+                       break;
+               case LPFC_ASYNC_LINK_SPEED_25GBPS:
+                       ae->un.AttrInt = HBA_PORTSPEED_25GE;
+                       break;
+               case LPFC_ASYNC_LINK_SPEED_40GBPS:
+                       ae->un.AttrInt = HBA_PORTSPEED_40GE;
+                       break;
+               case LPFC_ASYNC_LINK_SPEED_100GBPS:
+                       ae->un.AttrInt = HBA_PORTSPEED_100GE;
+                       break;
+               }
+       }
+       ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
+                         struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba   *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+       if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+               switch (phba->fc_linkspeed) {
+               case LPFC_LINK_SPEED_1GHZ:
+                       ae->un.AttrInt = HBA_PORTSPEED_1GFC;
+                       break;
+               case LPFC_LINK_SPEED_2GHZ:
+                       ae->un.AttrInt = HBA_PORTSPEED_2GFC;
+                       break;
+               case LPFC_LINK_SPEED_4GHZ:
+                       ae->un.AttrInt = HBA_PORTSPEED_4GFC;
+                       break;
+               case LPFC_LINK_SPEED_8GHZ:
+                       ae->un.AttrInt = HBA_PORTSPEED_8GFC;
+                       break;
+               case LPFC_LINK_SPEED_10GHZ:
+                       ae->un.AttrInt = HBA_PORTSPEED_10GFC;
+                       break;
+               case LPFC_LINK_SPEED_16GHZ:
+                       ae->un.AttrInt = HBA_PORTSPEED_16GFC;
+                       break;
+               case LPFC_LINK_SPEED_32GHZ:
+                       ae->un.AttrInt = HBA_PORTSPEED_32GFC;
+                       break;
+               default:
+                       ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+                       break;
+               }
+       } else {
+               switch (phba->fc_linkspeed) {
+               case LPFC_ASYNC_LINK_SPEED_10GBPS:
+                       ae->un.AttrInt = HBA_PORTSPEED_10GE;
+                       break;
+               case LPFC_ASYNC_LINK_SPEED_25GBPS:
+                       ae->un.AttrInt = HBA_PORTSPEED_25GE;
+                       break;
+               case LPFC_ASYNC_LINK_SPEED_40GBPS:
+                       ae->un.AttrInt = HBA_PORTSPEED_40GE;
+                       break;
+               case LPFC_ASYNC_LINK_SPEED_100GBPS:
+                       ae->un.AttrInt = HBA_PORTSPEED_100GE;
+                       break;
+               default:
+                       ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+                       break;
+               }
+       }
+
+       ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport,
+                             struct lpfc_fdmi_attr_def *ad)
+{
+       struct serv_parm *hsp;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+       hsp = (struct serv_parm *)&vport->fc_sparam;
+       ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb) << 8) |
+                         (uint32_t) hsp->cmn.bbRcvSizeLsb;
+       ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport,
+                              struct lpfc_fdmi_attr_def *ad)
+{
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       snprintf(ae->un.AttrString, sizeof(ae->un.AttrString),
+                "/sys/class/scsi_host/host%d", shost->host_no);
+       len = strnlen((char *)ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
+                             struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
+                init_utsname()->nodename);
+
+       len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport,
+                        struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0,  sizeof(struct lpfc_name));
+
+       memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+              sizeof(struct lpfc_name));
+       size = FOURBYTES + sizeof(struct lpfc_name);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_NODENAME);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport,
+                        struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0,  sizeof(struct lpfc_name));
+
+       memcpy(&ae->un.AttrWWN, &vport->fc_sparam.portName,
+              sizeof(struct lpfc_name));
+       size = FOURBYTES + sizeof(struct lpfc_name);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport,
+                                 struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       len = lpfc_vport_symbolic_port_name(vport, ae->un.AttrString, 256);
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport,
+                             struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       if (phba->fc_topology == LPFC_TOPOLOGY_LOOP)
+               ae->un.AttrInt =  cpu_to_be32(LPFC_FDMI_PORTTYPE_NLPORT);
+       else
+               ae->un.AttrInt =  cpu_to_be32(LPFC_FDMI_PORTTYPE_NPORT);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_class(struct lpfc_vport *vport,
+                         struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       ae->un.AttrInt = cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport,
+                               struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0,  sizeof(struct lpfc_name));
+
+       memcpy(&ae->un.AttrWWN, &vport->fabric_portname,
+              sizeof(struct lpfc_name));
+       size = FOURBYTES + sizeof(struct lpfc_name);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
+                                  struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 32);
+
+       ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+       ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+       ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+       size = FOURBYTES + 32;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport,
+                              struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       /* Link Up - operational */
+       ae->un.AttrInt =  cpu_to_be32(LPFC_FDMI_PORTSTATE_ONLINE);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport,
+                            struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       vport->fdmi_num_disc = lpfc_find_map_node(vport);
+       ae->un.AttrInt = cpu_to_be32(vport->fdmi_num_disc);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
+       return size;
+}
+
+int
+lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport,
+                           struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       ae->un.AttrInt =  cpu_to_be32(vport->fc_myDID);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
+       return size;
+}
+
+int
+lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport,
+                            struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       strncpy(ae->un.AttrString, "Smart SAN Initiator",
+               sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SMART_SERVICE);
+       return size;
+}
+
+int
+lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport,
+                         struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       memcpy(&ae->un.AttrString, &vport->fc_sparam.nodeName,
+              sizeof(struct lpfc_name));
+       memcpy((((uint8_t *)&ae->un.AttrString) +
+               sizeof(struct lpfc_name)),
+               &vport->fc_sparam.portName, sizeof(struct lpfc_name));
+       size = FOURBYTES + (2 * sizeof(struct lpfc_name));
+       ad->AttrLen =  cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SMART_GUID);
+       return size;
+}
+
+int
+lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport,
+                            struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       strncpy(ae->un.AttrString, "Smart SAN Version 1.0",
+               sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString,
+                         sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen =  cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SMART_VERSION);
+       return size;
+}
+
+int
+lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport,
+                          struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t len, size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       memset(ae, 0, 256);
+
+       strncpy(ae->un.AttrString, phba->ModelName,
+               sizeof(ae->un.AttrString));
+       len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+       len += (len & 3) ? (4 - (len & 3)) : 4;
+       size = FOURBYTES + len;
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SMART_MODEL);
+       return size;
+}
+
+int
+lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport,
+                              struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+       /* SRIOV (type 3) is not supported */
+       if (vport->vpi)
+               ae->un.AttrInt =  cpu_to_be32(2);  /* NPIV */
+       else
+               ae->un.AttrInt =  cpu_to_be32(1);  /* Physical */
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SMART_PORT_INFO);
+       return size;
+}
+
+int
+lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport,
+                        struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       ae->un.AttrInt =  cpu_to_be32(0);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SMART_QOS);
+       return size;
+}
+
+int
+lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport,
+                             struct lpfc_fdmi_attr_def *ad)
+{
+       struct lpfc_fdmi_attr_entry *ae;
+       uint32_t size;
+
+       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+       ae->un.AttrInt =  cpu_to_be32(0);
+       size = FOURBYTES + sizeof(uint32_t);
+       ad->AttrLen = cpu_to_be16(size);
+       ad->AttrType = cpu_to_be16(RPRT_SMART_SECURITY);
+       return size;
+}
+
+/* RHBA attribute jump table */
+int (*lpfc_fdmi_hba_action[])
+       (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+       /* Action routine                 Mask bit     Attribute type */
+       lpfc_fdmi_hba_attr_wwnn,          /* bit0     RHBA_NODENAME           */
+       lpfc_fdmi_hba_attr_manufacturer,  /* bit1     RHBA_MANUFACTURER       */
+       lpfc_fdmi_hba_attr_sn,            /* bit2     RHBA_SERIAL_NUMBER      */
+       lpfc_fdmi_hba_attr_model,         /* bit3     RHBA_MODEL              */
+       lpfc_fdmi_hba_attr_description,   /* bit4     RHBA_MODEL_DESCRIPTION  */
+       lpfc_fdmi_hba_attr_hdw_ver,       /* bit5     RHBA_HARDWARE_VERSION   */
+       lpfc_fdmi_hba_attr_drvr_ver,      /* bit6     RHBA_DRIVER_VERSION     */
+       lpfc_fdmi_hba_attr_rom_ver,       /* bit7     RHBA_OPTION_ROM_VERSION */
+       lpfc_fdmi_hba_attr_fmw_ver,       /* bit8     RHBA_FIRMWARE_VERSION   */
+       lpfc_fdmi_hba_attr_os_ver,        /* bit9     RHBA_OS_NAME_VERSION    */
+       lpfc_fdmi_hba_attr_ct_len,        /* bit10    RHBA_MAX_CT_PAYLOAD_LEN */
+       lpfc_fdmi_hba_attr_symbolic_name, /* bit11    RHBA_SYM_NODENAME       */
+       lpfc_fdmi_hba_attr_vendor_info,   /* bit12    RHBA_VENDOR_INFO        */
+       lpfc_fdmi_hba_attr_num_ports,     /* bit13    RHBA_NUM_PORTS          */
+       lpfc_fdmi_hba_attr_fabric_wwnn,   /* bit14    RHBA_FABRIC_WWNN        */
+       lpfc_fdmi_hba_attr_bios_ver,      /* bit15    RHBA_BIOS_VERSION       */
+       lpfc_fdmi_hba_attr_bios_state,    /* bit16    RHBA_BIOS_STATE         */
+       lpfc_fdmi_hba_attr_vendor_id,     /* bit17    RHBA_VENDOR_ID          */
+};
+
+/* RPA / RPRT attribute jump table */
+int (*lpfc_fdmi_port_action[])
+       (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+       /* Action routine                   Mask bit   Attribute type */
+       lpfc_fdmi_port_attr_fc4type,        /* bit0   RPRT_SUPPORT_FC4_TYPES  */
+       lpfc_fdmi_port_attr_support_speed,  /* bit1   RPRT_SUPPORTED_SPEED    */
+       lpfc_fdmi_port_attr_speed,          /* bit2   RPRT_PORT_SPEED         */
+       lpfc_fdmi_port_attr_max_frame,      /* bit3   RPRT_MAX_FRAME_SIZE     */
+       lpfc_fdmi_port_attr_os_devname,     /* bit4   RPRT_OS_DEVICE_NAME     */
+       lpfc_fdmi_port_attr_host_name,      /* bit5   RPRT_HOST_NAME          */
+       lpfc_fdmi_port_attr_wwnn,           /* bit6   RPRT_NODENAME           */
+       lpfc_fdmi_port_attr_wwpn,           /* bit7   RPRT_PORTNAME           */
+       lpfc_fdmi_port_attr_symbolic_name,  /* bit8   RPRT_SYM_PORTNAME       */
+       lpfc_fdmi_port_attr_port_type,      /* bit9   RPRT_PORT_TYPE          */
+       lpfc_fdmi_port_attr_class,          /* bit10  RPRT_SUPPORTED_CLASS    */
+       lpfc_fdmi_port_attr_fabric_wwpn,    /* bit11  RPRT_FABRICNAME         */
+       lpfc_fdmi_port_attr_active_fc4type, /* bit12  RPRT_ACTIVE_FC4_TYPES   */
+       lpfc_fdmi_port_attr_port_state,     /* bit13  RPRT_PORT_STATE         */
+       lpfc_fdmi_port_attr_num_disc,       /* bit14  RPRT_DISC_PORT          */
+       lpfc_fdmi_port_attr_nportid,        /* bit15  RPRT_PORT_ID            */
+       lpfc_fdmi_smart_attr_service,       /* bit16  RPRT_SMART_SERVICE      */
+       lpfc_fdmi_smart_attr_guid,          /* bit17  RPRT_SMART_GUID         */
+       lpfc_fdmi_smart_attr_version,       /* bit18  RPRT_SMART_VERSION      */
+       lpfc_fdmi_smart_attr_model,         /* bit19  RPRT_SMART_MODEL        */
+       lpfc_fdmi_smart_attr_port_info,     /* bit20  RPRT_SMART_PORT_INFO    */
+       lpfc_fdmi_smart_attr_qos,           /* bit21  RPRT_SMART_QOS          */
+       lpfc_fdmi_smart_attr_security,      /* bit22  RPRT_SMART_SECURITY     */
+};
+
+/**
+ * lpfc_fdmi_cmd - Build and send a FDMI cmd to the specified NPort
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID)
+ * cmdcode: FDMI command to send
+ * mask: Mask of HBA or PORT Attributes to send
+ *
+ * Builds and sends a FDMI command using the CT subsystem.
+ */
+int
+lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+             int cmdcode, uint32_t new_mask)
 {
        struct lpfc_hba *phba = vport->phba;
        struct lpfc_dmabuf *mp, *bmp;
        struct lpfc_sli_ct_request *CtReq;
        struct ulp_bde64 *bpl;
+       uint32_t bit_pos;
        uint32_t size;
        uint32_t rsp_size;
+       uint32_t mask;
        struct lpfc_fdmi_reg_hba *rh;
        struct lpfc_fdmi_port_entry *pe;
        struct lpfc_fdmi_reg_portattr *pab = NULL;
        struct lpfc_fdmi_attr_block *ab = NULL;
-       struct lpfc_fdmi_attr_entry *ae;
-       struct lpfc_fdmi_attr_def *ad;
-       void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
-                     struct lpfc_iocbq *);
+       int  (*func)(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad);
+       void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
+                    struct lpfc_iocbq *);
 
-       if (ndlp == NULL) {
-               ndlp = lpfc_findnode_did(vport, FDMI_DID);
-               if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
-                       return 0;
-               cmpl = lpfc_cmpl_ct_cmd_fdmi; /* cmd interface */
-       } else {
-               cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
-       }
+       if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+               return 0;
+
+       cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
 
        /* fill in BDEs for command */
        /* Allocate buffer for command payload */
@@ -1470,573 +2535,99 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
        switch (cmdcode) {
        case SLI_MGMT_RHAT:
        case SLI_MGMT_RHBA:
-               {
-                       lpfc_vpd_t *vp = &phba->vpd;
-                       uint32_t i, j, incr;
-                       int len = 0;
+               rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
+               /* HBA Identifier */
+               memcpy(&rh->hi.PortName, &phba->pport->fc_sparam.portName,
+                      sizeof(struct lpfc_name));
 
-                       rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
-                       /* HBA Identifier */
-                       memcpy(&rh->hi.PortName, &vport->fc_sparam.portName,
+               if (cmdcode == SLI_MGMT_RHBA) {
+                       /* Registered Port List */
+                       /* One entry (port) per adapter */
+                       rh->rpl.EntryCnt = cpu_to_be32(1);
+                       memcpy(&rh->rpl.pe, &phba->pport->fc_sparam.portName,
                               sizeof(struct lpfc_name));
 
-                       if (cmdcode == SLI_MGMT_RHBA) {
-                               /* Registered Port List */
-                               /* One entry (port) per adapter */
-                               rh->rpl.EntryCnt = cpu_to_be32(1);
-                               memcpy(&rh->rpl.pe, &vport->fc_sparam.portName,
-                                      sizeof(struct lpfc_name));
-
-                               /* point to the HBA attribute block */
-                               size = 2 * sizeof(struct lpfc_name) +
-                                       FOURBYTES;
-                       } else {
-                               size = sizeof(struct lpfc_name);
-                       }
-                       ab = (struct lpfc_fdmi_attr_block *)
-                               ((uint8_t *)rh + size);
-                       ab->EntryCnt = 0;
-                       size += FOURBYTES;
-
-                       /*
-                        * Point to beginning of first HBA attribute entry
-                        */
-                       /* #1 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(struct lpfc_name));
-                       ad->AttrType = cpu_to_be16(RHBA_NODENAME);
-                       ad->AttrLen =  cpu_to_be16(FOURBYTES
-                                               + sizeof(struct lpfc_name));
-                       memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
-                              sizeof(struct lpfc_name));
-                       ab->EntryCnt++;
-                       size += FOURBYTES + sizeof(struct lpfc_name);
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #2 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.Manufacturer));
-                       ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
-                       strncpy(ae->un.Manufacturer, "Emulex Corporation",
-                               sizeof(ae->un.Manufacturer));
-                       len = strnlen(ae->un.Manufacturer,
-                                         sizeof(ae->un.Manufacturer));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #3 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.SerialNumber));
-                       ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
-                       strncpy(ae->un.SerialNumber, phba->SerialNumber,
-                               sizeof(ae->un.SerialNumber));
-                       len = strnlen(ae->un.SerialNumber,
-                                         sizeof(ae->un.SerialNumber));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #4 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.Model));
-                       ad->AttrType = cpu_to_be16(RHBA_MODEL);
-                       strncpy(ae->un.Model, phba->ModelName,
-                               sizeof(ae->un.Model));
-                       len = strnlen(ae->un.Model, sizeof(ae->un.Model));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #5 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.ModelDescription));
-                       ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
-                       strncpy(ae->un.ModelDescription, phba->ModelDesc,
-                               sizeof(ae->un.ModelDescription));
-                       len = strnlen(ae->un.ModelDescription,
-                                         sizeof(ae->un.ModelDescription));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + 8) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #6 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, 8);
-                       ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 8);
-                       /* Convert JEDEC ID to ascii for hardware version */
-                       incr = vp->rev.biuRev;
-                       for (i = 0; i < 8; i++) {
-                               j = (incr & 0xf);
-                               if (j <= 9)
-                                       ae->un.HardwareVersion[7 - i] =
-                                           (char)((uint8_t)0x30 +
-                                                  (uint8_t)j);
-                               else
-                                       ae->un.HardwareVersion[7 - i] =
-                                           (char)((uint8_t)0x61 +
-                                                  (uint8_t)(j - 10));
-                               incr = (incr >> 4);
+                       /* point to the HBA attribute block */
+                       size = 2 * sizeof(struct lpfc_name) +
+                               FOURBYTES;
+               } else {
+                       size = sizeof(struct lpfc_name);
+               }
+               ab = (struct lpfc_fdmi_attr_block *)((uint8_t *)rh + size);
+               ab->EntryCnt = 0;
+               size += FOURBYTES;
+               bit_pos = 0;
+               if (new_mask)
+                       mask = new_mask;
+               else
+                       mask = vport->fdmi_hba_mask;
+
+               /* Mask will dictate what attributes to build in the request */
+               while (mask) {
+                       if (mask & 0x1) {
+                               func = lpfc_fdmi_hba_action[bit_pos];
+                               size += func(vport,
+                                            (struct lpfc_fdmi_attr_def *)
+                                            ((uint8_t *)rh + size));
+                               ab->EntryCnt++;
+                               if ((size + 256) >
+                                   (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+                                       goto hba_out;
                        }
-                       ab->EntryCnt++;
-                       size += FOURBYTES + 8;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #7 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.DriverVersion));
-                       ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
-                       strncpy(ae->un.DriverVersion, lpfc_release_version,
-                               sizeof(ae->un.DriverVersion));
-                       len = strnlen(ae->un.DriverVersion,
-                                       sizeof(ae->un.DriverVersion));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #8 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.OptionROMVersion));
-                       ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
-                       strncpy(ae->un.OptionROMVersion, phba->OptionROMVersion,
-                               sizeof(ae->un.OptionROMVersion));
-                       len = strnlen(ae->un.OptionROMVersion,
-                                     sizeof(ae->un.OptionROMVersion));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #9 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.FirmwareVersion));
-                       ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
-                       lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion,
-                               1);
-                       len = strnlen(ae->un.FirmwareVersion,
-                                       sizeof(ae->un.FirmwareVersion));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #10 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.OsNameVersion));
-                       ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
-                       snprintf(ae->un.OsNameVersion,
-                                sizeof(ae->un.OsNameVersion),
-                                "%s %s %s",
-                                init_utsname()->sysname,
-                                init_utsname()->release,
-                                init_utsname()->version);
-                       len = strnlen(ae->un.OsNameVersion,
-                                     sizeof(ae->un.OsNameVersion));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /* #11 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       ad->AttrType =
-                               cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-                       ae->un.MaxCTPayloadLen = cpu_to_be32(LPFC_MAX_CT_SIZE);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + 4;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto hba_out;
-
-                       /*
-                        * Currently switches don't seem to support the
-                        * following extended HBA attributes.
-                        */
-                       if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
-                               goto hba_out;
-
-                       /* #12 HBA attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)rh + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.NodeSymName));
-                       ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
-                       len = lpfc_vport_symbolic_node_name(vport,
-                               ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       ab->EntryCnt++;
-                       size += FOURBYTES + len;
-hba_out:
-                       ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
-                       /* Total size */
-                       size = GID_REQUEST_SZ - 4 + size;
+                       mask = mask >> 1;
+                       bit_pos++;
                }
+hba_out:
+               ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
+               /* Total size */
+               size = GID_REQUEST_SZ - 4 + size;
                break;
 
        case SLI_MGMT_RPRT:
        case SLI_MGMT_RPA:
-               {
-                       struct serv_parm *hsp;
-                       int len = 0;
-
-                       if (cmdcode == SLI_MGMT_RPRT) {
-                               rh = (struct lpfc_fdmi_reg_hba *)
-                                       &CtReq->un.PortID;
-                               /* HBA Identifier */
-                               memcpy(&rh->hi.PortName,
-                                      &vport->fc_sparam.portName,
-                                      sizeof(struct lpfc_name));
-                               pab = (struct lpfc_fdmi_reg_portattr *)
-                                       &rh->rpl.EntryCnt;
-                       } else
-                               pab = (struct lpfc_fdmi_reg_portattr *)
-                                       &CtReq->un.PortID;
-                       size = sizeof(struct lpfc_name) + FOURBYTES;
-                       memcpy((uint8_t *)&pab->PortName,
-                              (uint8_t *)&vport->fc_sparam.portName,
+               pab = (struct lpfc_fdmi_reg_portattr *)&CtReq->un.PortID;
+               if (cmdcode == SLI_MGMT_RPRT) {
+                       rh = (struct lpfc_fdmi_reg_hba *)pab;
+                       /* HBA Identifier */
+                       memcpy(&rh->hi.PortName,
+                              &phba->pport->fc_sparam.portName,
                               sizeof(struct lpfc_name));
-                       pab->ab.EntryCnt = 0;
-
-                       /* #1 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.FC4Types));
-                       ad->AttrType =
-                               cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
-                       ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
-                       ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
-                       ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 32;
-
-                       /* #2 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-                       ae->un.SupportSpeed = 0;
-                       if (phba->lmt & LMT_32Gb)
-                               ae->un.SupportSpeed |= HBA_PORTSPEED_32GBIT;
-                       if (phba->lmt & LMT_16Gb)
-                               ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT;
-                       if (phba->lmt & LMT_10Gb)
-                               ae->un.SupportSpeed |= HBA_PORTSPEED_10GBIT;
-                       if (phba->lmt & LMT_8Gb)
-                               ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT;
-                       if (phba->lmt & LMT_4Gb)
-                               ae->un.SupportSpeed |= HBA_PORTSPEED_4GBIT;
-                       if (phba->lmt & LMT_2Gb)
-                               ae->un.SupportSpeed |= HBA_PORTSPEED_2GBIT;
-                       if (phba->lmt & LMT_1Gb)
-                               ae->un.SupportSpeed |= HBA_PORTSPEED_1GBIT;
-                       ae->un.SupportSpeed =
-                               cpu_to_be32(ae->un.SupportSpeed);
-
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 4;
-
-                       /* #3 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-                       switch (phba->fc_linkspeed) {
-                       case LPFC_LINK_SPEED_1GHZ:
-                               ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
-                               break;
-                       case LPFC_LINK_SPEED_2GHZ:
-                               ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
-                               break;
-                       case LPFC_LINK_SPEED_4GHZ:
-                               ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
-                               break;
-                       case LPFC_LINK_SPEED_8GHZ:
-                               ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
-                               break;
-                       case LPFC_LINK_SPEED_10GHZ:
-                               ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
-                               break;
-                       case LPFC_LINK_SPEED_16GHZ:
-                               ae->un.PortSpeed = HBA_PORTSPEED_16GBIT;
-                               break;
-                       case LPFC_LINK_SPEED_32GHZ:
-                               ae->un.PortSpeed = HBA_PORTSPEED_32GBIT;
-                               break;
-                       default:
-                               ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN;
-                               break;
-                       }
-                       ae->un.PortSpeed = cpu_to_be32(ae->un.PortSpeed);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 4;
-
-                       /* #4 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-                       hsp = (struct serv_parm *)&vport->fc_sparam;
-                       ae->un.MaxFrameSize =
-                           (((uint32_t)hsp->cmn.
-                             bbRcvSizeMsb) << 8) | (uint32_t)hsp->cmn.
-                           bbRcvSizeLsb;
-                       ae->un.MaxFrameSize =
-                               cpu_to_be32(ae->un.MaxFrameSize);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 4;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #5 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.OsDeviceName));
-                       ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
-                       strncpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME,
-                               sizeof(ae->un.OsDeviceName));
-                       len = strnlen((char *)ae->un.OsDeviceName,
-                                         sizeof(ae->un.OsDeviceName));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #6 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.HostName));
-                       snprintf(ae->un.HostName, sizeof(ae->un.HostName), "%s",
-                                init_utsname()->nodename);
-                       ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
-                       len = strnlen(ae->un.HostName,
-                                       sizeof(ae->un.HostName));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen =
-                               cpu_to_be16(FOURBYTES + len);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + sizeof(struct lpfc_name)) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
+                       pab = (struct lpfc_fdmi_reg_portattr *)
+                               ((uint8_t *)pab +  sizeof(struct lpfc_name));
+               }
 
-                       /*
-                        * Currently switches don't seem to support the
-                        * following extended Port attributes.
-                        */
-                       if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
-                               goto port_out;
-
-                       /* #7 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0,  sizeof(struct lpfc_name));
-                       ad->AttrType = cpu_to_be16(RPRT_NODENAME);
-                       ad->AttrLen =  cpu_to_be16(FOURBYTES
-                                               + sizeof(struct lpfc_name));
-                       memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
-                              sizeof(struct lpfc_name));
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + sizeof(struct lpfc_name);
-                       if ((size + sizeof(struct lpfc_name)) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #8 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0,  sizeof(struct lpfc_name));
-                       ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
-                       ad->AttrLen =  cpu_to_be16(FOURBYTES
-                                               + sizeof(struct lpfc_name));
-                       memcpy(&ae->un.PortName, &vport->fc_sparam.portName,
-                              sizeof(struct lpfc_name));
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + sizeof(struct lpfc_name);
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #9 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.NodeSymName));
-                       ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
-                       len = lpfc_vport_symbolic_port_name(vport,
-                               ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
-                       len += (len & 3) ? (4 - (len & 3)) : 4;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + len);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + len;
-                       if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #10 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
-                       ae->un.PortState = 0;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 4;
-                       if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #11 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
-                       ae->un.SupportClass =
-                               cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 4;
-                       if ((size + sizeof(struct lpfc_name)) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #12 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(struct lpfc_name));
-                       ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
-                       ad->AttrLen =  cpu_to_be16(FOURBYTES
-                                               + sizeof(struct lpfc_name));
-                       memcpy(&ae->un.FabricName, &vport->fabric_nodename,
-                              sizeof(struct lpfc_name));
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + sizeof(struct lpfc_name);
-                       if ((size + LPFC_FDMI_MAX_AE_SIZE) >
-                                       (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #13 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       memset(ae, 0, sizeof(ae->un.FC4Types));
-                       ad->AttrType =
-                               cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
-                       ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
-                       ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
-                       ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 32;
-                       if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #257 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
-                       ae->un.PortState = 0;
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 4;
-                       if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #258 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
-                       ae->un.PortState = lpfc_find_map_node(vport);
-                       ae->un.PortState = cpu_to_be32(ae->un.PortState);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 4;
-                       if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
-                               goto port_out;
-
-                       /* #259 Port attribute entry */
-                       ad = (struct lpfc_fdmi_attr_def *)
-                               ((uint8_t *)pab + size);
-                       ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
-                       ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
-                       ae->un.PortId =  cpu_to_be32(vport->fc_myDID);
-                       ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
-                       pab->ab.EntryCnt++;
-                       size += FOURBYTES + 4;
-port_out:
-                       pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
-                       /* Total size */
-                       size = GID_REQUEST_SZ - 4 + size;
+               memcpy((uint8_t *)&pab->PortName,
+                      (uint8_t *)&vport->fc_sparam.portName,
+                      sizeof(struct lpfc_name));
+               size += sizeof(struct lpfc_name) + FOURBYTES;
+               pab->ab.EntryCnt = 0;
+               bit_pos = 0;
+               if (new_mask)
+                       mask = new_mask;
+               else
+                       mask = vport->fdmi_port_mask;
+
+               /* Mask will dictate what attributes to build in the request */
+               while (mask) {
+                       if (mask & 0x1) {
+                               func = lpfc_fdmi_port_action[bit_pos];
+                               size += func(vport,
+                                            (struct lpfc_fdmi_attr_def *)
+                                            ((uint8_t *)pab + size));
+                               pab->ab.EntryCnt++;
+                               if ((size + 256) >
+                                   (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+                                       goto port_out;
+                       }
+                       mask = mask >> 1;
+                       bit_pos++;
                }
+port_out:
+               pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
+               /* Total size */
+               if (cmdcode == SLI_MGMT_RPRT)
+                       size += sizeof(struct lpfc_name);
+               size = GID_REQUEST_SZ - 4 + size;
                break;
 
        case SLI_MGMT_GHAT:
@@ -2157,41 +2748,6 @@ lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport)
        lpfc_do_scr_ns_plogi(vport->phba, vport);
 }
 
-void
-lpfc_fdmi_tmo(unsigned long ptr)
-{
-       struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
-       struct lpfc_hba   *phba = vport->phba;
-       uint32_t tmo_posted;
-       unsigned long iflag;
-
-       spin_lock_irqsave(&vport->work_port_lock, iflag);
-       tmo_posted = vport->work_port_events & WORKER_FDMI_TMO;
-       if (!tmo_posted)
-               vport->work_port_events |= WORKER_FDMI_TMO;
-       spin_unlock_irqrestore(&vport->work_port_lock, iflag);
-
-       if (!tmo_posted)
-               lpfc_worker_wake_up(phba);
-       return;
-}
-
-void
-lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
-{
-       struct lpfc_nodelist *ndlp;
-
-       ndlp = lpfc_findnode_did(vport, FDMI_DID);
-       if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
-               if (init_utsname()->nodename[0] != '\0')
-                       lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
-               else
-                       mod_timer(&vport->fc_fdmitmo, jiffies +
-                                 msecs_to_jiffies(1000 * 60));
-       }
-       return;
-}
-
 void
 lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
 {
index b6fa257ea3e0ba802e65f57d46c45944318bef7b..7f5abb8f52bc82d1380e9c0dbd12a0ad7fca814a 100644 (file)
@@ -455,9 +455,9 @@ int
 lpfc_issue_reg_vfi(struct lpfc_vport *vport)
 {
        struct lpfc_hba  *phba = vport->phba;
-       LPFC_MBOXQ_t *mboxq;
+       LPFC_MBOXQ_t *mboxq = NULL;
        struct lpfc_nodelist *ndlp;
-       struct lpfc_dmabuf *dmabuf;
+       struct lpfc_dmabuf *dmabuf = NULL;
        int rc = 0;
 
        /* move forward in case of SLI4 FC port loopback test and pt2pt mode */
@@ -471,25 +471,33 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
                }
        }
 
-       dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-       if (!dmabuf) {
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
                rc = -ENOMEM;
                goto fail;
        }
-       dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
-       if (!dmabuf->virt) {
-               rc = -ENOMEM;
-               goto fail_free_dmabuf;
-       }
 
-       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mboxq) {
-               rc = -ENOMEM;
-               goto fail_free_coherent;
+       /* Supply CSP's only if we are fabric connect or pt-to-pt connect */
+       if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) {
+               dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+               if (!dmabuf) {
+                       rc = -ENOMEM;
+                       goto fail;
+               }
+               dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
+               if (!dmabuf->virt) {
+                       rc = -ENOMEM;
+                       goto fail;
+               }
+               memcpy(dmabuf->virt, &phba->fc_fabparam,
+                      sizeof(struct serv_parm));
        }
+
        vport->port_state = LPFC_FABRIC_CFG_LINK;
-       memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
-       lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+       if (dmabuf)
+               lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+       else
+               lpfc_reg_vfi(mboxq, vport, 0);
 
        mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
        mboxq->vport = vport;
@@ -497,17 +505,19 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
        rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
        if (rc == MBX_NOT_FINISHED) {
                rc = -ENXIO;
-               goto fail_free_mbox;
+               goto fail;
        }
        return 0;
 
-fail_free_mbox:
-       mempool_free(mboxq, phba->mbox_mem_pool);
-fail_free_coherent:
-       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-fail_free_dmabuf:
-       kfree(dmabuf);
 fail:
+       if (mboxq)
+               mempool_free(mboxq, phba->mbox_mem_pool);
+       if (dmabuf) {
+               if (dmabuf->virt)
+                       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+               kfree(dmabuf);
+       }
+
        lpfc_vport_set_state(vport, FC_VPORT_FAILED);
        lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
                "0289 Issue Register VFI failed: Err %d\n", rc);
@@ -678,6 +688,21 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                                sp->cmn.bbRcvSizeLsb;
 
        fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
+       if (fabric_param_changed) {
+               /* Reset FDMI attribute masks based on config parameter */
+               if (phba->cfg_fdmi_on == LPFC_FDMI_NO_SUPPORT) {
+                       vport->fdmi_hba_mask = 0;
+                       vport->fdmi_port_mask = 0;
+               } else {
+                       /* Setup appropriate attribute masks */
+                       vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+                       if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+                               vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+                       else
+                               vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+               }
+
+       }
        memcpy(&vport->fabric_portname, &sp->portName,
                        sizeof(struct lpfc_name));
        memcpy(&vport->fabric_nodename, &sp->nodeName,
@@ -711,9 +736,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
         * For FC we need to do some special processing because of the SLI
         * Port's default settings of the Common Service Parameters.
         */
-       if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) {
+       if ((phba->sli_rev == LPFC_SLI_REV4) &&
+           (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)) {
                /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
-               if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed)
+               if (fabric_param_changed)
                        lpfc_unregister_fcf_prep(phba);
 
                /* This should just update the VFI CSPs*/
@@ -824,13 +850,21 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
        spin_lock_irq(shost->host_lock);
        vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+       vport->fc_flag |= FC_PT2PT;
        spin_unlock_irq(shost->host_lock);
 
-       phba->fc_edtov = FF_DEF_EDTOV;
-       phba->fc_ratov = FF_DEF_RATOV;
+       /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
+       if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
+               lpfc_unregister_fcf_prep(phba);
+
+               spin_lock_irq(shost->host_lock);
+               vport->fc_flag &= ~FC_VFI_REGISTERED;
+               spin_unlock_irq(shost->host_lock);
+               phba->fc_topology_changed = 0;
+       }
+
        rc = memcmp(&vport->fc_portname, &sp->portName,
                    sizeof(vport->fc_portname));
-       memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
 
        if (rc >= 0) {
                /* This side will initiate the PLOGI */
@@ -839,38 +873,14 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                spin_unlock_irq(shost->host_lock);
 
                /*
-                * N_Port ID cannot be 0, set our to LocalID the other
-                * side will be RemoteID.
+                * N_Port ID cannot be 0, set our Id to LocalID
+                * the other side will be RemoteID.
                 */
 
                /* not equal */
                if (rc)
                        vport->fc_myDID = PT2PT_LocalID;
 
-               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-               if (!mbox)
-                       goto fail;
-
-               lpfc_config_link(phba, mbox);
-
-               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               mbox->vport = vport;
-               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-               if (rc == MBX_NOT_FINISHED) {
-                       mempool_free(mbox, phba->mbox_mem_pool);
-                       goto fail;
-               }
-
-               /*
-                * For SLI4, the VFI/VPI are registered AFTER the
-                * Nport with the higher WWPN sends the PLOGI with
-                * an assigned NPortId.
-                */
-
-               /* not equal */
-               if ((phba->sli_rev == LPFC_SLI_REV4) && rc)
-                       lpfc_issue_reg_vfi(vport);
-
                /* Decrement ndlp reference count indicating that ndlp can be
                 * safely released when other references to it are done.
                 */
@@ -912,29 +922,20 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        /* If we are pt2pt with another NPort, force NPIV off! */
        phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
 
-       spin_lock_irq(shost->host_lock);
-       vport->fc_flag |= FC_PT2PT;
-       spin_unlock_irq(shost->host_lock);
-       /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
-       if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
-               lpfc_unregister_fcf_prep(phba);
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               goto fail;
 
-               /* The FC_VFI_REGISTERED flag will get clear in the cmpl
-                * handler for unreg_vfi, but if we don't force the
-                * FC_VFI_REGISTERED flag then the reg_vfi mailbox could be
-                * built with the update bit set instead of just the vp bit to
-                * change the Nport ID.  We need to have the vp set and the
-                * Upd cleared on topology changes.
-                */
-               spin_lock_irq(shost->host_lock);
-               vport->fc_flag &= ~FC_VFI_REGISTERED;
-               spin_unlock_irq(shost->host_lock);
-               phba->fc_topology_changed = 0;
-               lpfc_issue_reg_vfi(vport);
+       lpfc_config_link(phba, mbox);
+
+       mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
+       mbox->vport = vport;
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               mempool_free(mbox, phba->mbox_mem_pool);
+               goto fail;
        }
 
-       /* Start discovery - this should just do CLEAR_LA */
-       lpfc_disc_start(vport);
        return 0;
 fail:
        return -ENXIO;
@@ -1157,6 +1158,7 @@ flogifail:
        spin_lock_irq(&phba->hbalock);
        phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
        spin_unlock_irq(&phba->hbalock);
+
        lpfc_nlp_put(ndlp);
 
        if (!lpfc_error_lost_link(irsp)) {
@@ -3792,14 +3794,17 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                lpfc_nlp_set_state(vport, ndlp,
                                           NLP_STE_REG_LOGIN_ISSUE);
                        }
+
+                       ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
                        if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
                            != MBX_NOT_FINISHED)
                                goto out;
-                       else
-                               /* Decrement the ndlp reference count we
-                                * set for this failed mailbox command.
-                                */
-                               lpfc_nlp_put(ndlp);
+
+                       /* Decrement the ndlp reference count we
+                        * set for this failed mailbox command.
+                        */
+                       lpfc_nlp_put(ndlp);
+                       ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
 
                        /* ELS rsp: Cannot issue reg_login for <NPortid> */
                        lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -3856,6 +3861,7 @@ out:
                                 * the routine lpfc_els_free_iocb.
                                 */
                                cmdiocb->context1 = NULL;
+
        }
 
        lpfc_els_free_iocb(phba, cmdiocb);
@@ -3898,6 +3904,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
        IOCB_t *oldcmd;
        struct lpfc_iocbq *elsiocb;
        uint8_t *pcmd;
+       struct serv_parm *sp;
        uint16_t cmdsize;
        int rc;
        ELS_PKT *els_pkt_ptr;
@@ -3927,6 +3934,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                        "Issue ACC:       did:x%x flg:x%x",
                        ndlp->nlp_DID, ndlp->nlp_flag, 0);
                break;
+       case ELS_CMD_FLOGI:
        case ELS_CMD_PLOGI:
                cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
                elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
@@ -3944,10 +3952,34 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
 
                *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
                pcmd += sizeof(uint32_t);
-               memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
+               sp = (struct serv_parm *)pcmd;
+
+               if (flag == ELS_CMD_FLOGI) {
+                       /* Copy the received service parameters back */
+                       memcpy(sp, &phba->fc_fabparam,
+                              sizeof(struct serv_parm));
+
+                       /* Clear the F_Port bit */
+                       sp->cmn.fPort = 0;
+
+                       /* Mark all class service parameters as invalid */
+                       sp->cls1.classValid = 0;
+                       sp->cls2.classValid = 0;
+                       sp->cls3.classValid = 0;
+                       sp->cls4.classValid = 0;
+
+                       /* Copy our worldwide names */
+                       memcpy(&sp->portName, &vport->fc_sparam.portName,
+                              sizeof(struct lpfc_name));
+                       memcpy(&sp->nodeName, &vport->fc_sparam.nodeName,
+                              sizeof(struct lpfc_name));
+               } else {
+                       memcpy(pcmd, &vport->fc_sparam,
+                              sizeof(struct serv_parm));
+               }
 
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
-                       "Issue ACC PLOGI: did:x%x flg:x%x",
+                       "Issue ACC FLOGI/PLOGI: did:x%x flg:x%x",
                        ndlp->nlp_DID, ndlp->nlp_flag, 0);
                break;
        case ELS_CMD_PRLO:
@@ -4673,6 +4705,23 @@ lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc,
        desc->length = cpu_to_be32(sizeof(desc->info));
 }
 
+int
+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)
+               return 0;
+       desc->tag = cpu_to_be32(RDP_FEC_DESC_TAG);
+
+       desc->info.CorrectedBlocks =
+               cpu_to_be32(stat->fecCorrBlkCount);
+       desc->info.UncorrectableBlocks =
+               cpu_to_be32(stat->fecUncorrBlkCount);
+
+       desc->length = cpu_to_be32(sizeof(desc->info));
+
+       return sizeof(struct fc_fec_rdp_desc);
+}
+
 void
 lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
 {
@@ -4681,26 +4730,26 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
 
        desc->tag = cpu_to_be32(RDP_PORT_SPEED_DESC_TAG);
 
-       switch (phba->sli4_hba.link_state.speed) {
-       case LPFC_FC_LA_SPEED_1G:
+       switch (phba->fc_linkspeed) {
+       case LPFC_LINK_SPEED_1GHZ:
                rdp_speed = RDP_PS_1GB;
                break;
-       case LPFC_FC_LA_SPEED_2G:
+       case LPFC_LINK_SPEED_2GHZ:
                rdp_speed = RDP_PS_2GB;
                break;
-       case LPFC_FC_LA_SPEED_4G:
+       case LPFC_LINK_SPEED_4GHZ:
                rdp_speed = RDP_PS_4GB;
                break;
-       case LPFC_FC_LA_SPEED_8G:
+       case LPFC_LINK_SPEED_8GHZ:
                rdp_speed = RDP_PS_8GB;
                break;
-       case LPFC_FC_LA_SPEED_10G:
+       case LPFC_LINK_SPEED_10GHZ:
                rdp_speed = RDP_PS_10GB;
                break;
-       case LPFC_FC_LA_SPEED_16G:
+       case LPFC_LINK_SPEED_16GHZ:
                rdp_speed = RDP_PS_16GB;
                break;
-       case LPFC_FC_LA_SPEED_32G:
+       case LPFC_LINK_SPEED_32GHZ:
                rdp_speed = RDP_PS_32GB;
                break;
        default:
@@ -4778,15 +4827,18 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
        struct lpfc_nodelist *ndlp = rdp_context->ndlp;
        struct lpfc_vport *vport = ndlp->vport;
        struct lpfc_iocbq *elsiocb;
+       struct ulp_bde64 *bpl;
        IOCB_t *icmd;
        uint8_t *pcmd;
        struct ls_rjt *stat;
        struct fc_rdp_res_frame *rdp_res;
        uint32_t cmdsize;
-       int rc;
+       int rc, fec_size;
 
        if (status != SUCCESS)
                goto error;
+
+       /* This will change once we know the true size of the RDP payload */
        cmdsize = sizeof(struct fc_rdp_res_frame);
 
        elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize,
@@ -4823,10 +4875,18 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
        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);
-       rdp_res->length = cpu_to_be32(RDP_DESC_PAYLOAD_SIZE);
-
+       fec_size = lpfc_rdp_res_fec_desc(&rdp_res->fec_desc,
+                       &rdp_context->link_stat);
+       rdp_res->length = cpu_to_be32(fec_size + RDP_DESC_PAYLOAD_SIZE);
        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.bdeFlags = 0;
+       bpl->tus.w = le32_to_cpu(bpl->tus.w);
+
        phba->fc_stat.elsXmitACC++;
        rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
        if (rc == IOCB_ERROR)
@@ -4956,13 +5016,12 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        if (RDP_NPORT_ID_SIZE !=
                        be32_to_cpu(rdp_req->nport_id_desc.length))
                goto rjt_logerr;
-       rdp_context = kmalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
+       rdp_context = kzalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
        if (!rdp_context) {
                rjt_err = LSRJT_UNABLE_TPC;
                goto error;
        }
 
-       memset(rdp_context, 0, sizeof(struct lpfc_rdp_context));
        cmd = &cmdiocb->iocb;
        rdp_context->ndlp = lpfc_nlp_get(ndlp);
        rdp_context->ox_id = cmd->unsli3.rcvsli3.ox_id;
@@ -5739,7 +5798,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        IOCB_t *icmd = &cmdiocb->iocb;
        struct serv_parm *sp;
        LPFC_MBOXQ_t *mbox;
-       struct ls_rjt stat;
        uint32_t cmd, did;
        int rc;
        uint32_t fc_flag = 0;
@@ -5765,135 +5823,92 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                return 1;
        }
 
-       if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
-               /* For a FLOGI we accept, then if our portname is greater
-                * then the remote portname we initiate Nport login.
-                */
+       (void) lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1);
 
-               rc = memcmp(&vport->fc_portname, &sp->portName,
-                           sizeof(struct lpfc_name));
 
-               if (!rc) {
-                       if (phba->sli_rev < LPFC_SLI_REV4) {
-                               mbox = mempool_alloc(phba->mbox_mem_pool,
-                                                    GFP_KERNEL);
-                               if (!mbox)
-                                       return 1;
-                               lpfc_linkdown(phba);
-                               lpfc_init_link(phba, mbox,
-                                              phba->cfg_topology,
-                                              phba->cfg_link_speed);
-                               mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
-                               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-                               mbox->vport = vport;
-                               rc = lpfc_sli_issue_mbox(phba, mbox,
-                                                        MBX_NOWAIT);
-                               lpfc_set_loopback_flag(phba);
-                               if (rc == MBX_NOT_FINISHED)
-                                       mempool_free(mbox, phba->mbox_mem_pool);
-                               return 1;
-                       } else {
-                               /* abort the flogi coming back to ourselves
-                                * due to external loopback on the port.
-                                */
-                               lpfc_els_abort_flogi(phba);
-                               return 0;
-                       }
-               } else if (rc > 0) {    /* greater than */
-                       spin_lock_irq(shost->host_lock);
-                       vport->fc_flag |= FC_PT2PT_PLOGI;
-                       spin_unlock_irq(shost->host_lock);
+       /*
+        * If our portname is greater than the remote portname,
+        * then we initiate Nport login.
+        */
 
-                       /* If we have the high WWPN we can assign our own
-                        * myDID; otherwise, we have to WAIT for a PLOGI
-                        * from the remote NPort to find out what it
-                        * will be.
-                        */
-                       vport->fc_myDID = PT2PT_LocalID;
-               } else
-                       vport->fc_myDID = PT2PT_RemoteID;
+       rc = memcmp(&vport->fc_portname, &sp->portName,
+                   sizeof(struct lpfc_name));
 
-               /*
-                * The vport state should go to LPFC_FLOGI only
-                * AFTER we issue a FLOGI, not receive one.
+       if (!rc) {
+               if (phba->sli_rev < LPFC_SLI_REV4) {
+                       mbox = mempool_alloc(phba->mbox_mem_pool,
+                                            GFP_KERNEL);
+                       if (!mbox)
+                               return 1;
+                       lpfc_linkdown(phba);
+                       lpfc_init_link(phba, mbox,
+                                      phba->cfg_topology,
+                                      phba->cfg_link_speed);
+                       mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
+                       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+                       mbox->vport = vport;
+                       rc = lpfc_sli_issue_mbox(phba, mbox,
+                                                MBX_NOWAIT);
+                       lpfc_set_loopback_flag(phba);
+                       if (rc == MBX_NOT_FINISHED)
+                               mempool_free(mbox, phba->mbox_mem_pool);
+                       return 1;
+               }
+
+               /* abort the flogi coming back to ourselves
+                * due to external loopback on the port.
                 */
+               lpfc_els_abort_flogi(phba);
+               return 0;
+
+       } else if (rc > 0) {    /* greater than */
                spin_lock_irq(shost->host_lock);
-               fc_flag = vport->fc_flag;
-               port_state = vport->port_state;
-               vport->fc_flag |= FC_PT2PT;
-               vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+               vport->fc_flag |= FC_PT2PT_PLOGI;
                spin_unlock_irq(shost->host_lock);
-               lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
-                                "3311 Rcv Flogi PS x%x new PS x%x "
-                                "fc_flag x%x new fc_flag x%x\n",
-                                port_state, vport->port_state,
-                                fc_flag, vport->fc_flag);
 
-               /*
-                * We temporarily set fc_myDID to make it look like we are
-                * a Fabric. This is done just so we end up with the right
-                * did / sid on the FLOGI ACC rsp.
+               /* If we have the high WWPN we can assign our own
+                * myDID; otherwise, we have to WAIT for a PLOGI
+                * from the remote NPort to find out what it
+                * will be.
                 */
-               did = vport->fc_myDID;
-               vport->fc_myDID = Fabric_DID;
-
+               vport->fc_myDID = PT2PT_LocalID;
        } else {
-               /* Reject this request because invalid parameters */
-               stat.un.b.lsRjtRsvd0 = 0;
-               stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
-               stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
-               stat.un.b.vendorUnique = 0;
-
-               /*
-                * We temporarily set fc_myDID to make it look like we are
-                * a Fabric. This is done just so we end up with the right
-                * did / sid on the FLOGI LS_RJT rsp.
-                */
-               did = vport->fc_myDID;
-               vport->fc_myDID = Fabric_DID;
-
-               lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
-                       NULL);
+               vport->fc_myDID = PT2PT_RemoteID;
+       }
 
-               /* Now lets put fc_myDID back to what its supposed to be */
-               vport->fc_myDID = did;
+       /*
+        * The vport state should go to LPFC_FLOGI only
+        * AFTER we issue a FLOGI, not receive one.
+        */
+       spin_lock_irq(shost->host_lock);
+       fc_flag = vport->fc_flag;
+       port_state = vport->port_state;
+       vport->fc_flag |= FC_PT2PT;
+       vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+       spin_unlock_irq(shost->host_lock);
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+                        "3311 Rcv Flogi PS x%x new PS x%x "
+                        "fc_flag x%x new fc_flag x%x\n",
+                        port_state, vport->port_state,
+                        fc_flag, vport->fc_flag);
 
-               return 1;
-       }
+       /*
+        * We temporarily set fc_myDID to make it look like we are
+        * a Fabric. This is done just so we end up with the right
+        * did / sid on the FLOGI ACC rsp.
+        */
+       did = vport->fc_myDID;
+       vport->fc_myDID = Fabric_DID;
 
-       /* send our FLOGI first */
-       if (vport->port_state < LPFC_FLOGI) {
-               vport->fc_myDID = 0;
-               lpfc_initial_flogi(vport);
-               vport->fc_myDID = Fabric_DID;
-       }
+       memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
 
        /* Send back ACC */
-       lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
+       lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, cmdiocb, ndlp, NULL);
 
        /* Now lets put fc_myDID back to what its supposed to be */
        vport->fc_myDID = did;
 
-       if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
-               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-               if (!mbox)
-                       goto fail;
-
-               lpfc_config_link(phba, mbox);
-
-               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               mbox->vport = vport;
-               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-               if (rc == MBX_NOT_FINISHED) {
-                       mempool_free(mbox, phba->mbox_mem_pool);
-                       goto fail;
-               }
-       }
-
        return 0;
-fail:
-       return 1;
 }
 
 /**
@@ -7345,7 +7360,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        /* reject till our FLOGI completes */
        if ((vport->port_state < LPFC_FABRIC_CFG_LINK) &&
-               (cmd != ELS_CMD_FLOGI)) {
+           (cmd != ELS_CMD_FLOGI)) {
                rjt_err = LSRJT_UNABLE_TPC;
                rjt_exp = LSEXP_NOTHING_MORE;
                goto lsrjt;
@@ -7381,6 +7396,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        rjt_exp = LSEXP_NOTHING_MORE;
                        break;
                }
+
                if (vport->port_state < LPFC_DISC_AUTH) {
                        if (!(phba->pport->fc_flag & FC_PT2PT) ||
                                (phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
@@ -7730,6 +7746,35 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        }
 }
 
+void
+lpfc_start_fdmi(struct lpfc_vport *vport)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_nodelist *ndlp;
+
+       /* If this is the first time, allocate an ndlp and initialize
+        * it. Otherwise, make sure the node is enabled and then do the
+        * login.
+        */
+       ndlp = lpfc_findnode_did(vport, FDMI_DID);
+       if (!ndlp) {
+               ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+               if (ndlp) {
+                       lpfc_nlp_init(vport, ndlp, FDMI_DID);
+                       ndlp->nlp_type |= NLP_FABRIC;
+               } else {
+                       return;
+               }
+       }
+       if (!NLP_CHK_NODE_ACT(ndlp))
+               ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE);
+
+       if (ndlp) {
+               lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+               lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+       }
+}
+
 /**
  * lpfc_do_scr_ns_plogi - Issue a plogi to the name server for scr
  * @phba: pointer to lpfc hba data structure.
@@ -7746,7 +7791,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 void
 lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
 {
-       struct lpfc_nodelist *ndlp, *ndlp_fdmi;
+       struct lpfc_nodelist *ndlp;
        struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
        /*
@@ -7804,32 +7849,9 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
                return;
        }
 
-       if (vport->cfg_fdmi_on & LPFC_FDMI_SUPPORT) {
-               /* If this is the first time, allocate an ndlp and initialize
-                * it. Otherwise, make sure the node is enabled and then do the
-                * login.
-                */
-               ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID);
-               if (!ndlp_fdmi) {
-                       ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
-                                                 GFP_KERNEL);
-                       if (ndlp_fdmi) {
-                               lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
-                               ndlp_fdmi->nlp_type |= NLP_FABRIC;
-                       } else
-                               return;
-               }
-               if (!NLP_CHK_NODE_ACT(ndlp_fdmi))
-                       ndlp_fdmi = lpfc_enable_node(vport,
-                                                    ndlp_fdmi,
-                                                    NLP_STE_NPR_NODE);
-
-               if (ndlp_fdmi) {
-                       lpfc_nlp_set_state(vport, ndlp_fdmi,
-                                          NLP_STE_PLOGI_ISSUE);
-                       lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
-               }
-       }
+       if ((phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) &&
+           (vport->load_flag & FC_ALLOW_FDMI))
+               lpfc_start_fdmi(vport);
 }
 
 /**
index bfc2442dd74a5738283b32f78506af70f85bb327..c37d72effbffeb4bbcf56d26dcc5069fe34dddd7 100644 (file)
@@ -674,8 +674,6 @@ lpfc_work_done(struct lpfc_hba *phba)
                                lpfc_mbox_timeout_handler(phba);
                        if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
                                lpfc_unblock_fabric_iocbs(phba);
-                       if (work_port_events & WORKER_FDMI_TMO)
-                               lpfc_fdmi_timeout_handler(vport);
                        if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
                                lpfc_ramp_down_queue_handler(phba);
                        if (work_port_events & WORKER_DELAYED_DISC_TMO)
@@ -1083,7 +1081,7 @@ out:
 }
 
 
-static void
+void
 lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_vport *vport = pmb->vport;
@@ -1113,8 +1111,10 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        /* Start discovery by sending a FLOGI. port_state is identically
         * LPFC_FLOGI while waiting for FLOGI cmpl
         */
-       if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI)
+       if (vport->port_state != LPFC_FLOGI)
                lpfc_initial_flogi(vport);
+       else if (vport->fc_flag & FC_PT2PT)
+               lpfc_disc_start(vport);
        return;
 
 out:
@@ -2963,8 +2963,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 
 out_free_mem:
        mempool_free(mboxq, phba->mbox_mem_pool);
-       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-       kfree(dmabuf);
+       if (dmabuf) {
+               lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+               kfree(dmabuf);
+       }
        return;
 }
 
@@ -3035,19 +3037,22 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
        uint32_t fc_flags = 0;
 
        spin_lock_irq(&phba->hbalock);
-       switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
-       case LPFC_LINK_SPEED_1GHZ:
-       case LPFC_LINK_SPEED_2GHZ:
-       case LPFC_LINK_SPEED_4GHZ:
-       case LPFC_LINK_SPEED_8GHZ:
-       case LPFC_LINK_SPEED_10GHZ:
-       case LPFC_LINK_SPEED_16GHZ:
-       case LPFC_LINK_SPEED_32GHZ:
-               phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
-               break;
-       default:
-               phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
-               break;
+       phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
+
+       if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+               switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
+               case LPFC_LINK_SPEED_1GHZ:
+               case LPFC_LINK_SPEED_2GHZ:
+               case LPFC_LINK_SPEED_4GHZ:
+               case LPFC_LINK_SPEED_8GHZ:
+               case LPFC_LINK_SPEED_10GHZ:
+               case LPFC_LINK_SPEED_16GHZ:
+               case LPFC_LINK_SPEED_32GHZ:
+                       break;
+               default:
+                       phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
+                       break;
+               }
        }
 
        if (phba->fc_topology &&
@@ -3448,10 +3453,10 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                spin_lock_irq(shost->host_lock);
                ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
                spin_unlock_irq(shost->host_lock);
-       } else
-               /* Good status, call state machine */
-               lpfc_disc_state_machine(vport, ndlp, pmb,
-                               NLP_EVT_CMPL_REG_LOGIN);
+       }
+
+       /* Call state machine */
+       lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
 
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
@@ -5550,15 +5555,15 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                         ndlp->nlp_usg_map, ndlp);
        /*
         * Start issuing Fabric-Device Management Interface (FDMI) command to
-        * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if
-        * fdmi-on=2 (supporting RPA/hostnmae)
+        * 0xfffffa (FDMI well known port).
+        * DHBA -> DPRT -> RHBA -> RPA  (physical port)
+        * DPRT -> RPRT (vports)
         */
-
-       if (vport->cfg_fdmi_on & LPFC_FDMI_REG_DELAY)
-               mod_timer(&vport->fc_fdmitmo,
-                         jiffies + msecs_to_jiffies(1000 * 60));
+       if (vport->port_type == LPFC_PHYSICAL_PORT)
+               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
        else
-               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
+               lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+
 
        /* decrement the node reference count held for this callback
         * function.
index 2cce88e967ce168500e4f5bc738451532fb49144..dd20412c7e4c5aea1f33a888055808827609c91e 100644 (file)
@@ -1097,6 +1097,18 @@ struct fc_rdp_port_name_desc {
 };
 
 
+struct fc_rdp_fec_info {
+       uint32_t CorrectedBlocks;
+       uint32_t UncorrectableBlocks;
+};
+
+#define RDP_FEC_DESC_TAG  0x00010005
+struct fc_fec_rdp_desc {
+       uint32_t tag;
+       uint32_t length;
+       struct fc_rdp_fec_info info;
+};
+
 struct fc_rdp_link_error_status_payload_info {
        struct fc_link_status link_status; /* 24 bytes */
        uint32_t  port_type;             /* bits 31-30 only */
@@ -1196,14 +1208,15 @@ 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_fec_rdp_desc fec_desc;              /* FC Word 34 - 37 */
 };
 
 
 #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_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))
 
 
 /******** FDMI ********/
@@ -1233,31 +1246,10 @@ struct lpfc_fdmi_attr_def { /* Defined in TLV format */
 /* Attribute Entry */
 struct lpfc_fdmi_attr_entry {
        union {
-               uint32_t VendorSpecific;
-               uint32_t SupportClass;
-               uint32_t SupportSpeed;
-               uint32_t PortSpeed;
-               uint32_t MaxFrameSize;
-               uint32_t MaxCTPayloadLen;
-               uint32_t PortState;
-               uint32_t PortId;
-               struct lpfc_name NodeName;
-               struct lpfc_name PortName;
-               struct lpfc_name FabricName;
-               uint8_t FC4Types[32];
-               uint8_t Manufacturer[64];
-               uint8_t SerialNumber[64];
-               uint8_t Model[256];
-               uint8_t ModelDescription[256];
-               uint8_t HardwareVersion[256];
-               uint8_t DriverVersion[256];
-               uint8_t OptionROMVersion[256];
-               uint8_t FirmwareVersion[256];
-               uint8_t OsHostName[256];
-               uint8_t NodeSymName[256];
-               uint8_t OsDeviceName[256];
-               uint8_t OsNameVersion[256];
-               uint8_t HostName[256];
+               uint32_t AttrInt;
+               uint8_t  AttrTypes[32];
+               uint8_t  AttrString[256];
+               struct lpfc_name AttrWWN;
        } un;
 };
 
@@ -1327,6 +1319,8 @@ struct lpfc_fdmi_reg_portattr {
 #define  SLI_MGMT_DPRT     0x310       /* De-register Port */
 #define  SLI_MGMT_DPA      0x311       /* De-register Port attributes */
 
+#define LPFC_FDMI_MAX_RETRY     3  /* Max retries for a FDMI command */
+
 /*
  * HBA Attribute Types
  */
@@ -1342,6 +1336,39 @@ struct lpfc_fdmi_reg_portattr {
 #define  RHBA_OS_NAME_VERSION   0xa /* 4 to 256 byte ASCII string */
 #define  RHBA_MAX_CT_PAYLOAD_LEN 0xb /* 32-bit unsigned int */
 #define  RHBA_SYM_NODENAME       0xc /* 4 to 256 byte ASCII string */
+#define  RHBA_VENDOR_INFO        0xd  /* 32-bit unsigned int */
+#define  RHBA_NUM_PORTS          0xe  /* 32-bit unsigned int */
+#define  RHBA_FABRIC_WWNN        0xf  /* 8 byte WWNN */
+#define  RHBA_BIOS_VERSION       0x10 /* 4 to 256 byte ASCII string */
+#define  RHBA_BIOS_STATE         0x11 /* 32-bit unsigned int */
+#define  RHBA_VENDOR_ID          0xe0 /* 8 byte ASCII string */
+
+/* Bit mask for all individual HBA attributes */
+#define LPFC_FDMI_HBA_ATTR_wwnn                        0x00000001
+#define LPFC_FDMI_HBA_ATTR_manufacturer                0x00000002
+#define LPFC_FDMI_HBA_ATTR_sn                  0x00000004
+#define LPFC_FDMI_HBA_ATTR_model               0x00000008
+#define LPFC_FDMI_HBA_ATTR_description         0x00000010
+#define LPFC_FDMI_HBA_ATTR_hdw_ver             0x00000020
+#define LPFC_FDMI_HBA_ATTR_drvr_ver            0x00000040
+#define LPFC_FDMI_HBA_ATTR_rom_ver             0x00000080
+#define LPFC_FDMI_HBA_ATTR_fmw_ver             0x00000100
+#define LPFC_FDMI_HBA_ATTR_os_ver              0x00000200
+#define LPFC_FDMI_HBA_ATTR_ct_len              0x00000400
+#define LPFC_FDMI_HBA_ATTR_symbolic_name       0x00000800
+#define LPFC_FDMI_HBA_ATTR_vendor_info         0x00001000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_num_ports           0x00002000
+#define LPFC_FDMI_HBA_ATTR_fabric_wwnn         0x00004000
+#define LPFC_FDMI_HBA_ATTR_bios_ver            0x00008000
+#define LPFC_FDMI_HBA_ATTR_bios_state          0x00010000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_vendor_id           0x00020000
+
+/* Bit mask for FDMI-1 defined HBA attributes */
+#define LPFC_FDMI1_HBA_ATTR                    0x000007ff
+
+/* Bit mask for FDMI-2 defined HBA attributes */
+/* Skip vendor_info and bios_state */
+#define LPFC_FDMI2_HBA_ATTR                    0x0002efff
 
 /*
  * Port Attrubute Types
@@ -1353,15 +1380,65 @@ struct lpfc_fdmi_reg_portattr {
 #define  RPRT_OS_DEVICE_NAME          0x5 /* 4 to 256 byte ASCII string */
 #define  RPRT_HOST_NAME               0x6 /* 4 to 256 byte ASCII string */
 #define  RPRT_NODENAME                0x7 /* 8 byte WWNN */
-#define  RPRT_PORTNAME                0x8 /* 8 byte WWNN */
+#define  RPRT_PORTNAME                0x8 /* 8 byte WWPN */
 #define  RPRT_SYM_PORTNAME            0x9 /* 4 to 256 byte ASCII string */
 #define  RPRT_PORT_TYPE               0xa /* 32-bit unsigned int */
 #define  RPRT_SUPPORTED_CLASS         0xb /* 32-bit unsigned int */
-#define  RPRT_FABRICNAME              0xc /* 8 byte Fabric WWNN */
+#define  RPRT_FABRICNAME              0xc /* 8 byte Fabric WWPN */
 #define  RPRT_ACTIVE_FC4_TYPES        0xd /* 32 byte binary array */
 #define  RPRT_PORT_STATE              0x101 /* 32-bit unsigned int */
 #define  RPRT_DISC_PORT               0x102 /* 32-bit unsigned int */
 #define  RPRT_PORT_ID                 0x103 /* 32-bit unsigned int */
+#define  RPRT_SMART_SERVICE           0xf100 /* 4 to 256 byte ASCII string */
+#define  RPRT_SMART_GUID              0xf101 /* 8 byte WWNN + 8 byte WWPN */
+#define  RPRT_SMART_VERSION           0xf102 /* 4 to 256 byte ASCII string */
+#define  RPRT_SMART_MODEL             0xf103 /* 4 to 256 byte ASCII string */
+#define  RPRT_SMART_PORT_INFO         0xf104 /* 32-bit unsigned int */
+#define  RPRT_SMART_QOS               0xf105 /* 32-bit unsigned int */
+#define  RPRT_SMART_SECURITY          0xf106 /* 32-bit unsigned int */
+
+/* Bit mask for all individual PORT attributes */
+#define LPFC_FDMI_PORT_ATTR_fc4type            0x00000001
+#define LPFC_FDMI_PORT_ATTR_support_speed      0x00000002
+#define LPFC_FDMI_PORT_ATTR_speed              0x00000004
+#define LPFC_FDMI_PORT_ATTR_max_frame          0x00000008
+#define LPFC_FDMI_PORT_ATTR_os_devname         0x00000010
+#define LPFC_FDMI_PORT_ATTR_host_name          0x00000020
+#define LPFC_FDMI_PORT_ATTR_wwnn               0x00000040
+#define LPFC_FDMI_PORT_ATTR_wwpn               0x00000080
+#define LPFC_FDMI_PORT_ATTR_symbolic_name      0x00000100
+#define LPFC_FDMI_PORT_ATTR_port_type          0x00000200
+#define LPFC_FDMI_PORT_ATTR_class              0x00000400
+#define LPFC_FDMI_PORT_ATTR_fabric_wwpn                0x00000800
+#define LPFC_FDMI_PORT_ATTR_port_state         0x00001000
+#define LPFC_FDMI_PORT_ATTR_active_fc4type     0x00002000
+#define LPFC_FDMI_PORT_ATTR_num_disc           0x00004000
+#define LPFC_FDMI_PORT_ATTR_nportid            0x00008000
+#define LPFC_FDMI_SMART_ATTR_service           0x00010000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_guid              0x00020000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_version           0x00040000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_model             0x00080000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_port_info         0x00100000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_qos               0x00200000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_security          0x00400000 /* Vendor specific */
+
+/* Bit mask for FDMI-1 defined PORT attributes */
+#define LPFC_FDMI1_PORT_ATTR                   0x0000003f
+
+/* Bit mask for FDMI-2 defined PORT attributes */
+#define LPFC_FDMI2_PORT_ATTR                   0x0000ffff
+
+/* Bit mask for Smart SAN defined PORT attributes */
+#define LPFC_FDMI2_SMART_ATTR                  0x007fffff
+
+/* Defines for PORT port state attribute */
+#define LPFC_FDMI_PORTSTATE_UNKNOWN    1
+#define LPFC_FDMI_PORTSTATE_ONLINE     2
+
+/* Defines for PORT port type attribute */
+#define LPFC_FDMI_PORTTYPE_UNKNOWN     0
+#define LPFC_FDMI_PORTTYPE_NPORT       1
+#define LPFC_FDMI_PORTTYPE_NLPORT      2
 
 /*
  *  Begin HBA configuration parameters.
@@ -2498,10 +2575,38 @@ typedef struct {
 /* Structure for MB Command READ_LINK_STAT (18) */
 
 typedef struct {
-       uint32_t rsvd1;
+       uint32_t word0;
+
+#define lpfc_read_link_stat_rec_SHIFT   0
+#define lpfc_read_link_stat_rec_MASK   0x1
+#define lpfc_read_link_stat_rec_WORD   word0
+
+#define lpfc_read_link_stat_gec_SHIFT  1
+#define lpfc_read_link_stat_gec_MASK   0x1
+#define lpfc_read_link_stat_gec_WORD   word0
+
+#define lpfc_read_link_stat_w02oftow23of_SHIFT 2
+#define lpfc_read_link_stat_w02oftow23of_MASK   0x3FFFFF
+#define lpfc_read_link_stat_w02oftow23of_WORD   word0
+
+#define lpfc_read_link_stat_rsvd_SHIFT 24
+#define lpfc_read_link_stat_rsvd_MASK   0x1F
+#define lpfc_read_link_stat_rsvd_WORD   word0
+
+#define lpfc_read_link_stat_gec2_SHIFT  29
+#define lpfc_read_link_stat_gec2_MASK   0x1
+#define lpfc_read_link_stat_gec2_WORD   word0
+
+#define lpfc_read_link_stat_clrc_SHIFT  30
+#define lpfc_read_link_stat_clrc_MASK   0x1
+#define lpfc_read_link_stat_clrc_WORD   word0
+
+#define lpfc_read_link_stat_clof_SHIFT  31
+#define lpfc_read_link_stat_clof_MASK   0x1
+#define lpfc_read_link_stat_clof_WORD   word0
+
        uint32_t linkFailureCnt;
        uint32_t lossSyncCnt;
-
        uint32_t lossSignalCnt;
        uint32_t primSeqErrCnt;
        uint32_t invalidXmitWord;
@@ -2509,6 +2614,19 @@ typedef struct {
        uint32_t primSeqTimeout;
        uint32_t elasticOverrun;
        uint32_t arbTimeout;
+       uint32_t advRecBufCredit;
+       uint32_t curRecBufCredit;
+       uint32_t advTransBufCredit;
+       uint32_t curTransBufCredit;
+       uint32_t recEofCount;
+       uint32_t recEofdtiCount;
+       uint32_t recEofniCount;
+       uint32_t recSofcount;
+       uint32_t rsvd1;
+       uint32_t rsvd2;
+       uint32_t recDrpXriCount;
+       uint32_t fecCorrBlkCount;
+       uint32_t fecUncorrBlkCount;
 } READ_LNK_VAR;
 
 /* Structure for MB Command REG_LOGIN (19) */
index 33ec4fa39ccb46e147802a75b080a91a5aa65ea2..608f9415fb08d9994754411d03d66d1a20273686 100644 (file)
@@ -3317,6 +3317,7 @@ struct lpfc_acqe_link {
 #define LPFC_ASYNC_LINK_SPEED_20GBPS           0x5
 #define LPFC_ASYNC_LINK_SPEED_25GBPS           0x6
 #define LPFC_ASYNC_LINK_SPEED_40GBPS           0x7
+#define LPFC_ASYNC_LINK_SPEED_100GBPS          0x8
 #define lpfc_acqe_link_duplex_SHIFT            16
 #define lpfc_acqe_link_duplex_MASK             0x000000FF
 #define lpfc_acqe_link_duplex_WORD             word0
@@ -3447,23 +3448,50 @@ struct lpfc_acqe_fc_la {
 struct lpfc_acqe_misconfigured_event {
        struct {
        uint32_t word0;
-#define lpfc_sli_misconfigured_port0_SHIFT     0
-#define lpfc_sli_misconfigured_port0_MASK      0x000000FF
-#define lpfc_sli_misconfigured_port0_WORD      word0
-#define lpfc_sli_misconfigured_port1_SHIFT     8
-#define lpfc_sli_misconfigured_port1_MASK      0x000000FF
-#define lpfc_sli_misconfigured_port1_WORD      word0
-#define lpfc_sli_misconfigured_port2_SHIFT     16
-#define lpfc_sli_misconfigured_port2_MASK      0x000000FF
-#define lpfc_sli_misconfigured_port2_WORD      word0
-#define lpfc_sli_misconfigured_port3_SHIFT     24
-#define lpfc_sli_misconfigured_port3_MASK      0x000000FF
-#define lpfc_sli_misconfigured_port3_WORD      word0
+#define lpfc_sli_misconfigured_port0_state_SHIFT       0
+#define lpfc_sli_misconfigured_port0_state_MASK                0x000000FF
+#define lpfc_sli_misconfigured_port0_state_WORD                word0
+#define lpfc_sli_misconfigured_port1_state_SHIFT       8
+#define lpfc_sli_misconfigured_port1_state_MASK                0x000000FF
+#define lpfc_sli_misconfigured_port1_state_WORD                word0
+#define lpfc_sli_misconfigured_port2_state_SHIFT       16
+#define lpfc_sli_misconfigured_port2_state_MASK                0x000000FF
+#define lpfc_sli_misconfigured_port2_state_WORD                word0
+#define lpfc_sli_misconfigured_port3_state_SHIFT       24
+#define lpfc_sli_misconfigured_port3_state_MASK                0x000000FF
+#define lpfc_sli_misconfigured_port3_state_WORD                word0
+       uint32_t word1;
+#define lpfc_sli_misconfigured_port0_op_SHIFT          0
+#define lpfc_sli_misconfigured_port0_op_MASK           0x00000001
+#define lpfc_sli_misconfigured_port0_op_WORD           word1
+#define lpfc_sli_misconfigured_port0_severity_SHIFT    1
+#define lpfc_sli_misconfigured_port0_severity_MASK     0x00000003
+#define lpfc_sli_misconfigured_port0_severity_WORD     word1
+#define lpfc_sli_misconfigured_port1_op_SHIFT          8
+#define lpfc_sli_misconfigured_port1_op_MASK           0x00000001
+#define lpfc_sli_misconfigured_port1_op_WORD           word1
+#define lpfc_sli_misconfigured_port1_severity_SHIFT    9
+#define lpfc_sli_misconfigured_port1_severity_MASK     0x00000003
+#define lpfc_sli_misconfigured_port1_severity_WORD     word1
+#define lpfc_sli_misconfigured_port2_op_SHIFT          16
+#define lpfc_sli_misconfigured_port2_op_MASK           0x00000001
+#define lpfc_sli_misconfigured_port2_op_WORD           word1
+#define lpfc_sli_misconfigured_port2_severity_SHIFT    17
+#define lpfc_sli_misconfigured_port2_severity_MASK     0x00000003
+#define lpfc_sli_misconfigured_port2_severity_WORD     word1
+#define lpfc_sli_misconfigured_port3_op_SHIFT          24
+#define lpfc_sli_misconfigured_port3_op_MASK           0x00000001
+#define lpfc_sli_misconfigured_port3_op_WORD           word1
+#define lpfc_sli_misconfigured_port3_severity_SHIFT    25
+#define lpfc_sli_misconfigured_port3_severity_MASK     0x00000003
+#define lpfc_sli_misconfigured_port3_severity_WORD     word1
        } theEvent;
 #define LPFC_SLI_EVENT_STATUS_VALID                    0x00
 #define LPFC_SLI_EVENT_STATUS_NOT_PRESENT      0x01
 #define LPFC_SLI_EVENT_STATUS_WRONG_TYPE       0x02
 #define LPFC_SLI_EVENT_STATUS_UNSUPPORTED      0x03
+#define LPFC_SLI_EVENT_STATUS_UNQUALIFIED      0x04
+#define LPFC_SLI_EVENT_STATUS_UNCERTIFIED      0x05
 };
 
 struct lpfc_acqe_sli {
index db9446c612dadf1ffebb3de4803eb4a59ec6442f..a544366a367e3e079062ec5c7f17351db91ff395 100644 (file)
@@ -1184,8 +1184,10 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
 
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
-               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
                        lpfc_rcv_seq_check_edtov(vports[i]);
+                       lpfc_fdmi_num_disc_check(vports[i]);
+               }
        lpfc_destroy_vport_work_array(phba, vports);
 
        if ((phba->link_state == LPFC_HBA_ERROR) ||
@@ -1290,6 +1292,10 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
                                jiffies +
                                msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT));
                }
+       } else {
+                       mod_timer(&phba->hb_tmofunc,
+                               jiffies +
+                               msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
        }
 }
 
@@ -2621,7 +2627,6 @@ void
 lpfc_stop_vport_timers(struct lpfc_vport *vport)
 {
        del_timer_sync(&vport->els_tmofunc);
-       del_timer_sync(&vport->fc_fdmitmo);
        del_timer_sync(&vport->delayed_disc_tmo);
        lpfc_can_disctmo(vport);
        return;
@@ -3340,10 +3345,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        vport->fc_disctmo.function = lpfc_disc_timeout;
        vport->fc_disctmo.data = (unsigned long)vport;
 
-       init_timer(&vport->fc_fdmitmo);
-       vport->fc_fdmitmo.function = lpfc_fdmi_tmo;
-       vport->fc_fdmitmo.data = (unsigned long)vport;
-
        init_timer(&vport->els_tmofunc);
        vport->els_tmofunc.function = lpfc_els_timeout;
        vport->els_tmofunc.data = (unsigned long)vport;
@@ -3708,49 +3709,6 @@ lpfc_sli4_parse_latt_type(struct lpfc_hba *phba,
        return att_type;
 }
 
-/**
- * lpfc_sli4_parse_latt_link_speed - Parse sli4 link-attention link speed
- * @phba: pointer to lpfc hba data structure.
- * @acqe_link: pointer to the async link completion queue entry.
- *
- * This routine is to parse the SLI4 link-attention link speed and translate
- * it into the base driver's link-attention link speed coding.
- *
- * Return: Link-attention link speed in terms of base driver's coding.
- **/
-static uint8_t
-lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba,
-                               struct lpfc_acqe_link *acqe_link)
-{
-       uint8_t link_speed;
-
-       switch (bf_get(lpfc_acqe_link_speed, acqe_link)) {
-       case LPFC_ASYNC_LINK_SPEED_ZERO:
-       case LPFC_ASYNC_LINK_SPEED_10MBPS:
-       case LPFC_ASYNC_LINK_SPEED_100MBPS:
-               link_speed = LPFC_LINK_SPEED_UNKNOWN;
-               break;
-       case LPFC_ASYNC_LINK_SPEED_1GBPS:
-               link_speed = LPFC_LINK_SPEED_1GHZ;
-               break;
-       case LPFC_ASYNC_LINK_SPEED_10GBPS:
-               link_speed = LPFC_LINK_SPEED_10GHZ;
-               break;
-       case LPFC_ASYNC_LINK_SPEED_20GBPS:
-       case LPFC_ASYNC_LINK_SPEED_25GBPS:
-       case LPFC_ASYNC_LINK_SPEED_40GBPS:
-               link_speed = LPFC_LINK_SPEED_UNKNOWN;
-               break;
-       default:
-               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                               "0483 Invalid link-attention link speed: x%x\n",
-                               bf_get(lpfc_acqe_link_speed, acqe_link));
-               link_speed = LPFC_LINK_SPEED_UNKNOWN;
-               break;
-       }
-       return link_speed;
-}
-
 /**
  * lpfc_sli_port_speed_get - Get sli3 link speed code to link speed
  * @phba: pointer to lpfc hba data structure.
@@ -3767,27 +3725,35 @@ lpfc_sli_port_speed_get(struct lpfc_hba *phba)
        if (!lpfc_is_link_up(phba))
                return 0;
 
-       switch (phba->fc_linkspeed) {
-       case LPFC_LINK_SPEED_1GHZ:
-               link_speed = 1000;
-               break;
-       case LPFC_LINK_SPEED_2GHZ:
-               link_speed = 2000;
-               break;
-       case LPFC_LINK_SPEED_4GHZ:
-               link_speed = 4000;
-               break;
-       case LPFC_LINK_SPEED_8GHZ:
-               link_speed = 8000;
-               break;
-       case LPFC_LINK_SPEED_10GHZ:
-               link_speed = 10000;
-               break;
-       case LPFC_LINK_SPEED_16GHZ:
-               link_speed = 16000;
-               break;
-       default:
-               link_speed = 0;
+       if (phba->sli_rev <= LPFC_SLI_REV3) {
+               switch (phba->fc_linkspeed) {
+               case LPFC_LINK_SPEED_1GHZ:
+                       link_speed = 1000;
+                       break;
+               case LPFC_LINK_SPEED_2GHZ:
+                       link_speed = 2000;
+                       break;
+               case LPFC_LINK_SPEED_4GHZ:
+                       link_speed = 4000;
+                       break;
+               case LPFC_LINK_SPEED_8GHZ:
+                       link_speed = 8000;
+                       break;
+               case LPFC_LINK_SPEED_10GHZ:
+                       link_speed = 10000;
+                       break;
+               case LPFC_LINK_SPEED_16GHZ:
+                       link_speed = 16000;
+                       break;
+               default:
+                       link_speed = 0;
+               }
+       } else {
+               if (phba->sli4_hba.link_state.logical_speed)
+                       link_speed =
+                             phba->sli4_hba.link_state.logical_speed;
+               else
+                       link_speed = phba->sli4_hba.link_state.speed;
        }
        return link_speed;
 }
@@ -3983,7 +3949,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
        la->eventTag = acqe_link->event_tag;
        bf_set(lpfc_mbx_read_top_att_type, la, att_type);
        bf_set(lpfc_mbx_read_top_link_spd, la,
-              lpfc_sli4_parse_latt_link_speed(phba, acqe_link));
+              (bf_get(lpfc_acqe_link_speed, acqe_link)));
 
        /* Fake the the following irrelvant fields */
        bf_set(lpfc_mbx_read_top_topology, la, LPFC_TOPOLOGY_PT_PT);
@@ -4113,22 +4079,18 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
        char message[128];
        uint8_t status;
        uint8_t evt_type;
+       uint8_t operational = 0;
        struct temp_event temp_event_data;
        struct lpfc_acqe_misconfigured_event *misconfigured;
        struct Scsi_Host  *shost;
 
        evt_type = bf_get(lpfc_trailer_type, acqe_sli);
 
-       /* Special case Lancer */
-       if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
-                LPFC_SLI_INTF_IF_TYPE_2) {
-               lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                               "2901 Async SLI event - Event Data1:x%08x Event Data2:"
-                               "x%08x SLI Event Type:%d\n",
-                               acqe_sli->event_data1, acqe_sli->event_data2,
-                               evt_type);
-               return;
-       }
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "2901 Async SLI event - Event Data1:x%08x Event Data2:"
+                       "x%08x SLI Event Type:%d\n",
+                       acqe_sli->event_data1, acqe_sli->event_data2,
+                       evt_type);
 
        port_name = phba->Port[0];
        if (port_name == 0x00)
@@ -4174,29 +4136,46 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
                /* fetch the status for this port */
                switch (phba->sli4_hba.lnk_info.lnk_no) {
                case LPFC_LINK_NUMBER_0:
-                       status = bf_get(lpfc_sli_misconfigured_port0,
+                       status = bf_get(lpfc_sli_misconfigured_port0_state,
+                                       &misconfigured->theEvent);
+                       operational = bf_get(lpfc_sli_misconfigured_port0_op,
                                        &misconfigured->theEvent);
                        break;
                case LPFC_LINK_NUMBER_1:
-                       status = bf_get(lpfc_sli_misconfigured_port1,
+                       status = bf_get(lpfc_sli_misconfigured_port1_state,
+                                       &misconfigured->theEvent);
+                       operational = bf_get(lpfc_sli_misconfigured_port1_op,
                                        &misconfigured->theEvent);
                        break;
                case LPFC_LINK_NUMBER_2:
-                       status = bf_get(lpfc_sli_misconfigured_port2,
+                       status = bf_get(lpfc_sli_misconfigured_port2_state,
+                                       &misconfigured->theEvent);
+                       operational = bf_get(lpfc_sli_misconfigured_port2_op,
                                        &misconfigured->theEvent);
                        break;
                case LPFC_LINK_NUMBER_3:
-                       status = bf_get(lpfc_sli_misconfigured_port3,
+                       status = bf_get(lpfc_sli_misconfigured_port3_state,
+                                       &misconfigured->theEvent);
+                       operational = bf_get(lpfc_sli_misconfigured_port3_op,
                                        &misconfigured->theEvent);
                        break;
                default:
-                       status = ~LPFC_SLI_EVENT_STATUS_VALID;
-                       break;
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                                       "3296 "
+                                       "LPFC_SLI_EVENT_TYPE_MISCONFIGURED "
+                                       "event: Invalid link %d",
+                                       phba->sli4_hba.lnk_info.lnk_no);
+                       return;
                }
 
+               /* Skip if optic state unchanged */
+               if (phba->sli4_hba.lnk_info.optic_state == status)
+                       return;
+
                switch (status) {
                case LPFC_SLI_EVENT_STATUS_VALID:
-                       return; /* no message if the sfp is okay */
+                       sprintf(message, "Physical Link is functional");
+                       break;
                case LPFC_SLI_EVENT_STATUS_NOT_PRESENT:
                        sprintf(message, "Optics faulted/incorrectly "
                                "installed/not installed - Reseat optics, "
@@ -4211,15 +4190,26 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
                        sprintf(message, "Incompatible optics - Replace with "
                                "compatible optics for card to function.");
                        break;
+               case LPFC_SLI_EVENT_STATUS_UNQUALIFIED:
+                       sprintf(message, "Unqualified optics - Replace with "
+                               "Avago optics for Warranty and Technical "
+                               "Support - Link is%s operational",
+                               (operational) ? "" : " not");
+                       break;
+               case LPFC_SLI_EVENT_STATUS_UNCERTIFIED:
+                       sprintf(message, "Uncertified optics - Replace with "
+                               "Avago-certified optics to enable link "
+                               "operation - Link is%s operational",
+                               (operational) ? "" : " not");
+                       break;
                default:
                        /* firmware is reporting a status we don't know about */
                        sprintf(message, "Unknown event status x%02x", status);
                        break;
                }
-
+               phba->sli4_hba.lnk_info.optic_state = status;
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-                               "3176 Misconfigured Physical Port - "
-                               "Port Name %c %s\n", port_name, message);
+                               "3176 Port Name %c %s\n", port_name, message);
                break;
        case LPFC_SLI_EVENT_TYPE_REMOTE_DPORT:
                lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -5293,6 +5283,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list);
        INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list);
 
+       /* initialize optic_state to 0xFF */
+       phba->sli4_hba.lnk_info.optic_state = 0xff;
+
        /* Initialize the driver internal SLI layer lists. */
        lpfc_sli_setup(phba);
        lpfc_sli_queue_setup(phba);
@@ -6159,6 +6152,20 @@ lpfc_create_shost(struct lpfc_hba *phba)
        /* Put reference to SCSI host to driver's device private data */
        pci_set_drvdata(phba->pcidev, shost);
 
+       /*
+        * At this point we are fully registered with PSA. In addition,
+        * any initial discovery should be completed.
+        */
+       vport->load_flag |= FC_ALLOW_FDMI;
+       if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+
+               /* Setup appropriate attribute masks */
+               vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+               if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+                       vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+               else
+                       vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+       }
        return 0;
 }
 
@@ -8833,9 +8840,12 @@ found:
                                 * already mapped to this phys_id.
                                 */
                                if (cpup->irq != LPFC_VECTOR_MAP_EMPTY) {
-                                       chann[saved_chann] =
-                                               cpup->channel_id;
-                                       saved_chann++;
+                                       if (saved_chann <=
+                                           LPFC_FCP_IO_CHAN_MAX) {
+                                               chann[saved_chann] =
+                                                       cpup->channel_id;
+                                               saved_chann++;
+                                       }
                                        goto out;
                                }
 
index 3fa65338d3f55614628c2710afaacd8ebaa53b2b..4fb3581d4614c55cc50b9d5c711c18805c7cb050 100644 (file)
@@ -231,15 +231,13 @@ lpfc_mem_free(struct lpfc_hba *phba)
        if (phba->lpfc_hbq_pool)
                pci_pool_destroy(phba->lpfc_hbq_pool);
        phba->lpfc_hbq_pool = NULL;
-
-       if (phba->rrq_pool)
-               mempool_destroy(phba->rrq_pool);
+       mempool_destroy(phba->rrq_pool);
        phba->rrq_pool = NULL;
 
        /* Free NLP memory pool */
        mempool_destroy(phba->nlp_mem_pool);
        phba->nlp_mem_pool = NULL;
-       if (phba->sli_rev == LPFC_SLI_REV4 && phba->active_rrq_pool) {
+       if (phba->sli_rev == LPFC_SLI_REV4) {
                mempool_destroy(phba->active_rrq_pool);
                phba->active_rrq_pool = NULL;
        }
index ed9a2c80c4aad4324de640367ca2dbd76d7c15ea..193733e8c8235ac23469493b312f31a6c128e11e 100644 (file)
@@ -280,38 +280,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        uint32_t *lp;
        IOCB_t *icmd;
        struct serv_parm *sp;
+       uint32_t ed_tov;
        LPFC_MBOXQ_t *mbox;
        struct ls_rjt stat;
        int rc;
 
        memset(&stat, 0, sizeof (struct ls_rjt));
-       if (vport->port_state <= LPFC_FDISC) {
-               /* Before responding to PLOGI, check for pt2pt mode.
-                * If we are pt2pt, with an outstanding FLOGI, abort
-                * the FLOGI and resend it first.
-                */
-               if (vport->fc_flag & FC_PT2PT) {
-                        lpfc_els_abort_flogi(phba);
-                       if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-                               /* If the other side is supposed to initiate
-                                * the PLOGI anyway, just ACC it now and
-                                * move on with discovery.
-                                */
-                               phba->fc_edtov = FF_DEF_EDTOV;
-                               phba->fc_ratov = FF_DEF_RATOV;
-                               /* Start discovery - this should just do
-                                  CLEAR_LA */
-                               lpfc_disc_start(vport);
-                       } else
-                               lpfc_initial_flogi(vport);
-               } else {
-                       stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
-                       stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
-                       lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
-                                           ndlp, NULL);
-                       return 0;
-               }
-       }
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
        sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
@@ -404,30 +378,46 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        /* Check for Nport to NPort pt2pt protocol */
        if ((vport->fc_flag & FC_PT2PT) &&
            !(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
                /* rcv'ed PLOGI decides what our NPortId will be */
                vport->fc_myDID = icmd->un.rcvels.parmRo;
-               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-               if (mbox == NULL)
-                       goto out;
-               lpfc_config_link(phba, mbox);
-               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               mbox->vport = vport;
-               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-               if (rc == MBX_NOT_FINISHED) {
-                       mempool_free(mbox, phba->mbox_mem_pool);
-                       goto out;
+
+               ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+               if (sp->cmn.edtovResolution) {
+                       /* E_D_TOV ticks are in nanoseconds */
+                       ed_tov = (phba->fc_edtov + 999999) / 1000000;
                }
+
                /*
-                * For SLI4, the VFI/VPI are registered AFTER the
-                * Nport with the higher WWPN sends us a PLOGI with
-                * our assigned NPortId.
+                * For pt-to-pt, use the larger EDTOV
+                * RATOV = 2 * EDTOV
                 */
+               if (ed_tov > phba->fc_edtov)
+                       phba->fc_edtov = ed_tov;
+               phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+               memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+               /* Issue config_link / reg_vfi to account for updated TOV's */
+
                if (phba->sli_rev == LPFC_SLI_REV4)
                        lpfc_issue_reg_vfi(vport);
+               else {
+                       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+                       if (mbox == NULL)
+                               goto out;
+                       lpfc_config_link(phba, mbox);
+                       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+                       mbox->vport = vport;
+                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+                       if (rc == MBX_NOT_FINISHED) {
+                               mempool_free(mbox, phba->mbox_mem_pool);
+                               goto out;
+                       }
+               }
 
                lpfc_can_disctmo(vport);
        }
+
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox)
                goto out;
@@ -1038,7 +1028,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
        uint32_t *lp;
        IOCB_t *irsp;
        struct serv_parm *sp;
+       uint32_t ed_tov;
        LPFC_MBOXQ_t *mbox;
+       int rc;
 
        cmdiocb = (struct lpfc_iocbq *) arg;
        rspiocb = cmdiocb->context_un.rsp_iocb;
@@ -1094,18 +1086,63 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
        ndlp->nlp_maxframe =
                ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
 
+       if ((vport->fc_flag & FC_PT2PT) &&
+           (vport->fc_flag & FC_PT2PT_PLOGI)) {
+               ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+               if (sp->cmn.edtovResolution) {
+                       /* E_D_TOV ticks are in nanoseconds */
+                       ed_tov = (phba->fc_edtov + 999999) / 1000000;
+               }
+
+               /*
+                * Use the larger EDTOV
+                * RATOV = 2 * EDTOV for pt-to-pt
+                */
+               if (ed_tov > phba->fc_edtov)
+                       phba->fc_edtov = ed_tov;
+               phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+               memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+               /* Issue config_link / reg_vfi to account for updated TOV's */
+               if (phba->sli_rev == LPFC_SLI_REV4) {
+                       lpfc_issue_reg_vfi(vport);
+               } else {
+                       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+                       if (!mbox) {
+                               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                                "0133 PLOGI: no memory "
+                                                "for config_link "
+                                                "Data: x%x x%x x%x x%x\n",
+                                                ndlp->nlp_DID, ndlp->nlp_state,
+                                                ndlp->nlp_flag, ndlp->nlp_rpi);
+                               goto out;
+                       }
+
+                       lpfc_config_link(phba, mbox);
+
+                       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+                       mbox->vport = vport;
+                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+                       if (rc == MBX_NOT_FINISHED) {
+                               mempool_free(mbox, phba->mbox_mem_pool);
+                               goto out;
+                       }
+               }
+       }
+
+       lpfc_unreg_rpi(vport, ndlp);
+
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox) {
                lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-                       "0133 PLOGI: no memory for reg_login "
-                       "Data: x%x x%x x%x x%x\n",
-                       ndlp->nlp_DID, ndlp->nlp_state,
-                       ndlp->nlp_flag, ndlp->nlp_rpi);
+                                "0018 PLOGI: no memory for reg_login "
+                                "Data: x%x x%x x%x x%x\n",
+                                ndlp->nlp_DID, ndlp->nlp_state,
+                                ndlp->nlp_flag, ndlp->nlp_rpi);
                goto out;
        }
 
-       lpfc_unreg_rpi(vport, ndlp);
-
        if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
                         (uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
                switch (ndlp->nlp_DID) {
@@ -2299,6 +2336,9 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
                if (vport->phba->sli_rev < LPFC_SLI_REV4)
                        ndlp->nlp_rpi = mb->un.varWords[0];
                ndlp->nlp_flag |= NLP_RPI_REGISTERED;
+               if (ndlp->nlp_flag & NLP_LOGO_ACC) {
+                       lpfc_unreg_rpi(vport, ndlp);
+               }
        } else {
                if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
                        lpfc_drop_node(vport, ndlp);
index 4679ed4444a737e906342473031397b2137443ff..152b3c8a5428fd522bb514fc3acfeafce31a5572 100644 (file)
@@ -3676,6 +3676,7 @@ static void
 lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
                    struct lpfc_iocbq *rsp_iocb)
 {
+       struct lpfc_hba *phba = vport->phba;
        struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
        struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
        struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
@@ -3685,6 +3686,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
        uint32_t *lp;
        uint32_t host_status = DID_OK;
        uint32_t rsplen = 0;
+       uint32_t fcpDl;
        uint32_t logit = LOG_FCP | LOG_FCP_ERROR;
 
 
@@ -3755,13 +3757,14 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
                         fcprsp->rspInfo3);
 
        scsi_set_resid(cmnd, 0);
+       fcpDl = be32_to_cpu(fcpcmd->fcpDl);
        if (resp_info & RESID_UNDER) {
                scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
 
                lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER,
                                 "9025 FCP Read Underrun, expected %d, "
                                 "residual %d Data: x%x x%x x%x\n",
-                                be32_to_cpu(fcpcmd->fcpDl),
+                                fcpDl,
                                 scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
                                 cmnd->underflow);
 
@@ -3777,7 +3780,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
                                         LOG_FCP | LOG_FCP_ERROR,
                                         "9026 FCP Read Check Error "
                                         "and Underrun Data: x%x x%x x%x x%x\n",
-                                        be32_to_cpu(fcpcmd->fcpDl),
+                                        fcpDl,
                                         scsi_get_resid(cmnd), fcpi_parm,
                                         cmnd->cmnd[0]);
                        scsi_set_resid(cmnd, scsi_bufflen(cmnd));
@@ -3812,13 +3815,25 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
         * Check SLI validation that all the transfer was actually done
         * (fcpi_parm should be zero). Apply check only to reads.
         */
-       } else if (fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
+       } else if (fcpi_parm) {
                lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
-                                "9029 FCP Read Check Error Data: "
+                                "9029 FCP %s Check Error xri x%x  Data: "
                                 "x%x x%x x%x x%x x%x\n",
-                                be32_to_cpu(fcpcmd->fcpDl),
-                                be32_to_cpu(fcprsp->rspResId),
+                                ((cmnd->sc_data_direction == DMA_FROM_DEVICE) ?
+                                "Read" : "Write"),
+                                ((phba->sli_rev == LPFC_SLI_REV4) ?
+                                lpfc_cmd->cur_iocbq.sli4_xritag :
+                                rsp_iocb->iocb.ulpContext),
+                                fcpDl, be32_to_cpu(fcprsp->rspResId),
                                 fcpi_parm, cmnd->cmnd[0], scsi_status);
+
+               /* There is some issue with the LPe12000 that causes it
+                * to miscalculate the fcpi_parm and falsely trip this
+                * recovery logic.  Detect this case and don't error when true.
+                */
+               if (fcpi_parm > fcpDl)
+                       goto out;
+
                switch (scsi_status) {
                case SAM_STAT_GOOD:
                case SAM_STAT_CHECK_CONDITION:
@@ -3908,9 +3923,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
        uint32_t logit = LOG_FCP;
 
        /* Sanity check on return of outstanding command */
-       if (!(lpfc_cmd->pCmd))
-               return;
        cmd = lpfc_cmd->pCmd;
+       if (!cmd)
+               return;
        shost = cmd->device->host;
 
        lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
@@ -4446,15 +4461,7 @@ lpfc_info(struct Scsi_Host *host)
                                 phba->Port);
                }
                len = strlen(lpfcinfobuf);
-               if (phba->sli_rev <= LPFC_SLI_REV3) {
-                       link_speed = lpfc_sli_port_speed_get(phba);
-               } else {
-                       if (phba->sli4_hba.link_state.logical_speed)
-                               link_speed =
-                                     phba->sli4_hba.link_state.logical_speed;
-                       else
-                               link_speed = phba->sli4_hba.link_state.speed;
-               }
+               link_speed = lpfc_sli_port_speed_get(phba);
                if (link_speed != 0)
                        snprintf(lpfcinfobuf + len, 384-len,
                                 " Logical Link Speed: %d Mbps", link_speed);
index f9585cdd89333cf342b92297af61752ab3e63cdf..92dfd6a5178cef9e6826ad9159261765335c264b 100644 (file)
@@ -14842,10 +14842,12 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
        struct lpfc_dmabuf *h_buf;
        struct hbq_dmabuf *seq_dmabuf = NULL;
        struct hbq_dmabuf *temp_dmabuf = NULL;
+       uint8_t found = 0;
 
        INIT_LIST_HEAD(&dmabuf->dbuf.list);
        dmabuf->time_stamp = jiffies;
        new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+
        /* Use the hdr_buf to find the sequence that this frame belongs to */
        list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
                temp_hdr = (struct fc_frame_header *)h_buf->virt;
@@ -14885,7 +14887,8 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
                return seq_dmabuf;
        }
        /* find the correct place in the sequence to insert this frame */
-       list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) {
+       d_buf = list_entry(seq_dmabuf->dbuf.list.prev, typeof(*d_buf), list);
+       while (!found) {
                temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
                temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt;
                /*
@@ -14895,9 +14898,17 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
                if (be16_to_cpu(new_hdr->fh_seq_cnt) >
                        be16_to_cpu(temp_hdr->fh_seq_cnt)) {
                        list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list);
-                       return seq_dmabuf;
+                       found = 1;
+                       break;
                }
+
+               if (&d_buf->list == &seq_dmabuf->dbuf.list)
+                       break;
+               d_buf = list_entry(d_buf->list.prev, typeof(*d_buf), list);
        }
+
+       if (found)
+               return seq_dmabuf;
        return NULL;
 }
 
@@ -16173,7 +16184,7 @@ fail_fcf_read:
 }
 
 /**
- * lpfc_check_next_fcf_pri
+ * lpfc_check_next_fcf_pri_level
  * phba pointer to the lpfc_hba struct for this port.
  * This routine is called from the lpfc_sli4_fcf_rr_next_index_get
  * routine when the rr_bmask is empty. The FCF indecies are put into the
@@ -16329,8 +16340,12 @@ next_priority:
 
        if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
                phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
-               LPFC_FCF_FLOGI_FAILED)
+               LPFC_FCF_FLOGI_FAILED) {
+               if (list_is_singular(&phba->fcf.fcf_pri_list))
+                       return LPFC_FCOE_FCF_NEXT_NONE;
+
                goto next_priority;
+       }
 
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
                        "2845 Get next roundrobin failover FCF (x%x)\n",
index 1e916e16ce989beb47b4c3d13db70619407047aa..cd780c29495aa6eddedafa34367c315fa9813e84 100644 (file)
@@ -442,6 +442,7 @@ struct lpfc_sli4_lnk_info {
 #define LPFC_LNK_GE    0x0 /* FCoE */
 #define LPFC_LNK_FC    0x1 /* FC   */
        uint8_t lnk_no;
+       uint8_t optic_state;
 };
 
 #define LPFC_SLI4_HANDLER_CNT          (LPFC_FCP_IO_CHAN_MAX+ \
index ea53aa664759ba5d5f78c1a109854894f60f5227..4dc22562aaf164d7e9b302ebfe2da380fef2780c 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "11.0.0.0."
+#define LPFC_DRIVER_VERSION "11.0.0.10."
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
index 769012663a8f53c2590234009fec7d7127e15f85..b3f85def18ccca8daff2a809aac3d7b4e69cec1e 100644 (file)
@@ -393,6 +393,14 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
        *(struct lpfc_vport **)fc_vport->dd_data = vport;
        vport->fc_vport = fc_vport;
 
+       /* At this point we are fully registered with SCSI Layer.  */
+       vport->load_flag |= FC_ALLOW_FDMI;
+       if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+               /* Setup appropriate attribute masks */
+               vport->fdmi_hba_mask = phba->pport->fdmi_hba_mask;
+               vport->fdmi_port_mask = phba->pport->fdmi_port_mask;
+       }
+
        /*
         * In SLI4, the vpi must be activated before it can be used
         * by the port.
index 11393ebf1a68ef8f14a38d58f1321d7783a84d72..83658acddd584bfcd0c5eb5545648d021e3e65f1 100644 (file)
@@ -2020,8 +2020,10 @@ mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
        _base_free_irq(ioc);
        _base_disable_msix(ioc);
 
-       if (ioc->msix96_vector)
+       if (ioc->msix96_vector) {
                kfree(ioc->replyPostRegisterIndex);
+               ioc->replyPostRegisterIndex = NULL;
+       }
 
        if (ioc->chip_phys) {
                iounmap(ioc->chip);
index 9270d15ff1a4977817bd24215f4f8ccbaf3a7c3c..f6fc4a70592489c5bb01589304414f9be523961b 100644 (file)
@@ -330,6 +330,51 @@ static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
        mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff);
 }
 
+static void mvs_94xx_sgpio_init(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs_ex - 0x10200;
+       u32 tmp;
+
+       tmp = mr32(MVS_HST_CHIP_CONFIG);
+       tmp |= 0x100;
+       mw32(MVS_HST_CHIP_CONFIG, tmp);
+
+       mw32(MVS_SGPIO_CTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+               MVS_SGPIO_CTRL_SDOUT_AUTO << MVS_SGPIO_CTRL_SDOUT_SHIFT);
+
+       mw32(MVS_SGPIO_CFG1 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+               8 << MVS_SGPIO_CFG1_LOWA_SHIFT |
+               8 << MVS_SGPIO_CFG1_HIA_SHIFT |
+               4 << MVS_SGPIO_CFG1_LOWB_SHIFT |
+               4 << MVS_SGPIO_CFG1_HIB_SHIFT |
+               2 << MVS_SGPIO_CFG1_MAXACTON_SHIFT |
+               1 << MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT
+       );
+
+       mw32(MVS_SGPIO_CFG2 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+               (300000 / 100) << MVS_SGPIO_CFG2_CLK_SHIFT | /* 100kHz clock */
+               66 << MVS_SGPIO_CFG2_BLINK_SHIFT /* (66 * 0,121 Hz?)*/
+       );
+
+       mw32(MVS_SGPIO_CFG0 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+               MVS_SGPIO_CFG0_ENABLE |
+               MVS_SGPIO_CFG0_BLINKA |
+               MVS_SGPIO_CFG0_BLINKB |
+               /* 3*4 data bits / PDU */
+               (12 - 1) << MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT
+       );
+
+       mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+               DEFAULT_SGPIO_BITS);
+
+       mw32(MVS_SGPIO_DSRC + MVS_SGPIO_HOST_OFFSET * mvi->id,
+               ((mvi->id * 4) + 3) << (8 * 3) |
+               ((mvi->id * 4) + 2) << (8 * 2) |
+               ((mvi->id * 4) + 1) << (8 * 1) |
+               ((mvi->id * 4) + 0) << (8 * 0));
+
+}
+
 static int mvs_94xx_init(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
@@ -533,6 +578,8 @@ static int mvs_94xx_init(struct mvs_info *mvi)
        /* Enable SRS interrupt */
        mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
 
+       mvs_94xx_sgpio_init(mvi);
+
        return 0;
 }
 
@@ -1005,6 +1052,92 @@ static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
 
 }
 
+static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv,
+                       u8 reg_type, u8 reg_index,
+                       u8 reg_count, u8 *write_data)
+{
+       int i;
+
+       switch (reg_type) {
+
+       case SAS_GPIO_REG_TX_GP:
+               if (reg_index == 0)
+                       return -EINVAL;
+
+               if (reg_count > 1)
+                       return -EINVAL;
+
+               if (reg_count == 0)
+                       return 0;
+
+               /* maximum supported bits = hosts * 4 drives * 3 bits */
+               for (i = 0; i < mvs_prv->n_host * 4 * 3; i++) {
+
+                       /* select host */
+                       struct mvs_info *mvi = mvs_prv->mvi[i/(4*3)];
+
+                       void __iomem *regs = mvi->regs_ex - 0x10200;
+
+                       int drive = (i/3) & (4-1); /* drive number on host */
+                       u32 block = mr32(MVS_SGPIO_DCTRL +
+                               MVS_SGPIO_HOST_OFFSET * mvi->id);
+
+
+                       /*
+                       * if bit is set then create a mask with the first
+                       * bit of the drive set in the mask ...
+                       */
+                       u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ?
+                               1<<(24-drive*8) : 0;
+
+                       /*
+                       * ... and then shift it to the right position based
+                       * on the led type (activity/id/fail)
+                       */
+                       switch (i%3) {
+                       case 0: /* activity */
+                               block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT)
+                                       << (24-drive*8));
+                                       /* hardwire activity bit to SOF */
+                               block |= LED_BLINKA_SOF << (
+                                       MVS_SGPIO_DCTRL_ACT_SHIFT +
+                                       (24-drive*8));
+                               break;
+                       case 1: /* id */
+                               block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT)
+                                       << (24-drive*8));
+                               block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT;
+                               break;
+                       case 2: /* fail */
+                               block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT)
+                                       << (24-drive*8));
+                               block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT;
+                               break;
+                       }
+
+                       mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+                               block);
+
+               }
+
+               return reg_count;
+
+       case SAS_GPIO_REG_TX:
+               if (reg_index + reg_count > mvs_prv->n_host)
+                       return -EINVAL;
+
+               for (i = 0; i < reg_count; i++) {
+                       struct mvs_info *mvi = mvs_prv->mvi[i+reg_index];
+                       void __iomem *regs = mvi->regs_ex - 0x10200;
+
+                       mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+                               be32_to_cpu(((u32 *) write_data)[i]));
+               }
+               return reg_count;
+       }
+       return -ENOSYS;
+}
+
 const struct mvs_dispatch mvs_94xx_dispatch = {
        "mv94xx",
        mvs_94xx_init,
@@ -1057,5 +1190,6 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
        mvs_94xx_fix_dma,
        mvs_94xx_tune_interrupt,
        mvs_94xx_non_spec_ncq_error,
+       mvs_94xx_gpio_write,
 };
 
index 14e197497b4696971abfc81c492575f5a35e2db5..578960803a003316a0906c47e8219000840e147d 100644 (file)
@@ -38,6 +38,10 @@ enum VANIR_REVISION_ID {
        VANIR_C2_REV            = 0xC2,
 };
 
+enum host_registers {
+       MVS_HST_CHIP_CONFIG     = 0x10104,      /* chip configuration */
+};
+
 enum hw_registers {
        MVS_GBL_CTL             = 0x04,  /* global control */
        MVS_GBL_INT_STAT        = 0x00,  /* global irq status */
@@ -239,6 +243,73 @@ struct mvs_prd {
        __le32                  im_len;
 } __attribute__ ((packed));
 
+enum sgpio_registers {
+       MVS_SGPIO_HOST_OFFSET   = 0x100,        /* offset between hosts */
+
+       MVS_SGPIO_CFG0  = 0xc200,
+       MVS_SGPIO_CFG0_ENABLE   = (1 << 0),     /* enable pins */
+       MVS_SGPIO_CFG0_BLINKB   = (1 << 1),     /* blink generators */
+       MVS_SGPIO_CFG0_BLINKA   = (1 << 2),
+       MVS_SGPIO_CFG0_INVSCLK  = (1 << 3),     /* invert signal? */
+       MVS_SGPIO_CFG0_INVSLOAD = (1 << 4),
+       MVS_SGPIO_CFG0_INVSDOUT = (1 << 5),
+       MVS_SGPIO_CFG0_SLOAD_FALLEDGE = (1 << 6),       /* rise/fall edge? */
+       MVS_SGPIO_CFG0_SDOUT_FALLEDGE = (1 << 7),
+       MVS_SGPIO_CFG0_SDIN_RISEEDGE = (1 << 8),
+       MVS_SGPIO_CFG0_MAN_BITLEN_SHIFT = 18,   /* bits/frame manual mode */
+       MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT = 24,   /* bits/frame auto mode */
+
+       MVS_SGPIO_CFG1  = 0xc204,       /* blink timing register */
+       MVS_SGPIO_CFG1_LOWA_SHIFT       = 0,    /* A off time */
+       MVS_SGPIO_CFG1_HIA_SHIFT        = 4,    /* A on time */
+       MVS_SGPIO_CFG1_LOWB_SHIFT       = 8,    /* B off time */
+       MVS_SGPIO_CFG1_HIB_SHIFT        = 12,   /* B on time */
+       MVS_SGPIO_CFG1_MAXACTON_SHIFT   = 16,   /* max activity on time */
+
+               /* force activity off time */
+       MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT        = 20,
+               /* stretch activity on time */
+       MVS_SGPIO_CFG1_STRCHACTON_SHIFT = 24,
+               /* stretch activiity off time */
+       MVS_SGPIO_CFG1_STRCHACTOFF_SHIFT        = 28,
+
+
+       MVS_SGPIO_CFG2  = 0xc208,       /* clock speed register */
+       MVS_SGPIO_CFG2_CLK_SHIFT        = 0,
+       MVS_SGPIO_CFG2_BLINK_SHIFT      = 20,
+
+       MVS_SGPIO_CTRL  = 0xc20c,       /* SDOUT/SDIN mode control */
+       MVS_SGPIO_CTRL_SDOUT_AUTO       = 2,
+       MVS_SGPIO_CTRL_SDOUT_SHIFT      = 2,
+
+       MVS_SGPIO_DSRC  = 0xc220,       /* map ODn bits to drives */
+
+       MVS_SGPIO_DCTRL = 0xc238,
+       MVS_SGPIO_DCTRL_ERR_SHIFT       = 0,
+       MVS_SGPIO_DCTRL_LOC_SHIFT       = 3,
+       MVS_SGPIO_DCTRL_ACT_SHIFT       = 5,
+};
+
+enum sgpio_led_status {
+       LED_OFF = 0,
+       LED_ON  = 1,
+       LED_BLINKA      = 2,
+       LED_BLINKA_INV  = 3,
+       LED_BLINKA_SOF  = 4,
+       LED_BLINKA_EOF  = 5,
+       LED_BLINKB      = 6,
+       LED_BLINKB_INV  = 7,
+};
+
+#define DEFAULT_SGPIO_BITS ((LED_BLINKA_SOF << \
+                               MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 3) | \
+                       (LED_BLINKA_SOF << \
+                               MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 2) | \
+                       (LED_BLINKA_SOF << \
+                               MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 1) | \
+                       (LED_BLINKA_SOF << \
+                               MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 0))
+
 /*
  * these registers are accessed through port vendor
  * specific address/data registers
index 675e7fab0796e4c1ebfc3e7e77aa109592a25c02..c7c250519c4b05102001024871f8eca9500914a0 100644 (file)
@@ -84,6 +84,8 @@ static struct sas_domain_function_template mvs_transport_ops = {
        .lldd_port_formed       = mvs_port_formed,
        .lldd_port_deformed     = mvs_port_deformed,
 
+       .lldd_write_gpio        = mvs_gpio_write,
+
 };
 
 static void mvs_phy_init(struct mvs_info *mvi, int phy_id)
index 9c780740fb829db69d411c48717415f2ac10cb0e..83cd3ea2df41e50ea1291b565d15d2bd5ad43662 100644 (file)
@@ -737,8 +737,8 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf
                        mv_dprintk("device %016llx not ready.\n",
                                SAS_ADDR(dev->sas_addr));
 
-                       rc = SAS_PHY_DOWN;
-                       return rc;
+               rc = SAS_PHY_DOWN;
+               return rc;
        }
        tei.port = dev->port->lldd_port;
        if (tei.port && !tei.port->port_attached && !tmf) {
@@ -2105,3 +2105,16 @@ int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
        return 0;
 }
 
+int mvs_gpio_write(struct sas_ha_struct *sha, u8 reg_type, u8 reg_index,
+                       u8 reg_count, u8 *write_data)
+{
+       struct mvs_prv_info *mvs_prv = sha->lldd_ha;
+       struct mvs_info *mvi = mvs_prv->mvi[0];
+
+       if (MVS_CHIP_DISP->gpio_write) {
+               return MVS_CHIP_DISP->gpio_write(mvs_prv, reg_type,
+                       reg_index, reg_count, write_data);
+       }
+
+       return -ENOSYS;
+}
index dc409c04747ae668c629ffe468965302fcc853ac..f9afd4cdd4c4e9784e2bf83736ca5c48ed675f7e 100644 (file)
@@ -103,6 +103,7 @@ enum dev_reset {
 };
 
 struct mvs_info;
+struct mvs_prv_info;
 
 struct mvs_dispatch {
        char *name;
@@ -172,6 +173,8 @@ struct mvs_dispatch {
                                int buf_len, int from, void *prd);
        void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
        void (*non_spec_ncq_error)(struct mvs_info *mvi);
+       int (*gpio_write)(struct mvs_prv_info *mvs_prv, u8 reg_type,
+                       u8 reg_index, u8 reg_count, u8 *write_data);
 
 };
 
@@ -476,5 +479,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
 void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
 int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
 struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
+int mvs_gpio_write(struct sas_ha_struct *, u8 reg_type, u8 reg_index,
+                       u8 reg_count, u8 *write_data);
 #endif
 
index 0cccd6033feb6b477366fc3343e665d1ed68562e..d8a2b5185f56ec98b7dca33005146ff748a6cc5a 100644 (file)
@@ -170,10 +170,7 @@ static int _osd_get_print_system_info(struct osd_dev *od,
 
        /* FIXME: Where are the time utilities */
        pFirst = get_attrs[a++].val_ptr;
-       OSD_INFO("CLOCK                  [0x%02x%02x%02x%02x%02x%02x]\n",
-               ((char *)pFirst)[0], ((char *)pFirst)[1],
-               ((char *)pFirst)[2], ((char *)pFirst)[3],
-               ((char *)pFirst)[4], ((char *)pFirst)[5]);
+       OSD_INFO("CLOCK                  [0x%6phN]\n", pFirst);
 
        if (a < nelem) { /* IBM-OSD-SIM bug, Might not have it */
                unsigned len = get_attrs[a].len;
index a0f732b138e4b5868867a4c94e191ffd02ec43a2..10aa18ba05fdc6e6585502eda3a7dd1351db8099 100644 (file)
@@ -18,9 +18,6 @@ config SCSI_QLA_FC
        2322, 6322        ql2322_fw.bin
        24xx, 54xx        ql2400_fw.bin
        25xx              ql2500_fw.bin
-       2031              ql2600_fw.bin
-       8031              ql8300_fw.bin
-       27xx              ql2700_fw.bin
 
        Upon request, the driver caches the firmware image until
        the driver is unloaded.
index bfa9a64c316b6ca2eec9a1b2277608f68101d92d..6be32fdab365bd5258d1ea57b342a359fe968348 100644 (file)
@@ -5843,6 +5843,3 @@ MODULE_FIRMWARE(FW_FILE_ISP2300);
 MODULE_FIRMWARE(FW_FILE_ISP2322);
 MODULE_FIRMWARE(FW_FILE_ISP24XX);
 MODULE_FIRMWARE(FW_FILE_ISP25XX);
-MODULE_FIRMWARE(FW_FILE_ISP2031);
-MODULE_FIRMWARE(FW_FILE_ISP8031);
-MODULE_FIRMWARE(FW_FILE_ISP27XX);
index d07fb653f5dc3348c41bbc68597489d2c4b25180..b1bf42b93fccb23249e4341e3ce56f6b8c84c5d5 100644 (file)
@@ -782,7 +782,7 @@ void scsi_attach_vpd(struct scsi_device *sdev)
        int vpd_len = SCSI_VPD_PG_LEN;
        int pg80_supported = 0;
        int pg83_supported = 0;
-       unsigned char *vpd_buf;
+       unsigned char __rcu *vpd_buf, *orig_vpd_buf = NULL;
 
        if (sdev->skip_vpd_pages)
                return;
@@ -828,8 +828,16 @@ retry_pg80:
                        kfree(vpd_buf);
                        goto retry_pg80;
                }
+               mutex_lock(&sdev->inquiry_mutex);
+               orig_vpd_buf = sdev->vpd_pg80;
                sdev->vpd_pg80_len = result;
-               sdev->vpd_pg80 = vpd_buf;
+               rcu_assign_pointer(sdev->vpd_pg80, vpd_buf);
+               mutex_unlock(&sdev->inquiry_mutex);
+               synchronize_rcu();
+               if (orig_vpd_buf) {
+                       kfree(orig_vpd_buf);
+                       orig_vpd_buf = NULL;
+               }
                vpd_len = SCSI_VPD_PG_LEN;
        }
 
@@ -849,8 +857,14 @@ retry_pg83:
                        kfree(vpd_buf);
                        goto retry_pg83;
                }
+               mutex_lock(&sdev->inquiry_mutex);
+               orig_vpd_buf = sdev->vpd_pg83;
                sdev->vpd_pg83_len = result;
-               sdev->vpd_pg83 = vpd_buf;
+               rcu_assign_pointer(sdev->vpd_pg83, vpd_buf);
+               mutex_unlock(&sdev->inquiry_mutex);
+               synchronize_rcu();
+               if (orig_vpd_buf)
+                       kfree(orig_vpd_buf);
        }
 }
 
index d09d60293c272663b5b9b84f27ce2fab3e61a6aa..f3d69a98c72521b39696ca6a688b3163f8288197 100644 (file)
@@ -129,7 +129,7 @@ static const char *scsi_debug_version_date = "20141022";
 #define DEF_NO_LUN_0   0
 #define DEF_NUM_PARTS   0
 #define DEF_OPTS   0
-#define DEF_OPT_BLKS 64
+#define DEF_OPT_BLKS 1024
 #define DEF_PHYSBLK_EXP 0
 #define DEF_PTYPE   0
 #define DEF_REMOVABLE false
@@ -679,7 +679,7 @@ static void *fake_store(unsigned long long lba)
 
 static struct sd_dif_tuple *dif_store(sector_t sector)
 {
-       sector = do_div(sector, sdebug_store_sectors);
+       sector = sector_div(sector, sdebug_store_sectors);
 
        return dif_storep + sector;
 }
@@ -2781,7 +2781,7 @@ static unsigned long lba_to_map_index(sector_t lba)
                lba += scsi_debug_unmap_granularity -
                        scsi_debug_unmap_alignment;
        }
-       do_div(lba, scsi_debug_unmap_granularity);
+       sector_div(lba, scsi_debug_unmap_granularity);
 
        return lba;
 }
@@ -4140,7 +4140,7 @@ MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
 MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
 MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
 MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
-MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
+MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
 MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
 MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
 MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
@@ -4847,10 +4847,10 @@ static int __init scsi_debug_init(void)
        /* play around with geometry, don't waste too much on track 0 */
        sdebug_heads = 8;
        sdebug_sectors_per = 32;
-       if (scsi_debug_dev_size_mb >= 16)
-               sdebug_heads = 32;
-       else if (scsi_debug_dev_size_mb >= 256)
+       if (scsi_debug_dev_size_mb >= 256)
                sdebug_heads = 64;
+       else if (scsi_debug_dev_size_mb >= 16)
+               sdebug_heads = 32;
        sdebug_cylinders_per = (unsigned long)sdebug_capacity /
                               (sdebug_sectors_per * sdebug_heads);
        if (sdebug_cylinders_per >= 1024) {
index e7649ed3f6677e69fe2e3644da24d99de2aa3181..54d446c9f56e0e77372f9fe67be14d04a96a3d53 100644 (file)
@@ -153,76 +153,11 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev)
        module_put(sdev->handler->module);
 }
 
-/*
- * Functions for sysfs attribute 'dh_state'
- */
-static ssize_t
-store_dh_state(struct device *dev, struct device_attribute *attr,
-              const char *buf, size_t count)
-{
-       struct scsi_device *sdev = to_scsi_device(dev);
-       struct scsi_device_handler *scsi_dh;
-       int err = -EINVAL;
-
-       if (sdev->sdev_state == SDEV_CANCEL ||
-           sdev->sdev_state == SDEV_DEL)
-               return -ENODEV;
-
-       if (!sdev->handler) {
-               /*
-                * Attach to a device handler
-                */
-               scsi_dh = scsi_dh_lookup(buf);
-               if (!scsi_dh)
-                       return err;
-               err = scsi_dh_handler_attach(sdev, scsi_dh);
-       } else {
-               if (!strncmp(buf, "detach", 6)) {
-                       /*
-                        * Detach from a device handler
-                        */
-                       sdev_printk(KERN_WARNING, sdev,
-                                   "can't detach handler %s.\n",
-                                   sdev->handler->name);
-                       err = -EINVAL;
-               } else if (!strncmp(buf, "activate", 8)) {
-                       /*
-                        * Activate a device handler
-                        */
-                       if (sdev->handler->activate)
-                               err = sdev->handler->activate(sdev, NULL, NULL);
-                       else
-                               err = 0;
-               }
-       }
-
-       return err<0?err:count;
-}
-
-static ssize_t
-show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct scsi_device *sdev = to_scsi_device(dev);
-
-       if (!sdev->handler)
-               return snprintf(buf, 20, "detached\n");
-
-       return snprintf(buf, 20, "%s\n", sdev->handler->name);
-}
-
-static struct device_attribute scsi_dh_state_attr =
-       __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
-              store_dh_state);
-
 int scsi_dh_add_device(struct scsi_device *sdev)
 {
        struct scsi_device_handler *devinfo = NULL;
        const char *drv;
-       int err;
-
-       err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
-       if (err)
-               return err;
+       int err = 0;
 
        drv = scsi_dh_find_driver(sdev);
        if (drv)
@@ -238,11 +173,6 @@ void scsi_dh_release_device(struct scsi_device *sdev)
                scsi_dh_handler_detach(sdev);
 }
 
-void scsi_dh_remove_device(struct scsi_device *sdev)
-{
-       device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
-}
-
 /*
  * scsi_register_device_handler - register a device handler personality
  *      module.
index dd8ad2a44510cae1b97260b7d64fc65e7770db53..fa6b2c4eb7a2b1dc620bcf22db3abf1001a7f3d3 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/scatterlist.h>
 #include <linux/blk-mq.h>
 #include <linux/ratelimit.h>
+#include <asm/unaligned.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -3154,3 +3155,190 @@ void sdev_enable_disk_events(struct scsi_device *sdev)
        atomic_dec(&sdev->disk_events_disable_depth);
 }
 EXPORT_SYMBOL(sdev_enable_disk_events);
+
+/**
+ * scsi_vpd_lun_id - return a unique device identification
+ * @sdev: SCSI device
+ * @id:   buffer for the identification
+ * @id_len:  length of the buffer
+ *
+ * Copies a unique device identification into @id based
+ * on the information in the VPD page 0x83 of the device.
+ * The string will be formatted as a SCSI name string.
+ *
+ * Returns the length of the identification or error on failure.
+ * If the identifier is longer than the supplied buffer the actual
+ * identifier length is returned and the buffer is not zero-padded.
+ */
+int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
+{
+       u8 cur_id_type = 0xff;
+       u8 cur_id_size = 0;
+       unsigned char *d, *cur_id_str;
+       unsigned char __rcu *vpd_pg83;
+       int id_size = -EINVAL;
+
+       rcu_read_lock();
+       vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+       if (!vpd_pg83) {
+               rcu_read_unlock();
+               return -ENXIO;
+       }
+
+       /*
+        * Look for the correct descriptor.
+        * Order of preference for lun descriptor:
+        * - SCSI name string
+        * - NAA IEEE Registered Extended
+        * - EUI-64 based 16-byte
+        * - EUI-64 based 12-byte
+        * - NAA IEEE Registered
+        * - NAA IEEE Extended
+        * as longer descriptors reduce the likelyhood
+        * of identification clashes.
+        */
+
+       /* The id string must be at least 20 bytes + terminating NULL byte */
+       if (id_len < 21) {
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+
+       memset(id, 0, id_len);
+       d = vpd_pg83 + 4;
+       while (d < vpd_pg83 + sdev->vpd_pg83_len) {
+               /* Skip designators not referring to the LUN */
+               if ((d[1] & 0x30) != 0x00)
+                       goto next_desig;
+
+               switch (d[1] & 0xf) {
+               case 0x2:
+                       /* EUI-64 */
+                       if (cur_id_size > d[3])
+                               break;
+                       /* Prefer NAA IEEE Registered Extended */
+                       if (cur_id_type == 0x3 &&
+                           cur_id_size == d[3])
+                               break;
+                       cur_id_size = d[3];
+                       cur_id_str = d + 4;
+                       cur_id_type = d[1] & 0xf;
+                       switch (cur_id_size) {
+                       case 8:
+                               id_size = snprintf(id, id_len,
+                                                  "eui.%8phN",
+                                                  cur_id_str);
+                               break;
+                       case 12:
+                               id_size = snprintf(id, id_len,
+                                                  "eui.%12phN",
+                                                  cur_id_str);
+                               break;
+                       case 16:
+                               id_size = snprintf(id, id_len,
+                                                  "eui.%16phN",
+                                                  cur_id_str);
+                               break;
+                       default:
+                               cur_id_size = 0;
+                               break;
+                       }
+                       break;
+               case 0x3:
+                       /* NAA */
+                       if (cur_id_size > d[3])
+                               break;
+                       cur_id_size = d[3];
+                       cur_id_str = d + 4;
+                       cur_id_type = d[1] & 0xf;
+                       switch (cur_id_size) {
+                       case 8:
+                               id_size = snprintf(id, id_len,
+                                                  "naa.%8phN",
+                                                  cur_id_str);
+                               break;
+                       case 16:
+                               id_size = snprintf(id, id_len,
+                                                  "naa.%16phN",
+                                                  cur_id_str);
+                               break;
+                       default:
+                               cur_id_size = 0;
+                               break;
+                       }
+                       break;
+               case 0x8:
+                       /* SCSI name string */
+                       if (cur_id_size + 4 > d[3])
+                               break;
+                       /* Prefer others for truncated descriptor */
+                       if (cur_id_size && d[3] > id_len)
+                               break;
+                       cur_id_size = id_size = d[3];
+                       cur_id_str = d + 4;
+                       cur_id_type = d[1] & 0xf;
+                       if (cur_id_size >= id_len)
+                               cur_id_size = id_len - 1;
+                       memcpy(id, cur_id_str, cur_id_size);
+                       /* Decrease priority for truncated descriptor */
+                       if (cur_id_size != id_size)
+                               cur_id_size = 6;
+                       break;
+               default:
+                       break;
+               }
+next_desig:
+               d += d[3] + 4;
+       }
+       rcu_read_unlock();
+
+       return id_size;
+}
+EXPORT_SYMBOL(scsi_vpd_lun_id);
+
+/*
+ * scsi_vpd_tpg_id - return a target port group identifier
+ * @sdev: SCSI device
+ *
+ * Returns the Target Port Group identifier from the information
+ * froom VPD page 0x83 of the device.
+ *
+ * Returns the identifier or error on failure.
+ */
+int scsi_vpd_tpg_id(struct scsi_device *sdev, int *rel_id)
+{
+       unsigned char *d;
+       unsigned char __rcu *vpd_pg83;
+       int group_id = -EAGAIN, rel_port = -1;
+
+       rcu_read_lock();
+       vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+       if (!vpd_pg83) {
+               rcu_read_unlock();
+               return -ENXIO;
+       }
+
+       d = sdev->vpd_pg83 + 4;
+       while (d < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
+               switch (d[1] & 0xf) {
+               case 0x4:
+                       /* Relative target port */
+                       rel_port = get_unaligned_be16(&d[6]);
+                       break;
+               case 0x5:
+                       /* Target port group */
+                       group_id = get_unaligned_be16(&d[6]);
+                       break;
+               default:
+                       break;
+               }
+               d += d[3] + 4;
+       }
+       rcu_read_unlock();
+
+       if (group_id >= 0 && rel_id && rel_port != -1)
+               *rel_id = rel_port;
+
+       return group_id;
+}
+EXPORT_SYMBOL(scsi_vpd_tpg_id);
index 4d01cdb1b348306807663467bf56c254f16b94df..27b4d0a6a01dbc2ad7c38f1645b5be35fa15fbd8 100644 (file)
@@ -174,12 +174,11 @@ extern struct async_domain scsi_sd_probe_domain;
 #ifdef CONFIG_SCSI_DH
 int scsi_dh_add_device(struct scsi_device *sdev);
 void scsi_dh_release_device(struct scsi_device *sdev);
-void scsi_dh_remove_device(struct scsi_device *sdev);
 #else
 static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; }
 static inline void scsi_dh_release_device(struct scsi_device *sdev) { }
-static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
 #endif
+static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
 
 /* 
  * internal scsi timeout functions: for use by mid-layer and transport
index 054923e3393c6f2dffd0959fea6ee610ecf177ac..6a820668d442f2e1b1d111ee652717e9ae0e896a 100644 (file)
@@ -236,6 +236,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        INIT_LIST_HEAD(&sdev->starved_entry);
        INIT_LIST_HEAD(&sdev->event_list);
        spin_lock_init(&sdev->list_lock);
+       mutex_init(&sdev->inquiry_mutex);
        INIT_WORK(&sdev->event_work, scsi_evt_thread);
        INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue);
 
@@ -1519,6 +1520,9 @@ EXPORT_SYMBOL(scsi_add_device);
 void scsi_rescan_device(struct device *dev)
 {
        device_lock(dev);
+
+       scsi_attach_vpd(to_scsi_device(dev));
+
        if (dev->driver && try_module_get(dev->driver->owner)) {
                struct scsi_driver *drv = to_scsi_driver(dev->driver);
 
index 21930c9ac9cd90caf6e5386b4495992fb3f8542d..4f18a851e2c7f7de25e590e9a6f93750150e5f37 100644 (file)
@@ -17,6 +17,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dh.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_driver.h>
 
@@ -760,11 +761,15 @@ show_vpd_##_page(struct file *filp, struct kobject *kobj, \
 {                                                                      \
        struct device *dev = container_of(kobj, struct device, kobj);   \
        struct scsi_device *sdev = to_scsi_device(dev);                 \
+       int ret;                                                        \
        if (!sdev->vpd_##_page)                                         \
                return -EINVAL;                                         \
-       return memory_read_from_buffer(buf, count, &off,                \
-                                      sdev->vpd_##_page,               \
+       rcu_read_lock();                                                \
+       ret = memory_read_from_buffer(buf, count, &off,                 \
+                                     rcu_dereference(sdev->vpd_##_page), \
                                       sdev->vpd_##_page##_len);        \
+       rcu_read_unlock();                                              \
+       return ret;                                             \
 }                                                                      \
 static struct bin_attribute dev_attr_vpd_##_page = {           \
        .attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO },   \
@@ -900,6 +905,76 @@ sdev_show_function(queue_depth, "%d\n");
 static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
                   sdev_store_queue_depth);
 
+static ssize_t
+sdev_show_wwid(struct device *dev, struct device_attribute *attr,
+                   char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       ssize_t count;
+
+       count = scsi_vpd_lun_id(sdev, buf, PAGE_SIZE);
+       if (count > 0) {
+               buf[count] = '\n';
+               count++;
+       }
+       return count;
+}
+static DEVICE_ATTR(wwid, S_IRUGO, sdev_show_wwid, NULL);
+
+#ifdef CONFIG_SCSI_DH
+static ssize_t
+sdev_show_dh_state(struct device *dev, struct device_attribute *attr,
+                  char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+
+       if (!sdev->handler)
+               return snprintf(buf, 20, "detached\n");
+
+       return snprintf(buf, 20, "%s\n", sdev->handler->name);
+}
+
+static ssize_t
+sdev_store_dh_state(struct device *dev, struct device_attribute *attr,
+                   const char *buf, size_t count)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       int err = -EINVAL;
+
+       if (sdev->sdev_state == SDEV_CANCEL ||
+           sdev->sdev_state == SDEV_DEL)
+               return -ENODEV;
+
+       if (!sdev->handler) {
+               /*
+                * Attach to a device handler
+                */
+               err = scsi_dh_attach(sdev->request_queue, buf);
+       } else if (!strncmp(buf, "activate", 8)) {
+               /*
+                * Activate a device handler
+                */
+               if (sdev->handler->activate)
+                       err = sdev->handler->activate(sdev, NULL, NULL);
+               else
+                       err = 0;
+       } else if (!strncmp(buf, "detach", 6)) {
+               /*
+                * Detach from a device handler
+                */
+               sdev_printk(KERN_WARNING, sdev,
+                           "can't detach handler %s.\n",
+                           sdev->handler->name);
+               err = -EINVAL;
+       }
+
+       return err < 0 ? err : count;
+}
+
+static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state,
+                  sdev_store_dh_state);
+#endif
+
 static ssize_t
 sdev_show_queue_ramp_up_period(struct device *dev,
                               struct device_attribute *attr,
@@ -969,6 +1044,10 @@ static struct attribute *scsi_sdev_attrs[] = {
        &dev_attr_modalias.attr,
        &dev_attr_queue_depth.attr,
        &dev_attr_queue_type.attr,
+       &dev_attr_wwid.attr,
+#ifdef CONFIG_SCSI_DH
+       &dev_attr_dh_state.attr,
+#endif
        &dev_attr_queue_ramp_up_period.attr,
        REF_EVT(media_change),
        REF_EVT(inquiry_change_reported),
@@ -1058,11 +1137,12 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
        }
 
        error = scsi_dh_add_device(sdev);
-       if (error) {
+       if (error)
+               /*
+                * device_handler is optional, so any error can be ignored
+                */
                sdev_printk(KERN_INFO, sdev,
                                "failed to add device handler: %d\n", error);
-               return error;
-       }
 
        device_enable_async_suspend(&sdev->sdev_dev);
        error = device_add(&sdev->sdev_dev);
index 24eaaf66af710042d9a96c71c93b5930721a5a9e..8a8822641b266399aae02491875ea15fe7f3bc52 100644 (file)
@@ -2586,7 +2586,7 @@ fc_rport_final_delete(struct work_struct *work)
        transport_remove_device(dev);
        device_del(dev);
        transport_destroy_device(dev);
-       put_device(&shost->shost_gendev);       /* for fc_host->rport list */
+       scsi_host_put(shost);                   /* for fc_host->rport list */
        put_device(dev);                        /* for self-reference */
 }
 
@@ -2650,7 +2650,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
        else
                rport->scsi_target_id = -1;
        list_add_tail(&rport->peers, &fc_host->rports);
-       get_device(&shost->shost_gendev);       /* for fc_host->rport list */
+       scsi_host_get(shost);                   /* for fc_host->rport list */
 
        spin_unlock_irqrestore(shost->host_lock, flags);
 
@@ -2685,7 +2685,7 @@ delete_rport:
        transport_destroy_device(dev);
        spin_lock_irqsave(shost->host_lock, flags);
        list_del(&rport->peers);
-       put_device(&shost->shost_gendev);       /* for fc_host->rport list */
+       scsi_host_put(shost);                   /* for fc_host->rport list */
        spin_unlock_irqrestore(shost->host_lock, flags);
        put_device(dev->parent);
        kfree(rport);
@@ -3383,7 +3383,7 @@ fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev,
        fc_host->npiv_vports_inuse++;
        vport->number = fc_host->next_vport_number++;
        list_add_tail(&vport->peers, &fc_host->vports);
-       get_device(&shost->shost_gendev);       /* for fc_host->vport list */
+       scsi_host_get(shost);                   /* for fc_host->vport list */
 
        spin_unlock_irqrestore(shost->host_lock, flags);
 
@@ -3441,7 +3441,7 @@ delete_vport:
        transport_destroy_device(dev);
        spin_lock_irqsave(shost->host_lock, flags);
        list_del(&vport->peers);
-       put_device(&shost->shost_gendev);       /* for fc_host->vport list */
+       scsi_host_put(shost);                   /* for fc_host->vport list */
        fc_host->npiv_vports_inuse--;
        spin_unlock_irqrestore(shost->host_lock, flags);
        put_device(dev->parent);
@@ -3504,7 +3504,7 @@ fc_vport_terminate(struct fc_vport *vport)
                vport->flags |= FC_VPORT_DELETED;
                list_del(&vport->peers);
                fc_host->npiv_vports_inuse--;
-               put_device(&shost->shost_gendev);  /* for fc_host->vport list */
+               scsi_host_put(shost);           /* for fc_host->vport list */
        }
        spin_unlock_irqrestore(shost->host_lock, flags);
 
index b6486b5d8681122759ae9bd3d5ca8e59542231a9..8c732c8de0153eb1b1da0402136c7ba568ec2fb7 100644 (file)
@@ -148,8 +148,6 @@ struct scsi_tape {
        int tape_type;
        int long_timeout;       /* timeout for commands known to take long time */
 
-       unsigned long max_pfn;  /* the maximum page number reachable by the HBA */
-
        /* Mode characteristics */
        struct st_modedef modes[ST_NBR_MODES];
        int current_mode;
index 3fba42ad9fb8aee55d5015167a9cb9ad601fb1a7..41c115c230d9bf66da94693597967d037fdefaf6 100644 (file)
@@ -41,6 +41,7 @@
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_devinfo.h>
 #include <scsi/scsi_dbg.h>
+#include <scsi/scsi_transport_fc.h>
 
 /*
  * All wire protocol details (storage protocol between the guest and the host)
@@ -92,9 +93,8 @@ enum vstor_packet_operation {
  */
 
 struct hv_fc_wwn_packet {
-       bool    primary_active;
-       u8      reserved1;
-       u8      reserved2;
+       u8      primary_active;
+       u8      reserved1[3];
        u8      primary_port_wwn[8];
        u8      primary_node_wwn[8];
        u8      secondary_port_wwn[8];
@@ -164,6 +164,26 @@ static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
 */
 static int vmstor_proto_version;
 
+#define STORVSC_LOGGING_NONE   0
+#define STORVSC_LOGGING_ERROR  1
+#define STORVSC_LOGGING_WARN   2
+
+static int logging_level = STORVSC_LOGGING_ERROR;
+module_param(logging_level, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(logging_level,
+       "Logging level, 0 - None, 1 - Error (default), 2 - Warning.");
+
+static inline bool do_logging(int level)
+{
+       return logging_level >= level;
+}
+
+#define storvsc_log(dev, level, fmt, ...)                      \
+do {                                                           \
+       if (do_logging(level))                                  \
+               dev_warn(&(dev)->device, fmt, ##__VA_ARGS__);   \
+} while (0)
+
 struct vmscsi_win8_extension {
        /*
         * The following were added in Windows 8
@@ -378,6 +398,9 @@ static int storvsc_timeout = 180;
 
 static int msft_blist_flags = BLIST_TRY_VPD_PAGES;
 
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct scsi_transport_template *fc_transport_template;
+#endif
 
 static void storvsc_on_channel_callback(void *context);
 
@@ -437,6 +460,11 @@ struct storvsc_device {
        /* Used for vsc/vsp channel reset process */
        struct storvsc_cmd_request init_request;
        struct storvsc_cmd_request reset_request;
+       /*
+        * Currently active port and node names for FC devices.
+        */
+       u64 node_name;
+       u64 port_name;
 };
 
 struct hv_host_device {
@@ -676,29 +704,36 @@ static void  handle_multichannel_storage(struct hv_device *device, int max_chns)
        vmbus_are_subchannels_present(device->channel);
 }
 
-static int storvsc_channel_init(struct hv_device *device)
+static void cache_wwn(struct storvsc_device *stor_device,
+                     struct vstor_packet *vstor_packet)
 {
-       struct storvsc_device *stor_device;
-       struct storvsc_cmd_request *request;
-       struct vstor_packet *vstor_packet;
-       int ret, t, i;
-       int max_chns;
-       bool process_sub_channels = false;
+       /*
+        * Cache the currently active port and node ww names.
+        */
+       if (vstor_packet->wwn_packet.primary_active) {
+               stor_device->node_name =
+                       wwn_to_u64(vstor_packet->wwn_packet.primary_node_wwn);
+               stor_device->port_name =
+                       wwn_to_u64(vstor_packet->wwn_packet.primary_port_wwn);
+       } else {
+               stor_device->node_name =
+                       wwn_to_u64(vstor_packet->wwn_packet.secondary_node_wwn);
+               stor_device->port_name =
+                       wwn_to_u64(vstor_packet->wwn_packet.secondary_port_wwn);
+       }
+}
 
-       stor_device = get_out_stor_device(device);
-       if (!stor_device)
-               return -ENODEV;
 
-       request = &stor_device->init_request;
+static int storvsc_execute_vstor_op(struct hv_device *device,
+                                   struct storvsc_cmd_request *request,
+                                   bool status_check)
+{
+       struct vstor_packet *vstor_packet;
+       int ret, t;
+
        vstor_packet = &request->vstor_packet;
 
-       /*
-        * Now, initiate the vsc/vsp initialization protocol on the open
-        * channel
-        */
-       memset(request, 0, sizeof(struct storvsc_cmd_request));
        init_completion(&request->wait_event);
-       vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
        vstor_packet->flags = REQUEST_COMPLETION_FLAG;
 
        ret = vmbus_sendpacket(device->channel, vstor_packet,
@@ -708,27 +743,56 @@ static int storvsc_channel_init(struct hv_device *device)
                               VM_PKT_DATA_INBAND,
                               VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
        if (ret != 0)
-               goto cleanup;
+               return ret;
 
        t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-       if (t == 0) {
-               ret = -ETIMEDOUT;
-               goto cleanup;
-       }
+       if (t == 0)
+               return -ETIMEDOUT;
+
+       if (!status_check)
+               return ret;
 
        if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-           vstor_packet->status != 0) {
-               ret = -EINVAL;
-               goto cleanup;
-       }
+           vstor_packet->status != 0)
+               return -EINVAL;
+
+       return ret;
+}
+
+static int storvsc_channel_init(struct hv_device *device, bool is_fc)
+{
+       struct storvsc_device *stor_device;
+       struct storvsc_cmd_request *request;
+       struct vstor_packet *vstor_packet;
+       int ret, i;
+       int max_chns;
+       bool process_sub_channels = false;
 
+       stor_device = get_out_stor_device(device);
+       if (!stor_device)
+               return -ENODEV;
+
+       request = &stor_device->init_request;
+       vstor_packet = &request->vstor_packet;
+
+       /*
+        * Now, initiate the vsc/vsp initialization protocol on the open
+        * channel
+        */
+       memset(request, 0, sizeof(struct storvsc_cmd_request));
+       vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
+       ret = storvsc_execute_vstor_op(device, request, true);
+       if (ret)
+               return ret;
+       /*
+        * Query host supported protocol version.
+        */
 
        for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) {
                /* reuse the packet for version range supported */
                memset(vstor_packet, 0, sizeof(struct vstor_packet));
                vstor_packet->operation =
                        VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
-               vstor_packet->flags = REQUEST_COMPLETION_FLAG;
 
                vstor_packet->version.major_minor =
                        vmstor_protocols[i].protocol_version;
@@ -737,26 +801,12 @@ static int storvsc_channel_init(struct hv_device *device)
                 * The revision number is only used in Windows; set it to 0.
                 */
                vstor_packet->version.revision = 0;
-
-               ret = vmbus_sendpacket(device->channel, vstor_packet,
-                              (sizeof(struct vstor_packet) -
-                               vmscsi_size_delta),
-                              (unsigned long)request,
-                              VM_PKT_DATA_INBAND,
-                              VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+               ret = storvsc_execute_vstor_op(device, request, false);
                if (ret != 0)
-                       goto cleanup;
+                       return ret;
 
-               t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-               if (t == 0) {
-                       ret = -ETIMEDOUT;
-                       goto cleanup;
-               }
-
-               if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO) {
-                       ret = -EINVAL;
-                       goto cleanup;
-               }
+               if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO)
+                       return -EINVAL;
 
                if (vstor_packet->status == 0) {
                        vmstor_proto_version =
@@ -772,37 +822,15 @@ static int storvsc_channel_init(struct hv_device *device)
                }
        }
 
-       if (vstor_packet->status != 0) {
-               ret = -EINVAL;
-               goto cleanup;
-       }
+       if (vstor_packet->status != 0)
+               return -EINVAL;
 
 
        memset(vstor_packet, 0, sizeof(struct vstor_packet));
        vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
-       vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
-       ret = vmbus_sendpacket(device->channel, vstor_packet,
-                              (sizeof(struct vstor_packet) -
-                               vmscsi_size_delta),
-                              (unsigned long)request,
-                              VM_PKT_DATA_INBAND,
-                              VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
+       ret = storvsc_execute_vstor_op(device, request, true);
        if (ret != 0)
-               goto cleanup;
-
-       t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-       if (t == 0) {
-               ret = -ETIMEDOUT;
-               goto cleanup;
-       }
-
-       if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-           vstor_packet->status != 0) {
-               ret = -EINVAL;
-               goto cleanup;
-       }
+               return ret;
 
        /*
         * Check to see if multi-channel support is there.
@@ -818,37 +846,34 @@ static int storvsc_channel_init(struct hv_device *device)
        stor_device->max_transfer_bytes =
                vstor_packet->storage_channel_properties.max_transfer_bytes;
 
-       memset(vstor_packet, 0, sizeof(struct vstor_packet));
-       vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
-       vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
-       ret = vmbus_sendpacket(device->channel, vstor_packet,
-                              (sizeof(struct vstor_packet) -
-                               vmscsi_size_delta),
-                              (unsigned long)request,
-                              VM_PKT_DATA_INBAND,
-                              VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+       if (!is_fc)
+               goto done;
 
+       /*
+        * For FC devices retrieve FC HBA data.
+        */
+       memset(vstor_packet, 0, sizeof(struct vstor_packet));
+       vstor_packet->operation = VSTOR_OPERATION_FCHBA_DATA;
+       ret = storvsc_execute_vstor_op(device, request, true);
        if (ret != 0)
-               goto cleanup;
+               return ret;
 
-       t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
-       if (t == 0) {
-               ret = -ETIMEDOUT;
-               goto cleanup;
-       }
+       /*
+        * Cache the currently active port and node ww names.
+        */
+       cache_wwn(stor_device, vstor_packet);
 
-       if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
-           vstor_packet->status != 0) {
-               ret = -EINVAL;
-               goto cleanup;
-       }
+done:
+
+       memset(vstor_packet, 0, sizeof(struct vstor_packet));
+       vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
+       ret = storvsc_execute_vstor_op(device, request, true);
+       if (ret != 0)
+               return ret;
 
        if (process_sub_channels)
                handle_multichannel_storage(device, max_chns);
 
-
-cleanup:
        return ret;
 }
 
@@ -920,19 +945,16 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
 }
 
 
-static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
+                                      struct storvsc_device *stor_dev)
 {
        struct scsi_cmnd *scmnd = cmd_request->cmd;
-       struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
        struct scsi_sense_hdr sense_hdr;
        struct vmscsi_request *vm_srb;
        struct Scsi_Host *host;
-       struct storvsc_device *stor_dev;
-       struct hv_device *dev = host_dev->dev;
        u32 payload_sz = cmd_request->payload_sz;
        void *payload = cmd_request->payload;
 
-       stor_dev = get_in_stor_device(dev);
        host = stor_dev->host;
 
        vm_srb = &cmd_request->vstor_packet.vm_srb;
@@ -941,7 +963,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))
+                               SCSI_SENSE_BUFFERSIZE, &sense_hdr) &&
+                   do_logging(STORVSC_LOGGING_ERROR))
                        scsi_print_sense_hdr(scmnd->device, "storvsc",
                                             &sense_hdr);
        }
@@ -961,14 +984,13 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
                kfree(payload);
 }
 
-static void storvsc_on_io_completion(struct hv_device *device,
+static void storvsc_on_io_completion(struct storvsc_device *stor_device,
                                  struct vstor_packet *vstor_packet,
                                  struct storvsc_cmd_request *request)
 {
-       struct storvsc_device *stor_device;
        struct vstor_packet *stor_pkt;
+       struct hv_device *device = stor_device->device;
 
-       stor_device = hv_get_drvdata(device);
        stor_pkt = &request->vstor_packet;
 
        /*
@@ -995,6 +1017,13 @@ static void storvsc_on_io_completion(struct hv_device *device,
        stor_pkt->vm_srb.sense_info_length =
        vstor_packet->vm_srb.sense_info_length;
 
+       if (vstor_packet->vm_srb.scsi_status != 0 ||
+           vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS)
+               storvsc_log(device, STORVSC_LOGGING_WARN,
+                       "cmd 0x%x scsi status 0x%x srb status 0x%x\n",
+                       stor_pkt->vm_srb.cdb[0],
+                       vstor_packet->vm_srb.scsi_status,
+                       vstor_packet->vm_srb.srb_status);
 
        if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
                /* CHECK_CONDITION */
@@ -1002,6 +1031,10 @@ static void storvsc_on_io_completion(struct hv_device *device,
                        SRB_STATUS_AUTOSENSE_VALID) {
                        /* autosense data available */
 
+                       storvsc_log(device, STORVSC_LOGGING_WARN,
+                               "stor pkt %p autosense data valid - len %d\n",
+                               request, vstor_packet->vm_srb.sense_info_length);
+
                        memcpy(request->cmd->sense_buffer,
                               vstor_packet->vm_srb.sense_data,
                               vstor_packet->vm_srb.sense_info_length);
@@ -1012,7 +1045,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
        stor_pkt->vm_srb.data_transfer_length =
        vstor_packet->vm_srb.data_transfer_length;
 
-       storvsc_command_completion(request);
+       storvsc_command_completion(request, stor_device);
 
        if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
                stor_device->drain_notify)
@@ -1021,21 +1054,19 @@ static void storvsc_on_io_completion(struct hv_device *device,
 
 }
 
-static void storvsc_on_receive(struct hv_device *device,
+static void storvsc_on_receive(struct storvsc_device *stor_device,
                             struct vstor_packet *vstor_packet,
                             struct storvsc_cmd_request *request)
 {
        struct storvsc_scan_work *work;
-       struct storvsc_device *stor_device;
 
        switch (vstor_packet->operation) {
        case VSTOR_OPERATION_COMPLETE_IO:
-               storvsc_on_io_completion(device, vstor_packet, request);
+               storvsc_on_io_completion(stor_device, vstor_packet, request);
                break;
 
        case VSTOR_OPERATION_REMOVE_DEVICE:
        case VSTOR_OPERATION_ENUMERATE_BUS:
-               stor_device = get_in_stor_device(device);
                work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC);
                if (!work)
                        return;
@@ -1045,6 +1076,13 @@ static void storvsc_on_receive(struct hv_device *device,
                schedule_work(&work->work);
                break;
 
+       case VSTOR_OPERATION_FCHBA_DATA:
+               cache_wwn(stor_device, vstor_packet);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+               fc_host_node_name(stor_device->host) = stor_device->node_name;
+               fc_host_port_name(stor_device->host) = stor_device->port_name;
+#endif
+               break;
        default:
                break;
        }
@@ -1088,7 +1126,7 @@ static void storvsc_on_channel_callback(void *context)
                                        vmscsi_size_delta));
                                complete(&request->wait_event);
                        } else {
-                               storvsc_on_receive(device,
+                               storvsc_on_receive(stor_device,
                                                (struct vstor_packet *)packet,
                                                request);
                        }
@@ -1100,7 +1138,8 @@ static void storvsc_on_channel_callback(void *context)
        return;
 }
 
-static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
+static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
+                                 bool is_fc)
 {
        struct vmstorage_channel_properties props;
        int ret;
@@ -1117,7 +1156,7 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
        if (ret != 0)
                return ret;
 
-       ret = storvsc_channel_init(device);
+       ret = storvsc_channel_init(device, is_fc);
 
        return ret;
 }
@@ -1542,6 +1581,7 @@ static int storvsc_probe(struct hv_device *device,
        struct Scsi_Host *host;
        struct hv_host_device *host_dev;
        bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
+       bool is_fc = ((dev_id->driver_data == SFC_GUID) ? true : false);
        int target = 0;
        struct storvsc_device *stor_device;
        int max_luns_per_target;
@@ -1599,7 +1639,7 @@ static int storvsc_probe(struct hv_device *device,
        hv_set_drvdata(device, stor_device);
 
        stor_device->port_number = host->host_no;
-       ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size);
+       ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc);
        if (ret)
                goto err_out1;
 
@@ -1611,6 +1651,9 @@ static int storvsc_probe(struct hv_device *device,
                host->max_lun = STORVSC_FC_MAX_LUNS_PER_TARGET;
                host->max_id = STORVSC_FC_MAX_TARGETS;
                host->max_channel = STORVSC_FC_MAX_CHANNELS - 1;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+               host->transportt = fc_transport_template;
+#endif
                break;
 
        case SCSI_GUID:
@@ -1650,6 +1693,12 @@ static int storvsc_probe(struct hv_device *device,
                        goto err_out2;
                }
        }
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+       if (host->transportt == fc_transport_template) {
+               fc_host_node_name(host) = stor_device->node_name;
+               fc_host_port_name(host) = stor_device->port_name;
+       }
+#endif
        return 0;
 
 err_out2:
@@ -1675,6 +1724,10 @@ static int storvsc_remove(struct hv_device *dev)
        struct storvsc_device *stor_device = hv_get_drvdata(dev);
        struct Scsi_Host *host = stor_device->host;
 
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+       if (host->transportt == fc_transport_template)
+               fc_remove_host(host);
+#endif
        scsi_remove_host(host);
        storvsc_dev_remove(dev);
        scsi_host_put(host);
@@ -1689,8 +1742,16 @@ static struct hv_driver storvsc_drv = {
        .remove = storvsc_remove,
 };
 
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct fc_function_template fc_transport_functions = {
+       .show_host_node_name = 1,
+       .show_host_port_name = 1,
+};
+#endif
+
 static int __init storvsc_drv_init(void)
 {
+       int ret;
 
        /*
         * Divide the ring buffer data size (which is 1 page less
@@ -1705,12 +1766,28 @@ static int __init storvsc_drv_init(void)
                vmscsi_size_delta,
                sizeof(u64)));
 
-       return vmbus_driver_register(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+       fc_transport_template = fc_attach_transport(&fc_transport_functions);
+       if (!fc_transport_template)
+               return -ENODEV;
+#endif
+
+       ret = vmbus_driver_register(&storvsc_drv);
+
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+       if (ret)
+               fc_release_transport(fc_transport_template);
+#endif
+
+       return ret;
 }
 
 static void __exit storvsc_drv_exit(void)
 {
        vmbus_driver_unregister(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+       fc_release_transport(fc_transport_template);
+#endif
 }
 
 MODULE_LICENSE("GPL");
index 9714f2a8b32977d7394838c888bda8b64c1210ef..d2a7b127b05c19e259c5dca4a4771bdfdb97b5f5 100644 (file)
@@ -333,7 +333,7 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
 
        err = ufshcd_init(hba, mmio_base, irq);
        if (err) {
-               dev_err(dev, "Intialization failed\n");
+               dev_err(dev, "Initialization failed\n");
                goto out_disable_rpm;
        }
 
index 0f133c1817de3421bb74133a8a48e79d9e0c3c3d..6164634aff1895b208e919ffd47b6aaf59ca5e91 100644 (file)
@@ -349,9 +349,9 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx,
  * Map all data buffers for a command into PCI space and
  * setup the scatter/gather list if needed.
  */
-static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
-                              struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
-                              struct PVSCSIRingReqDesc *e)
+static int pvscsi_map_buffers(struct pvscsi_adapter *adapter,
+                             struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
+                             struct PVSCSIRingReqDesc *e)
 {
        unsigned count;
        unsigned bufflen = scsi_bufflen(cmd);
@@ -360,18 +360,30 @@ static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
        e->dataLen = bufflen;
        e->dataAddr = 0;
        if (bufflen == 0)
-               return;
+               return 0;
 
        sg = scsi_sglist(cmd);
        count = scsi_sg_count(cmd);
        if (count != 0) {
                int segs = scsi_dma_map(cmd);
-               if (segs > 1) {
+
+               if (segs == -ENOMEM) {
+                       scmd_printk(KERN_ERR, cmd,
+                                   "vmw_pvscsi: Failed to map cmd sglist for DMA.\n");
+                       return -ENOMEM;
+               } else if (segs > 1) {
                        pvscsi_create_sg(ctx, sg, segs);
 
                        e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
                        ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl,
                                                    SGL_SIZE, PCI_DMA_TODEVICE);
+                       if (pci_dma_mapping_error(adapter->dev, ctx->sglPA)) {
+                               scmd_printk(KERN_ERR, cmd,
+                                           "vmw_pvscsi: Failed to map ctx sglist for DMA.\n");
+                               scsi_dma_unmap(cmd);
+                               ctx->sglPA = 0;
+                               return -ENOMEM;
+                       }
                        e->dataAddr = ctx->sglPA;
                } else
                        e->dataAddr = sg_dma_address(sg);
@@ -382,8 +394,15 @@ static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
                 */
                ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen,
                                             cmd->sc_data_direction);
+               if (pci_dma_mapping_error(adapter->dev, ctx->dataPA)) {
+                       scmd_printk(KERN_ERR, cmd,
+                                   "vmw_pvscsi: Failed to map direct data buffer for DMA.\n");
+                       return -ENOMEM;
+               }
                e->dataAddr = ctx->dataPA;
        }
+
+       return 0;
 }
 
 static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter,
@@ -690,6 +709,12 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
                ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer,
                                              SCSI_SENSE_BUFFERSIZE,
                                              PCI_DMA_FROMDEVICE);
+               if (pci_dma_mapping_error(adapter->dev, ctx->sensePA)) {
+                       scmd_printk(KERN_ERR, cmd,
+                                   "vmw_pvscsi: Failed to map sense buffer for DMA.\n");
+                       ctx->sensePA = 0;
+                       return -ENOMEM;
+               }
                e->senseAddr = ctx->sensePA;
                e->senseLen = SCSI_SENSE_BUFFERSIZE;
        } else {
@@ -711,7 +736,15 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
        else
                e->flags = 0;
 
-       pvscsi_map_buffers(adapter, ctx, cmd, e);
+       if (pvscsi_map_buffers(adapter, ctx, cmd, e) != 0) {
+               if (cmd->sense_buffer) {
+                       pci_unmap_single(adapter->dev, ctx->sensePA,
+                                        SCSI_SENSE_BUFFERSIZE,
+                                        PCI_DMA_FROMDEVICE);
+                       ctx->sensePA = 0;
+               }
+               return -ENOMEM;
+       }
 
        e->context = pvscsi_map_context(adapter, ctx);
 
index ee16f0c5c47d06acb040561859e4fe62e1ed0111..12712c92f37ac27d30796231862de2121c54f4b0 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <linux/types.h>
 
-#define PVSCSI_DRIVER_VERSION_STRING   "1.0.5.0-k"
+#define PVSCSI_DRIVER_VERSION_STRING   "1.0.6.0-k"
 
 #define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128
 
index 0d2607d1238753f951e43e6b278735971413423c..42a84ef42683adaf12b14f743e39a136745e7d40 100644 (file)
@@ -344,6 +344,43 @@ struct ssp_response_iu {
        u8     sense_data[0];
 } __attribute__ ((packed));
 
+struct ssp_command_iu {
+       u8     lun[8];
+       u8     _r_a;
+
+       union {
+               struct {
+                       u8  attr:3;
+                       u8  prio:4;
+                       u8  efb:1;
+               };
+               u8 efb_prio_attr;
+       };
+
+       u8    _r_b;
+
+       u8    _r_c:2;
+       u8    add_cdb_len:6;
+
+       u8    cdb[16];
+       u8    add_cdb[0];
+} __attribute__ ((packed));
+
+struct xfer_rdy_iu {
+       __be32 requested_offset;
+       __be32 write_data_len;
+       __be32 _r_a;
+} __attribute__ ((packed));
+
+struct ssp_tmf_iu {
+       u8     lun[8];
+       u16    _r_a;
+       u8     tmf;
+       u8     _r_b;
+       __be16 tag;
+       u8     _r_c[14];
+} __attribute__ ((packed));
+
 /* ---------- SMP ---------- */
 
 struct report_general_resp {
@@ -538,6 +575,43 @@ struct ssp_response_iu {
        u8     sense_data[0];
 } __attribute__ ((packed));
 
+struct ssp_command_iu {
+       u8     lun[8];
+       u8     _r_a;
+
+       union {
+               struct {
+                       u8  efb:1;
+                       u8  prio:4;
+                       u8  attr:3;
+               };
+               u8 efb_prio_attr;
+       };
+
+       u8    _r_b;
+
+       u8    add_cdb_len:6;
+       u8    _r_c:2;
+
+       u8    cdb[16];
+       u8    add_cdb[0];
+} __attribute__ ((packed));
+
+struct xfer_rdy_iu {
+       __be32 requested_offset;
+       __be32 write_data_len;
+       __be32 _r_a;
+} __attribute__ ((packed));
+
+struct ssp_tmf_iu {
+       u8     lun[8];
+       u16    _r_a;
+       u8     tmf;
+       u8     _r_b;
+       __be16 tag;
+       u8     _r_c[14];
+} __attribute__ ((packed));
+
 /* ---------- SMP ---------- */
 
 struct report_general_resp {
index f8170e90b49d25fc15d6ee61617509e315466fc3..56710e03101c6d854b42685bb529461666ec9800 100644 (file)
@@ -12,8 +12,6 @@ extern size_t __scsi_format_command(char *, size_t,
                                   const unsigned char *, size_t);
 extern void scsi_show_extd_sense(const struct scsi_device *, const char *,
                                 unsigned char, unsigned char);
-extern void scsi_show_sense_hdr(const struct scsi_device *, const char *,
-                               const struct scsi_sense_hdr *);
 extern void scsi_print_sense_hdr(const struct scsi_device *, const char *,
                                 const struct scsi_sense_hdr *);
 extern void scsi_print_sense(const struct scsi_cmnd *);
index fe89d7cd67b9d3cfdcacddc6e17bb9366de38c0f..f63a16760ae90a2d9e4887bc6874dbe2dd7bcfc9 100644 (file)
@@ -109,6 +109,7 @@ struct scsi_device {
        char type;
        char scsi_level;
        char inq_periph_qual;   /* PQ from INQUIRY data */      
+       struct mutex inquiry_mutex;
        unsigned char inquiry_len;      /* valid bytes in 'inquiry' */
        unsigned char * inquiry;        /* INQUIRY response data */
        const char * vendor;            /* [back_compat] point into 'inquiry' ... */
@@ -117,9 +118,9 @@ struct scsi_device {
 
 #define SCSI_VPD_PG_LEN                255
        int vpd_pg83_len;
-       unsigned char *vpd_pg83;
+       unsigned char __rcu *vpd_pg83;
        int vpd_pg80_len;
-       unsigned char *vpd_pg80;
+       unsigned char __rcu *vpd_pg80;
        unsigned char current_tag;      /* current tag */
        struct scsi_target      *sdev_target;   /* used only for single_lun */
 
@@ -414,6 +415,8 @@ static inline int scsi_execute_req(struct scsi_device *sdev,
 }
 extern void sdev_disable_disk_events(struct scsi_device *sdev);
 extern void sdev_enable_disk_events(struct scsi_device *sdev);
+extern int scsi_vpd_lun_id(struct scsi_device *, char *, size_t);
+extern int scsi_vpd_tpg_id(struct scsi_device *, int *);
 
 #ifdef CONFIG_PM
 extern int scsi_autopm_get_device(struct scsi_device *);
index 831351b2e66022ee66f56bc2b8fe9c2f9fd7347f..2302f3ce5f860fcc94ae2f86fd1fcaea41a6a876 100644 (file)
@@ -30,6 +30,16 @@ struct dk_cxlflash_hdr {
        __u64 return_flags;             /* Returned flags */
 };
 
+/*
+ * Return flag definitions available to all ioctls
+ *
+ * Similar to the input flags, these are grown from the bottom-up with the
+ * intention that ioctl-specific return flag definitions would grow from the
+ * top-down, allowing the two sets to co-exist. While not required/enforced
+ * at this time, this provides future flexibility.
+ */
+#define DK_CXLFLASH_ALL_PORTS_ACTIVE   0x0000000000000001ULL
+
 /*
  * Notes:
  * -----