[SCSI] mvsas: split driver into multiple files
authorJeff Garzik <jeff@garzik.org>
Fri, 8 May 2009 21:44:01 +0000 (17:44 -0400)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Wed, 20 May 2009 22:21:12 +0000 (17:21 -0500)
Split mvsas driver into multiple source codes, based on the split
and function distribution found in Marvell's mvsas update.

Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/scsi/mvsas/Makefile
drivers/scsi/mvsas/mv_64xx.c [new file with mode: 0644]
drivers/scsi/mvsas/mv_64xx.h [new file with mode: 0644]
drivers/scsi/mvsas/mv_chips.h [new file with mode: 0644]
drivers/scsi/mvsas/mv_defs.h [new file with mode: 0644]
drivers/scsi/mvsas/mv_init.c [new file with mode: 0644]
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h [new file with mode: 0644]

index 1ac6ed9..a1ca681 100644 (file)
@@ -22,5 +22,6 @@
 # USA
 
 obj-$(CONFIG_SCSI_MVSAS) += mvsas.o
-mvsas-y +=  mv_sas.o
-
+mvsas-y +=  mv_init.o  \
+           mv_sas.o   \
+           mv_64xx.o
diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c
new file mode 100644 (file)
index 0000000..697806c
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+       mv_64xx.c - Marvell 88SE6440 SAS/SATA support
+
+       Copyright 2007 Red Hat, Inc.
+       Copyright 2008 Marvell. <kewei@marvell.com>
+
+       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,
+       or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty
+       of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+       See the GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public
+       License along with this program; see the file COPYING.  If not,
+       write to the Free Software Foundation, 675 Mass Ave, Cambridge,
+       MA 02139, USA.
+
+ */
+
+#include "mv_sas.h"
+#include "mv_64xx.h"
+#include "mv_chips.h"
+
+void mvs_detect_porttype(struct mvs_info *mvi, int i)
+{
+       void __iomem *regs = mvi->regs;
+       u32 reg;
+       struct mvs_phy *phy = &mvi->phy[i];
+
+       /* TODO check & save device type */
+       reg = mr32(GBL_PORT_TYPE);
+
+       if (reg & MODE_SAS_SATA & (1 << i))
+               phy->phy_type |= PORT_TYPE_SAS;
+       else
+               phy->phy_type |= PORT_TYPE_SATA;
+}
+
+void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       tmp = mr32(PCS);
+       if (mvi->chip->n_phy <= 4)
+               tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
+       else
+               tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
+       mw32(PCS, tmp);
+}
+
+void __devinit mvs_phy_hacks(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       /* workaround for SATA R-ERR, to ignore phy glitch */
+       tmp = mvs_cr32(regs, CMD_PHY_TIMER);
+       tmp &= ~(1 << 9);
+       tmp |= (1 << 10);
+       mvs_cw32(regs, CMD_PHY_TIMER, tmp);
+
+       /* enable retry 127 times */
+       mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
+
+       /* extend open frame timeout to max */
+       tmp = mvs_cr32(regs, CMD_SAS_CTL0);
+       tmp &= ~0xffff;
+       tmp |= 0x3fff;
+       mvs_cw32(regs, CMD_SAS_CTL0, tmp);
+
+       /* workaround for WDTIMEOUT , set to 550 ms */
+       mvs_cw32(regs, CMD_WD_TIMER, 0x86470);
+
+       /* not to halt for different port op during wideport link change */
+       mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
+
+       /* workaround for Seagate disk not-found OOB sequence, recv
+        * COMINIT before sending out COMWAKE */
+       tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
+       tmp &= 0x0000ffff;
+       tmp |= 0x00fa0000;
+       mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
+
+       tmp = mvs_cr32(regs, CMD_PHY_TIMER);
+       tmp &= 0x1fffffff;
+       tmp |= (2U << 29);      /* 8 ms retry */
+       mvs_cw32(regs, CMD_PHY_TIMER, tmp);
+
+       /* TEST - for phy decoding error, adjust voltage levels */
+       mw32(P0_VSR_ADDR + 0, 0x8);
+       mw32(P0_VSR_DATA + 0, 0x2F0);
+
+       mw32(P0_VSR_ADDR + 8, 0x8);
+       mw32(P0_VSR_DATA + 8, 0x2F0);
+
+       mw32(P0_VSR_ADDR + 16, 0x8);
+       mw32(P0_VSR_DATA + 16, 0x2F0);
+
+       mw32(P0_VSR_ADDR + 24, 0x8);
+       mw32(P0_VSR_DATA + 24, 0x2F0);
+
+}
+
+void mvs_hba_interrupt_enable(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       tmp = mr32(GBL_CTL);
+
+       mw32(GBL_CTL, tmp | INT_EN);
+}
+
+void mvs_hba_interrupt_disable(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       tmp = mr32(GBL_CTL);
+
+       mw32(GBL_CTL, tmp & ~INT_EN);
+}
+
+void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp, offs;
+       u8 *tfs = &port->taskfileset;
+
+       if (*tfs == MVS_ID_NOT_MAPPED)
+               return;
+
+       offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+       if (*tfs < 16) {
+               tmp = mr32(PCS);
+               mw32(PCS, tmp & ~offs);
+       } else {
+               tmp = mr32(CTL);
+               mw32(CTL, tmp & ~offs);
+       }
+
+       tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
+       if (tmp)
+               mw32(INT_STAT_SRS, tmp);
+
+       *tfs = MVS_ID_NOT_MAPPED;
+}
+
+u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+{
+       int i;
+       u32 tmp, offs;
+       void __iomem *regs = mvi->regs;
+
+       if (port->taskfileset != MVS_ID_NOT_MAPPED)
+               return 0;
+
+       tmp = mr32(PCS);
+
+       for (i = 0; i < mvi->chip->srs_sz; i++) {
+               if (i == 16)
+                       tmp = mr32(CTL);
+               offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+               if (!(tmp & offs)) {
+                       port->taskfileset = i;
+
+                       if (i < 16)
+                               mw32(PCS, tmp | offs);
+                       else
+                               mw32(CTL, tmp | offs);
+                       tmp = mr32(INT_STAT_SRS) & (1U << i);
+                       if (tmp)
+                               mw32(INT_STAT_SRS, tmp);
+                       return 0;
+               }
+       }
+       return MVS_ID_NOT_MAPPED;
+}
+
diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h
new file mode 100644 (file)
index 0000000..c9f399e
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef _MVS64XX_REG_H_
+#define _MVS64XX_REG_H_
+
+/* enhanced mode registers (BAR4) */
+enum hw_registers {
+       MVS_GBL_CTL             = 0x04,  /* global control */
+       MVS_GBL_INT_STAT        = 0x08,  /* global irq status */
+       MVS_GBL_PI              = 0x0C,  /* ports implemented bitmask */
+       MVS_GBL_PORT_TYPE       = 0xa0,  /* port type */
+
+       MVS_CTL                 = 0x100, /* SAS/SATA port configuration */
+       MVS_PCS                 = 0x104, /* SAS/SATA port control/status */
+       MVS_CMD_LIST_LO         = 0x108, /* cmd list addr */
+       MVS_CMD_LIST_HI         = 0x10C,
+       MVS_RX_FIS_LO           = 0x110, /* RX FIS list addr */
+       MVS_RX_FIS_HI           = 0x114,
+
+       MVS_TX_CFG              = 0x120, /* TX configuration */
+       MVS_TX_LO               = 0x124, /* TX (delivery) ring addr */
+       MVS_TX_HI               = 0x128,
+
+       MVS_TX_PROD_IDX         = 0x12C, /* TX producer pointer */
+       MVS_TX_CONS_IDX         = 0x130, /* TX consumer pointer (RO) */
+       MVS_RX_CFG              = 0x134, /* RX configuration */
+       MVS_RX_LO               = 0x138, /* RX (completion) ring addr */
+       MVS_RX_HI               = 0x13C,
+       MVS_RX_CONS_IDX         = 0x140, /* RX consumer pointer (RO) */
+
+       MVS_INT_COAL            = 0x148, /* Int coalescing config */
+       MVS_INT_COAL_TMOUT      = 0x14C, /* Int coalescing timeout */
+       MVS_INT_STAT            = 0x150, /* Central int status */
+       MVS_INT_MASK            = 0x154, /* Central int enable */
+       MVS_INT_STAT_SRS        = 0x158, /* SATA register set status */
+       MVS_INT_MASK_SRS        = 0x15C,
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_INT_STAT         = 0x160, /* port0 interrupt status */
+       MVS_P0_INT_MASK         = 0x164, /* port0 interrupt mask */
+       MVS_P4_INT_STAT         = 0x200, /* Port 4 interrupt status */
+       MVS_P4_INT_MASK         = 0x204, /* Port 4 interrupt enable mask */
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_SER_CTLSTAT      = 0x180, /* port0 serial control/status */
+       MVS_P4_SER_CTLSTAT      = 0x220, /* port4 serial control/status */
+
+       MVS_CMD_ADDR            = 0x1B8, /* Command register port (addr) */
+       MVS_CMD_DATA            = 0x1BC, /* Command register port (data) */
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_CFG_ADDR         = 0x1C0, /* port0 phy register address */
+       MVS_P0_CFG_DATA         = 0x1C4, /* port0 phy register data */
+       MVS_P4_CFG_ADDR         = 0x230, /* Port 4 config address */
+       MVS_P4_CFG_DATA         = 0x234, /* Port 4 config data */
+
+                                        /* ports 1-3 follow after this */
+       MVS_P0_VSR_ADDR         = 0x1E0, /* port0 VSR address */
+       MVS_P0_VSR_DATA         = 0x1E4, /* port0 VSR data */
+       MVS_P4_VSR_ADDR         = 0x250, /* port 4 VSR addr */
+       MVS_P4_VSR_DATA         = 0x254, /* port 4 VSR data */
+};
+
+enum pci_cfg_registers {
+       PCR_PHY_CTL             = 0x40,
+       PCR_PHY_CTL2            = 0x90,
+       PCR_DEV_CTRL            = 0xE8,
+};
+
+/*  SAS/SATA Vendor Specific Port Registers */
+enum sas_sata_vsp_regs {
+       VSR_PHY_STAT            = 0x00, /* Phy Status */
+       VSR_PHY_MODE1           = 0x01, /* phy tx */
+       VSR_PHY_MODE2           = 0x02, /* tx scc */
+       VSR_PHY_MODE3           = 0x03, /* pll */
+       VSR_PHY_MODE4           = 0x04, /* VCO */
+       VSR_PHY_MODE5           = 0x05, /* Rx */
+       VSR_PHY_MODE6           = 0x06, /* CDR */
+       VSR_PHY_MODE7           = 0x07, /* Impedance */
+       VSR_PHY_MODE8           = 0x08, /* Voltage */
+       VSR_PHY_MODE9           = 0x09, /* Test */
+       VSR_PHY_MODE10          = 0x0A, /* Power */
+       VSR_PHY_MODE11          = 0x0B, /* Phy Mode */
+       VSR_PHY_VS0             = 0x0C, /* Vednor Specific 0 */
+       VSR_PHY_VS1             = 0x0D, /* Vednor Specific 1 */
+};
+
+struct mvs_prd {
+       __le64                  addr;           /* 64-bit buffer address */
+       __le32                  reserved;
+       __le32                  len;            /* 16-bit length */
+};
+
+#endif
diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h
new file mode 100644 (file)
index 0000000..cf74b7a
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef _MV_CHIPS_H_
+#define _MV_CHIPS_H_
+
+#define mr32(reg)      readl(regs + MVS_##reg)
+#define mw32(reg,val)  writel((val), regs + MVS_##reg)
+#define mw32_f(reg,val)        do {                    \
+       writel((val), regs + MVS_##reg);        \
+       readl(regs + MVS_##reg);                \
+       } while (0)
+
+static inline u32 mvs_cr32(void __iomem *regs, u32 addr)
+{
+       mw32(CMD_ADDR, addr);
+       return mr32(CMD_DATA);
+}
+
+static inline void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
+{
+       mw32(CMD_ADDR, addr);
+       mw32(CMD_DATA, val);
+}
+
+static inline u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
+{
+       void __iomem *regs = mvi->regs;
+       return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4):
+               mr32(P4_SER_CTLSTAT + (port - 4) * 4);
+}
+
+static inline void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
+{
+       void __iomem *regs = mvi->regs;
+       if (port < 4)
+               mw32(P0_SER_CTLSTAT + port * 4, val);
+       else
+               mw32(P4_SER_CTLSTAT + (port - 4) * 4, val);
+}
+
+static inline u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port)
+{
+       void __iomem *regs = mvi->regs + off;
+       void __iomem *regs2 = mvi->regs + off2;
+       return (port < 4)?readl(regs + port * 8):
+               readl(regs2 + (port - 4) * 8);
+}
+
+static inline void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
+                               u32 port, u32 val)
+{
+       void __iomem *regs = mvi->regs + off;
+       void __iomem *regs2 = mvi->regs + off2;
+       if (port < 4)
+               writel(val, regs + port * 8);
+       else
+               writel(val, regs2 + (port - 4) * 8);
+}
+
+static inline u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
+{
+       return mvs_read_port(mvi, MVS_P0_CFG_DATA,
+                       MVS_P4_CFG_DATA, port);
+}
+
+static inline void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val)
+{
+       mvs_write_port(mvi, MVS_P0_CFG_DATA,
+                       MVS_P4_CFG_DATA, port, val);
+}
+
+static inline void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr)
+{
+       mvs_write_port(mvi, MVS_P0_CFG_ADDR,
+                       MVS_P4_CFG_ADDR, port, addr);
+}
+
+static inline u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
+{
+       return mvs_read_port(mvi, MVS_P0_VSR_DATA,
+                       MVS_P4_VSR_DATA, port);
+}
+
+static inline void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val)
+{
+       mvs_write_port(mvi, MVS_P0_VSR_DATA,
+                       MVS_P4_VSR_DATA, port, val);
+}
+
+static inline void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr)
+{
+       mvs_write_port(mvi, MVS_P0_VSR_ADDR,
+                       MVS_P4_VSR_ADDR, port, addr);
+}
+
+static inline u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
+{
+       return mvs_read_port(mvi, MVS_P0_INT_STAT,
+                       MVS_P4_INT_STAT, port);
+}
+
+static inline void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
+{
+       mvs_write_port(mvi, MVS_P0_INT_STAT,
+                       MVS_P4_INT_STAT, port, val);
+}
+
+static inline u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
+{
+       return mvs_read_port(mvi, MVS_P0_INT_MASK,
+                       MVS_P4_INT_MASK, port);
+}
+
+static inline void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
+{
+       mvs_write_port(mvi, MVS_P0_INT_MASK,
+                       MVS_P4_INT_MASK, port, val);
+}
+
+#endif
diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h
new file mode 100644 (file)
index 0000000..d8e96a3
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+       mv_defs.h - Marvell 88SE6440 SAS/SATA support
+
+       Copyright 2007 Red Hat, Inc.
+       Copyright 2008 Marvell. <kewei@marvell.com>
+
+       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,
+       or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty
+       of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+       See the GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public
+       License along with this program; see the file COPYING.  If not,
+       write to the Free Software Foundation, 675 Mass Ave, Cambridge,
+       MA 02139, USA.
+
+ */
+
+#ifndef _MV_DEFS_H_
+#define _MV_DEFS_H_
+
+/* driver compile-time configuration */
+enum driver_configuration {
+       MVS_TX_RING_SZ          = 1024, /* TX ring size (12-bit) */
+       MVS_RX_RING_SZ          = 1024, /* RX ring size (12-bit) */
+                                       /* software requires power-of-2
+                                          ring size */
+
+       MVS_SLOTS               = 512,  /* command slots */
+       MVS_SLOT_BUF_SZ         = 8192, /* cmd tbl + IU + status + PRD */
+       MVS_SSP_CMD_SZ          = 64,   /* SSP command table buffer size */
+       MVS_ATA_CMD_SZ          = 96,   /* SATA command table buffer size */
+       MVS_OAF_SZ              = 64,   /* Open address frame buffer size */
+
+       MVS_RX_FIS_COUNT        = 17,   /* Optional rx'd FISs (max 17) */
+
+       MVS_QUEUE_SIZE          = 30,   /* Support Queue depth */
+       MVS_CAN_QUEUE           = MVS_SLOTS - 1,        /* SCSI Queue depth */
+};
+
+/* unchangeable hardware details */
+enum hardware_details {
+       MVS_MAX_PHYS            = 8,    /* max. possible phys */
+       MVS_MAX_PORTS           = 8,    /* max. possible ports */
+       MVS_RX_FISL_SZ          = 0x400 + (MVS_RX_FIS_COUNT * 0x100),
+};
+
+/* peripheral registers (BAR2) */
+enum peripheral_registers {
+       SPI_CTL                 = 0x10, /* EEPROM control */
+       SPI_CMD                 = 0x14, /* EEPROM command */
+       SPI_DATA                = 0x18, /* EEPROM data */
+};
+
+enum peripheral_register_bits {
+       TWSI_RDY                = (1U << 7),    /* EEPROM interface ready */
+       TWSI_RD                 = (1U << 4),    /* EEPROM read access */
+
+       SPI_ADDR_MASK           = 0x3ffff,      /* bits 17:0 */
+};
+
+enum hw_register_bits {
+       /* MVS_GBL_CTL */
+       INT_EN                  = (1U << 1),    /* Global int enable */
+       HBA_RST                 = (1U << 0),    /* HBA reset */
+
+       /* MVS_GBL_INT_STAT */
+       INT_XOR                 = (1U << 4),    /* XOR engine event */
+       INT_SAS_SATA            = (1U << 0),    /* SAS/SATA event */
+
+       /* MVS_GBL_PORT_TYPE */                 /* shl for ports 1-3 */
+       SATA_TARGET             = (1U << 16),   /* port0 SATA target enable */
+       MODE_AUTO_DET_PORT7 = (1U << 15),       /* port0 SAS/SATA autodetect */
+       MODE_AUTO_DET_PORT6 = (1U << 14),
+       MODE_AUTO_DET_PORT5 = (1U << 13),
+       MODE_AUTO_DET_PORT4 = (1U << 12),
+       MODE_AUTO_DET_PORT3 = (1U << 11),
+       MODE_AUTO_DET_PORT2 = (1U << 10),
+       MODE_AUTO_DET_PORT1 = (1U << 9),
+       MODE_AUTO_DET_PORT0 = (1U << 8),
+       MODE_AUTO_DET_EN    =   MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
+                               MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
+                               MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
+                               MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
+       MODE_SAS_PORT7_MASK = (1U << 7),  /* port0 SAS(1), SATA(0) mode */
+       MODE_SAS_PORT6_MASK = (1U << 6),
+       MODE_SAS_PORT5_MASK = (1U << 5),
+       MODE_SAS_PORT4_MASK = (1U << 4),
+       MODE_SAS_PORT3_MASK = (1U << 3),
+       MODE_SAS_PORT2_MASK = (1U << 2),
+       MODE_SAS_PORT1_MASK = (1U << 1),
+       MODE_SAS_PORT0_MASK = (1U << 0),
+       MODE_SAS_SATA   =       MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
+                               MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
+                               MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
+                               MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
+
+                               /* SAS_MODE value may be
+                                * dictated (in hw) by values
+                                * of SATA_TARGET & AUTO_DET
+                                */
+
+       /* MVS_TX_CFG */
+       TX_EN                   = (1U << 16),   /* Enable TX */
+       TX_RING_SZ_MASK         = 0xfff,        /* TX ring size, bits 11:0 */
+
+       /* MVS_RX_CFG */
+       RX_EN                   = (1U << 16),   /* Enable RX */
+       RX_RING_SZ_MASK         = 0xfff,        /* RX ring size, bits 11:0 */
+
+       /* MVS_INT_COAL */
+       COAL_EN                 = (1U << 16),   /* Enable int coalescing */
+
+       /* MVS_INT_STAT, MVS_INT_MASK */
+       CINT_I2C                = (1U << 31),   /* I2C event */
+       CINT_SW0                = (1U << 30),   /* software event 0 */
+       CINT_SW1                = (1U << 29),   /* software event 1 */
+       CINT_PRD_BC             = (1U << 28),   /* PRD BC err for read cmd */
+       CINT_DMA_PCIE           = (1U << 27),   /* DMA to PCIE timeout */
+       CINT_MEM                = (1U << 26),   /* int mem parity err */
+       CINT_I2C_SLAVE          = (1U << 25),   /* slave I2C event */
+       CINT_SRS                = (1U << 3),    /* SRS event */
+       CINT_CI_STOP            = (1U << 1),    /* cmd issue stopped */
+       CINT_DONE               = (1U << 0),    /* cmd completion */
+
+                                               /* shl for ports 1-3 */
+       CINT_PORT_STOPPED       = (1U << 16),   /* port0 stopped */
+       CINT_PORT               = (1U << 8),    /* port0 event */
+       CINT_PORT_MASK_OFFSET   = 8,
+       CINT_PORT_MASK          = (0xFF << CINT_PORT_MASK_OFFSET),
+
+       /* TX (delivery) ring bits */
+       TXQ_CMD_SHIFT           = 29,
+       TXQ_CMD_SSP             = 1,            /* SSP protocol */
+       TXQ_CMD_SMP             = 2,            /* SMP protocol */
+       TXQ_CMD_STP             = 3,            /* STP/SATA protocol */
+       TXQ_CMD_SSP_FREE_LIST   = 4,            /* add to SSP targ free list */
+       TXQ_CMD_SLOT_RESET      = 7,            /* reset command slot */
+       TXQ_MODE_I              = (1U << 28),   /* mode: 0=target,1=initiator */
+       TXQ_PRIO_HI             = (1U << 27),   /* priority: 0=normal, 1=high */
+       TXQ_SRS_SHIFT           = 20,           /* SATA register set */
+       TXQ_SRS_MASK            = 0x7f,
+       TXQ_PHY_SHIFT           = 12,           /* PHY bitmap */
+       TXQ_PHY_MASK            = 0xff,
+       TXQ_SLOT_MASK           = 0xfff,        /* slot number */
+
+       /* RX (completion) ring bits */
+       RXQ_GOOD                = (1U << 23),   /* Response good */
+       RXQ_SLOT_RESET          = (1U << 21),   /* Slot reset complete */
+       RXQ_CMD_RX              = (1U << 20),   /* target cmd received */
+       RXQ_ATTN                = (1U << 19),   /* attention */
+       RXQ_RSP                 = (1U << 18),   /* response frame xfer'd */
+       RXQ_ERR                 = (1U << 17),   /* err info rec xfer'd */
+       RXQ_DONE                = (1U << 16),   /* cmd complete */
+       RXQ_SLOT_MASK           = 0xfff,        /* slot number */
+
+       /* mvs_cmd_hdr bits */
+       MCH_PRD_LEN_SHIFT       = 16,           /* 16-bit PRD table len */
+       MCH_SSP_FR_TYPE_SHIFT   = 13,           /* SSP frame type */
+
+                                               /* SSP initiator only */
+       MCH_SSP_FR_CMD          = 0x0,          /* COMMAND frame */
+
+                                               /* SSP initiator or target */
+       MCH_SSP_FR_TASK         = 0x1,          /* TASK frame */
+
+                                               /* SSP target only */
+       MCH_SSP_FR_XFER_RDY     = 0x4,          /* XFER_RDY frame */
+       MCH_SSP_FR_RESP         = 0x5,          /* RESPONSE frame */
+       MCH_SSP_FR_READ         = 0x6,          /* Read DATA frame(s) */
+       MCH_SSP_FR_READ_RESP    = 0x7,          /* ditto, plus RESPONSE */
+
+       MCH_PASSTHRU            = (1U << 12),   /* pass-through (SSP) */
+       MCH_FBURST              = (1U << 11),   /* first burst (SSP) */
+       MCH_CHK_LEN             = (1U << 10),   /* chk xfer len (SSP) */
+       MCH_RETRY               = (1U << 9),    /* tport layer retry (SSP) */
+       MCH_PROTECTION          = (1U << 8),    /* protection info rec (SSP) */
+       MCH_RESET               = (1U << 7),    /* Reset (STP/SATA) */
+       MCH_FPDMA               = (1U << 6),    /* First party DMA (STP/SATA) */
+       MCH_ATAPI               = (1U << 5),    /* ATAPI (STP/SATA) */
+       MCH_BIST                = (1U << 4),    /* BIST activate (STP/SATA) */
+       MCH_PMP_MASK            = 0xf,          /* PMP from cmd FIS (STP/SATA)*/
+
+       CCTL_RST                = (1U << 5),    /* port logic reset */
+
+                                               /* 0(LSB first), 1(MSB first) */
+       CCTL_ENDIAN_DATA        = (1U << 3),    /* PRD data */
+       CCTL_ENDIAN_RSP         = (1U << 2),    /* response frame */
+       CCTL_ENDIAN_OPEN        = (1U << 1),    /* open address frame */
+       CCTL_ENDIAN_CMD         = (1U << 0),    /* command table */
+
+       /* MVS_Px_SER_CTLSTAT (per-phy control) */
+       PHY_SSP_RST             = (1U << 3),    /* reset SSP link layer */
+       PHY_BCAST_CHG           = (1U << 2),    /* broadcast(change) notif */
+       PHY_RST_HARD            = (1U << 1),    /* hard reset + phy reset */
+       PHY_RST                 = (1U << 0),    /* phy reset */
+       PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
+       PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
+       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
+       PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
+                       (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
+       PHY_READY_MASK          = (1U << 20),
+
+       /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
+       PHYEV_DEC_ERR           = (1U << 24),   /* Phy Decoding Error */
+       PHYEV_UNASSOC_FIS       = (1U << 19),   /* unassociated FIS rx'd */
+       PHYEV_AN                = (1U << 18),   /* SATA async notification */
+       PHYEV_BIST_ACT          = (1U << 17),   /* BIST activate FIS */
+       PHYEV_SIG_FIS           = (1U << 16),   /* signature FIS */
+       PHYEV_POOF              = (1U << 12),   /* phy ready from 1 -> 0 */
+       PHYEV_IU_BIG            = (1U << 11),   /* IU too long err */
+       PHYEV_IU_SMALL          = (1U << 10),   /* IU too short err */
+       PHYEV_UNK_TAG           = (1U << 9),    /* unknown tag */
+       PHYEV_BROAD_CH          = (1U << 8),    /* broadcast(CHANGE) */
+       PHYEV_COMWAKE           = (1U << 7),    /* COMWAKE rx'd */
+       PHYEV_PORT_SEL          = (1U << 6),    /* port selector present */
+       PHYEV_HARD_RST          = (1U << 5),    /* hard reset rx'd */
+       PHYEV_ID_TMOUT          = (1U << 4),    /* identify timeout */
+       PHYEV_ID_FAIL           = (1U << 3),    /* identify failed */
+       PHYEV_ID_DONE           = (1U << 2),    /* identify done */
+       PHYEV_HARD_RST_DONE     = (1U << 1),    /* hard reset done */
+       PHYEV_RDY_CH            = (1U << 0),    /* phy ready changed state */
+
+       /* MVS_PCS */
+       PCS_EN_SATA_REG_SHIFT   = (16),         /* Enable SATA Register Set */
+       PCS_EN_PORT_XMT_SHIFT   = (12),         /* Enable Port Transmit */
+       PCS_EN_PORT_XMT_SHIFT2  = (8),          /* For 6480 */
+       PCS_SATA_RETRY          = (1U << 8),    /* retry ctl FIS on R_ERR */
+       PCS_RSP_RX_EN           = (1U << 7),    /* raw response rx */
+       PCS_SELF_CLEAR          = (1U << 5),    /* self-clearing int mode */
+       PCS_FIS_RX_EN           = (1U << 4),    /* FIS rx enable */
+       PCS_CMD_STOP_ERR        = (1U << 3),    /* cmd stop-on-err enable */
+       PCS_CMD_RST             = (1U << 1),    /* reset cmd issue */
+       PCS_CMD_EN              = (1U << 0),    /* enable cmd issue */
+
+       /* Port n Attached Device Info */
+       PORT_DEV_SSP_TRGT       = (1U << 19),
+       PORT_DEV_SMP_TRGT       = (1U << 18),
+       PORT_DEV_STP_TRGT       = (1U << 17),
+       PORT_DEV_SSP_INIT       = (1U << 11),
+       PORT_DEV_SMP_INIT       = (1U << 10),
+       PORT_DEV_STP_INIT       = (1U << 9),
+       PORT_PHY_ID_MASK        = (0xFFU << 24),
+       PORT_DEV_TRGT_MASK      = (0x7U << 17),
+       PORT_DEV_INIT_MASK      = (0x7U << 9),
+       PORT_DEV_TYPE_MASK      = (0x7U << 0),
+
+       /* Port n PHY Status */
+       PHY_RDY                 = (1U << 2),
+       PHY_DW_SYNC             = (1U << 1),
+       PHY_OOB_DTCTD           = (1U << 0),
+
+       /* VSR */
+       /* PHYMODE 6 (CDB) */
+       PHY_MODE6_LATECLK       = (1U << 29),   /* Lock Clock */
+       PHY_MODE6_DTL_SPEED     = (1U << 27),   /* Digital Loop Speed */
+       PHY_MODE6_FC_ORDER      = (1U << 26),   /* Fibre Channel Mode Order*/
+       PHY_MODE6_MUCNT_EN      = (1U << 24),   /* u Count Enable */
+       PHY_MODE6_SEL_MUCNT_LEN = (1U << 22),   /* Training Length Select */
+       PHY_MODE6_SELMUPI       = (1U << 20),   /* Phase Multi Select (init) */
+       PHY_MODE6_SELMUPF       = (1U << 18),   /* Phase Multi Select (final) */
+       PHY_MODE6_SELMUFF       = (1U << 16),   /* Freq Loop Multi Sel(final) */
+       PHY_MODE6_SELMUFI       = (1U << 14),   /* Freq Loop Multi Sel(init) */
+       PHY_MODE6_FREEZE_LOOP   = (1U << 12),   /* Freeze Rx CDR Loop */
+       PHY_MODE6_INT_RXFOFFS   = (1U << 3),    /* Rx CDR Freq Loop Enable */
+       PHY_MODE6_FRC_RXFOFFS   = (1U << 2),    /* Initial Rx CDR Offset */
+       PHY_MODE6_STAU_0D8      = (1U << 1),    /* Rx CDR Freq Loop Saturate */
+       PHY_MODE6_RXSAT_DIS     = (1U << 0),    /* Saturate Ctl */
+};
+
+/* SAS/SATA configuration port registers, aka phy registers */
+enum sas_sata_config_port_regs {
+       PHYR_IDENTIFY           = 0x00, /* info for IDENTIFY frame */
+       PHYR_ADDR_LO            = 0x04, /* my SAS address (low) */
+       PHYR_ADDR_HI            = 0x08, /* my SAS address (high) */
+       PHYR_ATT_DEV_INFO       = 0x0C, /* attached device info */
+       PHYR_ATT_ADDR_LO        = 0x10, /* attached dev SAS addr (low) */
+       PHYR_ATT_ADDR_HI        = 0x14, /* attached dev SAS addr (high) */
+       PHYR_SATA_CTL           = 0x18, /* SATA control */
+       PHYR_PHY_STAT           = 0x1C, /* PHY status */
+       PHYR_SATA_SIG0          = 0x20, /*port SATA signature FIS(Byte 0-3) */
+       PHYR_SATA_SIG1          = 0x24, /*port SATA signature FIS(Byte 4-7) */
+       PHYR_SATA_SIG2          = 0x28, /*port SATA signature FIS(Byte 8-11) */
+       PHYR_SATA_SIG3          = 0x2c, /*port SATA signature FIS(Byte 12-15) */
+       PHYR_R_ERR_COUNT        = 0x30, /* port R_ERR count register */
+       PHYR_CRC_ERR_COUNT      = 0x34, /* port CRC error count register */
+       PHYR_WIDE_PORT          = 0x38, /* wide port participating */
+       PHYR_CURRENT0           = 0x80, /* current connection info 0 */
+       PHYR_CURRENT1           = 0x84, /* current connection info 1 */
+       PHYR_CURRENT2           = 0x88, /* current connection info 2 */
+};
+
+enum mvs_info_flags {
+       MVF_MSI                 = (1U << 0),    /* MSI is enabled */
+       MVF_PHY_PWR_FIX         = (1U << 1),    /* bug workaround */
+};
+
+enum sas_cmd_port_registers {
+       CMD_CMRST_OOB_DET       = 0x100, /* COMRESET OOB detect register */
+       CMD_CMWK_OOB_DET        = 0x104, /* COMWAKE OOB detect register */
+       CMD_CMSAS_OOB_DET       = 0x108, /* COMSAS OOB detect register */
+       CMD_BRST_OOB_DET        = 0x10c, /* burst OOB detect register */
+       CMD_OOB_SPACE           = 0x110, /* OOB space control register */
+       CMD_OOB_BURST           = 0x114, /* OOB burst control register */
+       CMD_PHY_TIMER           = 0x118, /* PHY timer control register */
+       CMD_PHY_CONFIG0         = 0x11c, /* PHY config register 0 */
+       CMD_PHY_CONFIG1         = 0x120, /* PHY config register 1 */
+       CMD_SAS_CTL0            = 0x124, /* SAS control register 0 */
+       CMD_SAS_CTL1            = 0x128, /* SAS control register 1 */
+       CMD_SAS_CTL2            = 0x12c, /* SAS control register 2 */
+       CMD_SAS_CTL3            = 0x130, /* SAS control register 3 */
+       CMD_ID_TEST             = 0x134, /* ID test register */
+       CMD_PL_TIMER            = 0x138, /* PL timer register */
+       CMD_WD_TIMER            = 0x13c, /* WD timer register */
+       CMD_PORT_SEL_COUNT      = 0x140, /* port selector count register */
+       CMD_APP_MEM_CTL         = 0x144, /* Application Memory Control */
+       CMD_XOR_MEM_CTL         = 0x148, /* XOR Block Memory Control */
+       CMD_DMA_MEM_CTL         = 0x14c, /* DMA Block Memory Control */
+       CMD_PORT_MEM_CTL0       = 0x150, /* Port Memory Control 0 */
+       CMD_PORT_MEM_CTL1       = 0x154, /* Port Memory Control 1 */
+       CMD_SATA_PORT_MEM_CTL0  = 0x158, /* SATA Port Memory Control 0 */
+       CMD_SATA_PORT_MEM_CTL1  = 0x15c, /* SATA Port Memory Control 1 */
+       CMD_XOR_MEM_BIST_CTL    = 0x160, /* XOR Memory BIST Control */
+       CMD_XOR_MEM_BIST_STAT   = 0x164, /* XOR Memroy BIST Status */
+       CMD_DMA_MEM_BIST_CTL    = 0x168, /* DMA Memory BIST Control */
+       CMD_DMA_MEM_BIST_STAT   = 0x16c, /* DMA Memory BIST Status */
+       CMD_PORT_MEM_BIST_CTL   = 0x170, /* Port Memory BIST Control */
+       CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */
+       CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */
+       CMD_STP_MEM_BIST_CTL    = 0x17c, /* STP Memory BIST Control */
+       CMD_STP_MEM_BIST_STAT0  = 0x180, /* STP Memory BIST Status 0 */
+       CMD_STP_MEM_BIST_STAT1  = 0x184, /* STP Memory BIST Status 1 */
+       CMD_RESET_COUNT         = 0x188, /* Reset Count */
+       CMD_MONTR_DATA_SEL      = 0x18C, /* Monitor Data/Select */
+       CMD_PLL_PHY_CONFIG      = 0x190, /* PLL/PHY Configuration */
+       CMD_PHY_CTL             = 0x194, /* PHY Control and Status */
+       CMD_PHY_TEST_COUNT0     = 0x198, /* Phy Test Count 0 */
+       CMD_PHY_TEST_COUNT1     = 0x19C, /* Phy Test Count 1 */
+       CMD_PHY_TEST_COUNT2     = 0x1A0, /* Phy Test Count 2 */
+       CMD_APP_ERR_CONFIG      = 0x1A4, /* Application Error Configuration */
+       CMD_PND_FIFO_CTL0       = 0x1A8, /* Pending FIFO Control 0 */
+       CMD_HOST_CTL            = 0x1AC, /* Host Control Status */
+       CMD_HOST_WR_DATA        = 0x1B0, /* Host Write Data */
+       CMD_HOST_RD_DATA        = 0x1B4, /* Host Read Data */
+       CMD_PHY_MODE_21         = 0x1B8, /* Phy Mode 21 */
+       CMD_SL_MODE0            = 0x1BC, /* SL Mode 0 */
+       CMD_SL_MODE1            = 0x1C0, /* SL Mode 1 */
+       CMD_PND_FIFO_CTL1       = 0x1C4, /* Pending FIFO Control 1 */
+};
+
+enum pci_cfg_register_bits {
+       PCTL_PWR_ON     = (0xFU << 24),
+       PCTL_OFF        = (0xFU << 12),
+       PRD_REQ_SIZE    = (0x4000),
+       PRD_REQ_MASK    = (0x00007000),
+};
+
+enum nvram_layout_offsets {
+       NVR_SIG         = 0x00,         /* 0xAA, 0x55 */
+       NVR_SAS_ADDR    = 0x02,         /* 8-byte SAS address */
+};
+
+enum chip_flavors {
+       chip_6320,
+       chip_6440,
+       chip_6480,
+};
+
+enum port_type {
+       PORT_TYPE_SAS   =  (1L << 1),
+       PORT_TYPE_SATA  =  (1L << 0),
+};
+
+/* Command Table Format */
+enum ct_format {
+       /* SSP */
+       SSP_F_H         =  0x00,
+       SSP_F_IU        =  0x18,
+       SSP_F_MAX       =  0x4D,
+       /* STP */
+       STP_CMD_FIS     =  0x00,
+       STP_ATAPI_CMD   =  0x40,
+       STP_F_MAX       =  0x10,
+       /* SMP */
+       SMP_F_T         =  0x00,
+       SMP_F_DEP       =  0x01,
+       SMP_F_MAX       =  0x101,
+};
+
+enum status_buffer {
+       SB_EIR_OFF      =  0x00,        /* Error Information Record */
+       SB_RFB_OFF      =  0x08,        /* Response Frame Buffer */
+       SB_RFB_MAX      =  0x400,       /* RFB size*/
+};
+
+enum error_info_rec {
+       CMD_ISS_STPD    = (1U << 31),   /* Cmd Issue Stopped */
+       CMD_PI_ERR      = (1U << 30),   /* Protection info error.  see flags2 */
+       RSP_OVER        = (1U << 29),   /* rsp buffer overflow */
+       RETRY_LIM       = (1U << 28),   /* FIS/frame retry limit exceeded */
+       UNK_FIS         = (1U << 27),   /* unknown FIS */
+       DMA_TERM        = (1U << 26),   /* DMA terminate primitive rx'd */
+       SYNC_ERR        = (1U << 25),   /* SYNC rx'd during frame xmit */
+       TFILE_ERR       = (1U << 24),   /* SATA taskfile Error bit set */
+       R_ERR           = (1U << 23),   /* SATA returned R_ERR prim */
+       RD_OFS          = (1U << 20),   /* Read DATA frame invalid offset */
+       XFER_RDY_OFS    = (1U << 19),   /* XFER_RDY offset error */
+       UNEXP_XFER_RDY  = (1U << 18),   /* unexpected XFER_RDY error */
+       DATA_OVER_UNDER = (1U << 16),   /* data overflow/underflow */
+       INTERLOCK       = (1U << 15),   /* interlock error */
+       NAK             = (1U << 14),   /* NAK rx'd */
+       ACK_NAK_TO      = (1U << 13),   /* ACK/NAK timeout */
+       CXN_CLOSED      = (1U << 12),   /* cxn closed w/out ack/nak */
+       OPEN_TO         = (1U << 11),   /* I_T nexus lost, open cxn timeout */
+       PATH_BLOCKED    = (1U << 10),   /* I_T nexus lost, pathway blocked */
+       NO_DEST         = (1U << 9),    /* I_T nexus lost, no destination */
+       STP_RES_BSY     = (1U << 8),    /* STP resources busy */
+       BREAK           = (1U << 7),    /* break received */
+       BAD_DEST        = (1U << 6),    /* bad destination */
+       BAD_PROTO       = (1U << 5),    /* protocol not supported */
+       BAD_RATE        = (1U << 4),    /* cxn rate not supported */
+       WRONG_DEST      = (1U << 3),    /* wrong destination error */
+       CREDIT_TO       = (1U << 2),    /* credit timeout */
+       WDOG_TO         = (1U << 1),    /* watchdog timeout */
+       BUF_PAR         = (1U << 0),    /* buffer parity error */
+};
+
+enum error_info_rec_2 {
+       SLOT_BSY_ERR    = (1U << 31),   /* Slot Busy Error */
+       GRD_CHK_ERR     = (1U << 14),   /* Guard Check Error */
+       APP_CHK_ERR     = (1U << 13),   /* Application Check error */
+       REF_CHK_ERR     = (1U << 12),   /* Reference Check Error */
+       USR_BLK_NM      = (1U << 0),    /* User Block Number */
+};
+
+#endif
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
new file mode 100644 (file)
index 0000000..258a1a9
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+       mv_init.c - Marvell 88SE6440 SAS/SATA init support
+
+       Copyright 2007 Red Hat, Inc.
+       Copyright 2008 Marvell. <kewei@marvell.com>
+
+       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,
+       or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty
+       of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+       See the GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public
+       License along with this program; see the file COPYING.  If not,
+       write to the Free Software Foundation, 675 Mass Ave, Cambridge,
+       MA 02139, USA.
+
+ */
+
+#include "mv_sas.h"
+#include "mv_64xx.h"
+#include "mv_chips.h"
+
+static struct scsi_transport_template *mvs_stt;
+
+static const struct mvs_chip_info mvs_chips[] = {
+       [chip_6320] =           { 2, 16, 9  },
+       [chip_6440] =           { 4, 16, 9  },
+       [chip_6480] =           { 8, 32, 10 },
+};
+
+static struct scsi_host_template mvs_sht = {
+       .module                 = THIS_MODULE,
+       .name                   = DRV_NAME,
+       .queuecommand           = sas_queuecommand,
+       .target_alloc           = sas_target_alloc,
+       .slave_configure        = mvs_slave_configure,
+       .slave_destroy          = sas_slave_destroy,
+       .scan_finished          = mvs_scan_finished,
+       .scan_start             = mvs_scan_start,
+       .change_queue_depth     = sas_change_queue_depth,
+       .change_queue_type      = sas_change_queue_type,
+       .bios_param             = sas_bios_param,
+       .can_queue              = 1,
+       .cmd_per_lun            = 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,
+       .slave_alloc            = sas_slave_alloc,
+       .target_destroy         = sas_target_destroy,
+       .ioctl                  = sas_ioctl,
+};
+
+static struct sas_domain_function_template mvs_transport_ops = {
+       .lldd_execute_task      = mvs_task_exec,
+       .lldd_control_phy       = mvs_phy_control,
+       .lldd_abort_task        = mvs_task_abort,
+       .lldd_port_formed       = mvs_port_formed,
+       .lldd_I_T_nexus_reset   = mvs_I_T_nexus_reset,
+};
+
+static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
+{
+       struct mvs_phy *phy = &mvi->phy[phy_id];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+       sas_phy->enabled = (phy_id < mvi->chip->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_id;
+       sas_phy->sas_addr = &mvi->sas_addr[0];
+       sas_phy->frame_rcvd = &phy->frame_rcvd[0];
+       sas_phy->ha = &mvi->sas;
+       sas_phy->lldd_phy = phy;
+}
+
+static void mvs_free(struct mvs_info *mvi)
+{
+       int i;
+
+       if (!mvi)
+               return;
+
+       for (i = 0; i < MVS_SLOTS; i++) {
+               struct mvs_slot_info *slot = &mvi->slot_info[i];
+
+               if (slot->buf)
+                       dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ,
+                                         slot->buf, slot->buf_dma);
+       }
+
+       if (mvi->tx)
+               dma_free_coherent(&mvi->pdev->dev,
+                                 sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
+                                 mvi->tx, mvi->tx_dma);
+       if (mvi->rx_fis)
+               dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
+                                 mvi->rx_fis, mvi->rx_fis_dma);
+       if (mvi->rx)
+               dma_free_coherent(&mvi->pdev->dev,
+                                 sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
+                                 mvi->rx, mvi->rx_dma);
+       if (mvi->slot)
+               dma_free_coherent(&mvi->pdev->dev,
+                                 sizeof(*mvi->slot) * MVS_SLOTS,
+                                 mvi->slot, mvi->slot_dma);
+#ifdef MVS_ENABLE_PERI
+       if (mvi->peri_regs)
+               iounmap(mvi->peri_regs);
+#endif
+       if (mvi->regs)
+               iounmap(mvi->regs);
+       if (mvi->shost)
+               scsi_host_put(mvi->shost);
+       kfree(mvi->sas.sas_port);
+       kfree(mvi->sas.sas_phy);
+       kfree(mvi);
+}
+
+#ifdef MVS_USE_TASKLET
+static void mvs_tasklet(unsigned long data)
+{
+       struct mvs_info *mvi = (struct mvs_info *) data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mvi->lock, flags);
+
+#ifdef MVS_DISABLE_MSI
+       mvs_int_full(mvi);
+#else
+       mvs_int_rx(mvi, true);
+#endif
+       spin_unlock_irqrestore(&mvi->lock, flags);
+}
+#endif
+
+static irqreturn_t mvs_interrupt(int irq, void *opaque)
+{
+       struct mvs_info *mvi = opaque;
+       void __iomem *regs = mvi->regs;
+       u32 stat;
+
+       stat = mr32(GBL_INT_STAT);
+
+       if (stat == 0 || stat == 0xffffffff)
+               return IRQ_NONE;
+
+       /* clear CMD_CMPLT ASAP */
+       mw32_f(INT_STAT, CINT_DONE);
+
+#ifndef MVS_USE_TASKLET
+       spin_lock(&mvi->lock);
+
+       mvs_int_full(mvi);
+
+       spin_unlock(&mvi->lock);
+#else
+       tasklet_schedule(&mvi->tasklet);
+#endif
+       return IRQ_HANDLED;
+}
+
+static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
+                                           const struct pci_device_id *ent)
+{
+       struct mvs_info *mvi;
+       unsigned long res_start, res_len, res_flag;
+       struct asd_sas_phy **arr_phy;
+       struct asd_sas_port **arr_port;
+       const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
+       int i;
+
+       /*
+        * alloc and init our per-HBA mvs_info struct
+        */
+
+       mvi = kzalloc(sizeof(*mvi), GFP_KERNEL);
+       if (!mvi)
+               return NULL;
+
+       spin_lock_init(&mvi->lock);
+#ifdef MVS_USE_TASKLET
+       tasklet_init(&mvi->tasklet, mvs_tasklet, (unsigned long)mvi);
+#endif
+       mvi->pdev = pdev;
+       mvi->chip = chip;
+
+       if (pdev->device == 0x6440 && pdev->revision == 0)
+               mvi->flags |= MVF_PHY_PWR_FIX;
+
+       /*
+        * alloc and init SCSI, SAS glue
+        */
+
+       mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *));
+       if (!mvi->shost)
+               goto err_out;
+
+       arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
+       arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
+       if (!arr_phy || !arr_port)
+               goto err_out;
+
+       for (i = 0; i < MVS_MAX_PHYS; i++) {
+               mvs_phy_init(mvi, i);
+               arr_phy[i] = &mvi->phy[i].sas_phy;
+               arr_port[i] = &mvi->port[i].sas_port;
+               mvi->port[i].taskfileset = MVS_ID_NOT_MAPPED;
+               mvi->port[i].wide_port_phymap = 0;
+               mvi->port[i].port_attached = 0;
+               INIT_LIST_HEAD(&mvi->port[i].list);
+       }
+
+       SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
+       mvi->shost->transportt = mvs_stt;
+       mvi->shost->max_id = 21;
+       mvi->shost->max_lun = ~0;
+       mvi->shost->max_channel = 0;
+       mvi->shost->max_cmd_len = 16;
+
+       mvi->sas.sas_ha_name = DRV_NAME;
+       mvi->sas.dev = &pdev->dev;
+       mvi->sas.lldd_module = THIS_MODULE;
+       mvi->sas.sas_addr = &mvi->sas_addr[0];
+       mvi->sas.sas_phy = arr_phy;
+       mvi->sas.sas_port = arr_port;
+       mvi->sas.num_phys = chip->n_phy;
+       mvi->sas.lldd_max_execute_num = 1;
+       mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
+       mvi->shost->can_queue = MVS_CAN_QUEUE;
+       mvi->shost->cmd_per_lun = MVS_SLOTS / mvi->sas.num_phys;
+       mvi->sas.lldd_ha = mvi;
+       mvi->sas.core.shost = mvi->shost;
+
+       mvs_tag_init(mvi);
+
+       /*
+        * ioremap main and peripheral registers
+        */
+
+#ifdef MVS_ENABLE_PERI
+       res_start = pci_resource_start(pdev, 2);
+       res_len = pci_resource_len(pdev, 2);
+       if (!res_start || !res_len)
+               goto err_out;
+
+       mvi->peri_regs = ioremap_nocache(res_start, res_len);
+       if (!mvi->peri_regs)
+               goto err_out;
+#endif
+
+       res_start = pci_resource_start(pdev, 4);
+       res_len = pci_resource_len(pdev, 4);
+       if (!res_start || !res_len)
+               goto err_out;
+
+       res_flag = pci_resource_flags(pdev, 4);
+       if (res_flag & IORESOURCE_CACHEABLE)
+               mvi->regs = ioremap(res_start, res_len);
+       else
+               mvi->regs = ioremap_nocache(res_start, res_len);
+
+       if (!mvi->regs)
+               goto err_out;
+
+       /*
+        * alloc and init our DMA areas
+        */
+
+       mvi->tx = dma_alloc_coherent(&pdev->dev,
+                                    sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
+                                    &mvi->tx_dma, GFP_KERNEL);
+       if (!mvi->tx)
+               goto err_out;
+       memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
+
+       mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
+                                        &mvi->rx_fis_dma, GFP_KERNEL);
+       if (!mvi->rx_fis)
+               goto err_out;
+       memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
+
+       mvi->rx = dma_alloc_coherent(&pdev->dev,
+                                    sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
+                                    &mvi->rx_dma, GFP_KERNEL);
+       if (!mvi->rx)
+               goto err_out;
+       memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1));
+
+       mvi->rx[0] = cpu_to_le32(0xfff);
+       mvi->rx_cons = 0xfff;
+
+       mvi->slot = dma_alloc_coherent(&pdev->dev,
+                                      sizeof(*mvi->slot) * MVS_SLOTS,
+                                      &mvi->slot_dma, GFP_KERNEL);
+       if (!mvi->slot)
+               goto err_out;
+       memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS);
+
+       for (i = 0; i < MVS_SLOTS; i++) {
+               struct mvs_slot_info *slot = &mvi->slot_info[i];
+
+               slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
+                                              &slot->buf_dma, GFP_KERNEL);
+               if (!slot->buf)
+                       goto err_out;
+               memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
+       }
+
+       /* finally, read NVRAM to get our SAS address */
+       if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
+               goto err_out;
+       return mvi;
+
+err_out:
+       mvs_free(mvi);
+       return NULL;
+}
+
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+       int rc;
+
+       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+               if (rc) {
+                       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+                       if (rc) {
+                               dev_printk(KERN_ERR, &pdev->dev,
+                                          "64-bit DMA enable failed\n");
+                               return rc;
+                       }
+               }
+       } else {
+               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit DMA enable failed\n");
+                       return rc;
+               }
+               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit consistent DMA enable failed\n");
+                       return rc;
+               }
+       }
+
+       return rc;
+}
+
+static int __devinit mvs_pci_init(struct pci_dev *pdev,
+                                 const struct pci_device_id *ent)
+{
+       int rc;
+       struct mvs_info *mvi;
+       irq_handler_t irq_handler = mvs_interrupt;
+
+       rc = pci_enable_device(pdev);
+       if (rc)
+               return rc;
+
+       pci_set_master(pdev);
+
+       rc = pci_request_regions(pdev, DRV_NAME);
+       if (rc)
+               goto err_out_disable;
+
+       rc = pci_go_64(pdev);
+       if (rc)
+               goto err_out_regions;
+
+       mvi = mvs_alloc(pdev, ent);
+       if (!mvi) {
+               rc = -ENOMEM;
+               goto err_out_regions;
+       }
+
+       rc = mvs_hw_init(mvi);
+       if (rc)
+               goto err_out_mvi;
+
+#ifndef MVS_DISABLE_MSI
+       if (!pci_enable_msi(pdev)) {
+               u32 tmp;
+               void __iomem *regs = mvi->regs;
+               mvi->flags |= MVF_MSI;
+               irq_handler = mvs_msi_interrupt;
+               tmp = mr32(PCS);
+               mw32(PCS, tmp | PCS_SELF_CLEAR);
+       }
+#endif
+
+       rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi);
+       if (rc)
+               goto err_out_msi;
+
+       rc = scsi_add_host(mvi->shost, &pdev->dev);
+       if (rc)
+               goto err_out_irq;
+
+       rc = sas_register_ha(&mvi->sas);
+       if (rc)
+               goto err_out_shost;
+
+       pci_set_drvdata(pdev, mvi);
+
+       mvs_print_info(mvi);
+
+       mvs_hba_interrupt_enable(mvi);
+
+       scsi_scan_host(mvi->shost);
+
+       return 0;
+
+err_out_shost:
+       scsi_remove_host(mvi->shost);
+err_out_irq:
+       free_irq(pdev->irq, mvi);
+err_out_msi:
+       if (mvi->flags |= MVF_MSI)
+               pci_disable_msi(pdev);
+err_out_mvi:
+       mvs_free(mvi);
+err_out_regions:
+       pci_release_regions(pdev);
+err_out_disable:
+       pci_disable_device(pdev);
+       return rc;
+}
+
+static void __devexit mvs_pci_remove(struct pci_dev *pdev)
+{
+       struct mvs_info *mvi = pci_get_drvdata(pdev);
+
+       pci_set_drvdata(pdev, NULL);
+
+       if (mvi) {
+               sas_unregister_ha(&mvi->sas);
+               mvs_hba_interrupt_disable(mvi);
+               sas_remove_host(mvi->shost);
+               scsi_remove_host(mvi->shost);
+
+               free_irq(pdev->irq, mvi);
+               if (mvi->flags & MVF_MSI)
+                       pci_disable_msi(pdev);
+               mvs_free(mvi);
+               pci_release_regions(pdev);
+       }
+       pci_disable_device(pdev);
+}
+
+static struct pci_device_id __devinitdata mvs_pci_table[] = {
+       { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
+       { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
+       {
+               .vendor         = PCI_VENDOR_ID_MARVELL,
+               .device         = 0x6440,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = 0x6480,
+               .class          = 0,
+               .class_mask     = 0,
+               .driver_data    = chip_6480,
+       },
+       { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
+       { PCI_VDEVICE(MARVELL, 0x6480), chip_6480 },
+
+       { }     /* terminate list */
+};
+
+static struct pci_driver mvs_pci_driver = {
+       .name           = DRV_NAME,
+       .id_table       = mvs_pci_table,
+       .probe          = mvs_pci_init,
+       .remove         = __devexit_p(mvs_pci_remove),
+};
+
+static int __init mvs_init(void)
+{
+       int rc;
+
+       mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);
+       if (!mvs_stt)
+               return -ENOMEM;
+
+       rc = pci_register_driver(&mvs_pci_driver);
+       if (rc)
+               goto err_out;
+
+       return 0;
+
+err_out:
+       sas_release_transport(mvs_stt);
+       return rc;
+}
+
+static void __exit mvs_exit(void)
+{
+       pci_unregister_driver(&mvs_pci_driver);
+       sas_release_transport(mvs_stt);
+}
+
+module_init(mvs_init);
+module_exit(mvs_exit);
+
+MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
+MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, mvs_pci_table);
index e4acebd..6a583c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
-       mvsas.c - Marvell 88SE6440 SAS/SATA support
+       mv_sas.c - Marvell 88SE6440 SAS/SATA support
 
        Copyright 2007 Red Hat, Inc.
        Copyright 2008 Marvell. <kewei@marvell.com>
 
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/ctype.h>
-#include <scsi/libsas.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/sas_ata.h>
-#include <asm/io.h>
-
-#define DRV_NAME       "mvsas"
-#define DRV_VERSION    "0.5.2"
-#define _MV_DUMP       0
-#define MVS_DISABLE_NVRAM
-#define MVS_DISABLE_MSI
-
-#define mr32(reg)      readl(regs + MVS_##reg)
-#define mw32(reg,val)  writel((val), regs + MVS_##reg)
-#define mw32_f(reg,val)        do {                    \
-       writel((val), regs + MVS_##reg);        \
-       readl(regs + MVS_##reg);                \
-       } while (0)
-
-#define MVS_ID_NOT_MAPPED      0x7f
-#define MVS_CHIP_SLOT_SZ       (1U << mvi->chip->slot_width)
+#include "mv_sas.h"
+#include "mv_64xx.h"
+#include "mv_chips.h"
 
 /* offset for D2H FIS in the Received FIS List Structure */
 #define SATA_RECEIVED_D2H_FIS(reg_set) \
 #define UNASSOC_D2H_FIS(id)            \
        ((void *) mvi->rx_fis + 0x100 * id)
 
-#define for_each_phy(__lseq_mask, __mc, __lseq, __rest)                        \
-       for ((__mc) = (__lseq_mask), (__lseq) = 0;                      \
-                                       (__mc) != 0 && __rest;          \
-                                       (++__lseq), (__mc) >>= 1)
-
-/* driver compile-time configuration */
-enum driver_configuration {
-       MVS_TX_RING_SZ          = 1024, /* TX ring size (12-bit) */
-       MVS_RX_RING_SZ          = 1024, /* RX ring size (12-bit) */
-                                       /* software requires power-of-2
-                                          ring size */
-
-       MVS_SLOTS               = 512,  /* command slots */
-       MVS_SLOT_BUF_SZ         = 8192, /* cmd tbl + IU + status + PRD */
-       MVS_SSP_CMD_SZ          = 64,   /* SSP command table buffer size */
-       MVS_ATA_CMD_SZ          = 96,   /* SATA command table buffer size */
-       MVS_OAF_SZ              = 64,   /* Open address frame buffer size */
-
-       MVS_RX_FIS_COUNT        = 17,   /* Optional rx'd FISs (max 17) */
-
-       MVS_QUEUE_SIZE          = 30,   /* Support Queue depth */
-       MVS_CAN_QUEUE           = MVS_SLOTS - 1,        /* SCSI Queue depth */
-};
-
-/* unchangeable hardware details */
-enum hardware_details {
-       MVS_MAX_PHYS            = 8,    /* max. possible phys */
-       MVS_MAX_PORTS           = 8,    /* max. possible ports */
-       MVS_RX_FISL_SZ          = 0x400 + (MVS_RX_FIS_COUNT * 0x100),
-};
-
-/* peripheral registers (BAR2) */
-enum peripheral_registers {
-       SPI_CTL                 = 0x10, /* EEPROM control */
-       SPI_CMD                 = 0x14, /* EEPROM command */
-       SPI_DATA                = 0x18, /* EEPROM data */
-};
-
-enum peripheral_register_bits {
-       TWSI_RDY                = (1U << 7),    /* EEPROM interface ready */
-       TWSI_RD                 = (1U << 4),    /* EEPROM read access */
-
-       SPI_ADDR_MASK           = 0x3ffff,      /* bits 17:0 */
-};
-
-/* enhanced mode registers (BAR4) */
-enum hw_registers {
-       MVS_GBL_CTL             = 0x04,  /* global control */
-       MVS_GBL_INT_STAT        = 0x08,  /* global irq status */
-       MVS_GBL_PI              = 0x0C,  /* ports implemented bitmask */
-       MVS_GBL_PORT_TYPE       = 0xa0,  /* port type */
-
-       MVS_CTL                 = 0x100, /* SAS/SATA port configuration */
-       MVS_PCS                 = 0x104, /* SAS/SATA port control/status */
-       MVS_CMD_LIST_LO         = 0x108, /* cmd list addr */
-       MVS_CMD_LIST_HI         = 0x10C,
-       MVS_RX_FIS_LO           = 0x110, /* RX FIS list addr */
-       MVS_RX_FIS_HI           = 0x114,
-
-       MVS_TX_CFG              = 0x120, /* TX configuration */
-       MVS_TX_LO               = 0x124, /* TX (delivery) ring addr */
-       MVS_TX_HI               = 0x128,
-
-       MVS_TX_PROD_IDX         = 0x12C, /* TX producer pointer */
-       MVS_TX_CONS_IDX         = 0x130, /* TX consumer pointer (RO) */
-       MVS_RX_CFG              = 0x134, /* RX configuration */
-       MVS_RX_LO               = 0x138, /* RX (completion) ring addr */
-       MVS_RX_HI               = 0x13C,
-       MVS_RX_CONS_IDX         = 0x140, /* RX consumer pointer (RO) */
-
-       MVS_INT_COAL            = 0x148, /* Int coalescing config */
-       MVS_INT_COAL_TMOUT      = 0x14C, /* Int coalescing timeout */
-       MVS_INT_STAT            = 0x150, /* Central int status */
-       MVS_INT_MASK            = 0x154, /* Central int enable */
-       MVS_INT_STAT_SRS        = 0x158, /* SATA register set status */
-       MVS_INT_MASK_SRS        = 0x15C,
-
-                                        /* ports 1-3 follow after this */
-       MVS_P0_INT_STAT         = 0x160, /* port0 interrupt status */
-       MVS_P0_INT_MASK         = 0x164, /* port0 interrupt mask */
-       MVS_P4_INT_STAT         = 0x200, /* Port 4 interrupt status */
-       MVS_P4_INT_MASK         = 0x204, /* Port 4 interrupt enable mask */
-
-                                        /* ports 1-3 follow after this */
-       MVS_P0_SER_CTLSTAT      = 0x180, /* port0 serial control/status */
-       MVS_P4_SER_CTLSTAT      = 0x220, /* port4 serial control/status */
-
-       MVS_CMD_ADDR            = 0x1B8, /* Command register port (addr) */
-       MVS_CMD_DATA            = 0x1BC, /* Command register port (data) */
-
-                                        /* ports 1-3 follow after this */
-       MVS_P0_CFG_ADDR         = 0x1C0, /* port0 phy register address */
-       MVS_P0_CFG_DATA         = 0x1C4, /* port0 phy register data */
-       MVS_P4_CFG_ADDR         = 0x230, /* Port 4 config address */
-       MVS_P4_CFG_DATA         = 0x234, /* Port 4 config data */
-
-                                        /* ports 1-3 follow after this */
-       MVS_P0_VSR_ADDR         = 0x1E0, /* port0 VSR address */
-       MVS_P0_VSR_DATA         = 0x1E4, /* port0 VSR data */
-       MVS_P4_VSR_ADDR         = 0x250, /* port 4 VSR addr */
-       MVS_P4_VSR_DATA         = 0x254, /* port 4 VSR data */
-};
-
-enum hw_register_bits {
-       /* MVS_GBL_CTL */
-       INT_EN                  = (1U << 1),    /* Global int enable */
-       HBA_RST                 = (1U << 0),    /* HBA reset */
-
-       /* MVS_GBL_INT_STAT */
-       INT_XOR                 = (1U << 4),    /* XOR engine event */
-       INT_SAS_SATA            = (1U << 0),    /* SAS/SATA event */
-
-       /* MVS_GBL_PORT_TYPE */                 /* shl for ports 1-3 */
-       SATA_TARGET             = (1U << 16),   /* port0 SATA target enable */
-       MODE_AUTO_DET_PORT7 = (1U << 15),       /* port0 SAS/SATA autodetect */
-       MODE_AUTO_DET_PORT6 = (1U << 14),
-       MODE_AUTO_DET_PORT5 = (1U << 13),
-       MODE_AUTO_DET_PORT4 = (1U << 12),
-       MODE_AUTO_DET_PORT3 = (1U << 11),
-       MODE_AUTO_DET_PORT2 = (1U << 10),
-       MODE_AUTO_DET_PORT1 = (1U << 9),
-       MODE_AUTO_DET_PORT0 = (1U << 8),
-       MODE_AUTO_DET_EN    =   MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
-                               MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
-                               MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
-                               MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
-       MODE_SAS_PORT7_MASK = (1U << 7),  /* port0 SAS(1), SATA(0) mode */
-       MODE_SAS_PORT6_MASK = (1U << 6),
-       MODE_SAS_PORT5_MASK = (1U << 5),
-       MODE_SAS_PORT4_MASK = (1U << 4),
-       MODE_SAS_PORT3_MASK = (1U << 3),
-       MODE_SAS_PORT2_MASK = (1U << 2),
-       MODE_SAS_PORT1_MASK = (1U << 1),
-       MODE_SAS_PORT0_MASK = (1U << 0),
-       MODE_SAS_SATA   =       MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
-                               MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
-                               MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
-                               MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
-
-                               /* SAS_MODE value may be
-                                * dictated (in hw) by values
-                                * of SATA_TARGET & AUTO_DET
-                                */
-
-       /* MVS_TX_CFG */
-       TX_EN                   = (1U << 16),   /* Enable TX */
-       TX_RING_SZ_MASK         = 0xfff,        /* TX ring size, bits 11:0 */
-
-       /* MVS_RX_CFG */
-       RX_EN                   = (1U << 16),   /* Enable RX */
-       RX_RING_SZ_MASK         = 0xfff,        /* RX ring size, bits 11:0 */
-
-       /* MVS_INT_COAL */
-       COAL_EN                 = (1U << 16),   /* Enable int coalescing */
-
-       /* MVS_INT_STAT, MVS_INT_MASK */
-       CINT_I2C                = (1U << 31),   /* I2C event */
-       CINT_SW0                = (1U << 30),   /* software event 0 */
-       CINT_SW1                = (1U << 29),   /* software event 1 */
-       CINT_PRD_BC             = (1U << 28),   /* PRD BC err for read cmd */
-       CINT_DMA_PCIE           = (1U << 27),   /* DMA to PCIE timeout */
-       CINT_MEM                = (1U << 26),   /* int mem parity err */
-       CINT_I2C_SLAVE          = (1U << 25),   /* slave I2C event */
-       CINT_SRS                = (1U << 3),    /* SRS event */
-       CINT_CI_STOP            = (1U << 1),    /* cmd issue stopped */
-       CINT_DONE               = (1U << 0),    /* cmd completion */
-
-                                               /* shl for ports 1-3 */
-       CINT_PORT_STOPPED       = (1U << 16),   /* port0 stopped */
-       CINT_PORT               = (1U << 8),    /* port0 event */
-       CINT_PORT_MASK_OFFSET   = 8,
-       CINT_PORT_MASK          = (0xFF << CINT_PORT_MASK_OFFSET),
-
-       /* TX (delivery) ring bits */
-       TXQ_CMD_SHIFT           = 29,
-       TXQ_CMD_SSP             = 1,            /* SSP protocol */
-       TXQ_CMD_SMP             = 2,            /* SMP protocol */
-       TXQ_CMD_STP             = 3,            /* STP/SATA protocol */
-       TXQ_CMD_SSP_FREE_LIST   = 4,            /* add to SSP targ free list */
-       TXQ_CMD_SLOT_RESET      = 7,            /* reset command slot */
-       TXQ_MODE_I              = (1U << 28),   /* mode: 0=target,1=initiator */
-       TXQ_PRIO_HI             = (1U << 27),   /* priority: 0=normal, 1=high */
-       TXQ_SRS_SHIFT           = 20,           /* SATA register set */
-       TXQ_SRS_MASK            = 0x7f,
-       TXQ_PHY_SHIFT           = 12,           /* PHY bitmap */
-       TXQ_PHY_MASK            = 0xff,
-       TXQ_SLOT_MASK           = 0xfff,        /* slot number */
-
-       /* RX (completion) ring bits */
-       RXQ_GOOD                = (1U << 23),   /* Response good */
-       RXQ_SLOT_RESET          = (1U << 21),   /* Slot reset complete */
-       RXQ_CMD_RX              = (1U << 20),   /* target cmd received */
-       RXQ_ATTN                = (1U << 19),   /* attention */
-       RXQ_RSP                 = (1U << 18),   /* response frame xfer'd */
-       RXQ_ERR                 = (1U << 17),   /* err info rec xfer'd */
-       RXQ_DONE                = (1U << 16),   /* cmd complete */
-       RXQ_SLOT_MASK           = 0xfff,        /* slot number */
-
-       /* mvs_cmd_hdr bits */
-       MCH_PRD_LEN_SHIFT       = 16,           /* 16-bit PRD table len */
-       MCH_SSP_FR_TYPE_SHIFT   = 13,           /* SSP frame type */
-
-                                               /* SSP initiator only */
-       MCH_SSP_FR_CMD          = 0x0,          /* COMMAND frame */
-
-                                               /* SSP initiator or target */
-       MCH_SSP_FR_TASK         = 0x1,          /* TASK frame */
-
-                                               /* SSP target only */
-       MCH_SSP_FR_XFER_RDY     = 0x4,          /* XFER_RDY frame */
-       MCH_SSP_FR_RESP         = 0x5,          /* RESPONSE frame */
-       MCH_SSP_FR_READ         = 0x6,          /* Read DATA frame(s) */
-       MCH_SSP_FR_READ_RESP    = 0x7,          /* ditto, plus RESPONSE */
-
-       MCH_PASSTHRU            = (1U << 12),   /* pass-through (SSP) */
-       MCH_FBURST              = (1U << 11),   /* first burst (SSP) */
-       MCH_CHK_LEN             = (1U << 10),   /* chk xfer len (SSP) */
-       MCH_RETRY               = (1U << 9),    /* tport layer retry (SSP) */
-       MCH_PROTECTION          = (1U << 8),    /* protection info rec (SSP) */
-       MCH_RESET               = (1U << 7),    /* Reset (STP/SATA) */
-       MCH_FPDMA               = (1U << 6),    /* First party DMA (STP/SATA) */
-       MCH_ATAPI               = (1U << 5),    /* ATAPI (STP/SATA) */
-       MCH_BIST                = (1U << 4),    /* BIST activate (STP/SATA) */
-       MCH_PMP_MASK            = 0xf,          /* PMP from cmd FIS (STP/SATA)*/
-
-       CCTL_RST                = (1U << 5),    /* port logic reset */
-
-                                               /* 0(LSB first), 1(MSB first) */
-       CCTL_ENDIAN_DATA        = (1U << 3),    /* PRD data */
-       CCTL_ENDIAN_RSP         = (1U << 2),    /* response frame */
-       CCTL_ENDIAN_OPEN        = (1U << 1),    /* open address frame */
-       CCTL_ENDIAN_CMD         = (1U << 0),    /* command table */
-
-       /* MVS_Px_SER_CTLSTAT (per-phy control) */
-       PHY_SSP_RST             = (1U << 3),    /* reset SSP link layer */
-       PHY_BCAST_CHG           = (1U << 2),    /* broadcast(change) notif */
-       PHY_RST_HARD            = (1U << 1),    /* hard reset + phy reset */
-       PHY_RST                 = (1U << 0),    /* phy reset */
-       PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
-       PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
-       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
-       PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
-                       (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
-       PHY_READY_MASK          = (1U << 20),
-
-       /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
-       PHYEV_DEC_ERR           = (1U << 24),   /* Phy Decoding Error */
-       PHYEV_UNASSOC_FIS       = (1U << 19),   /* unassociated FIS rx'd */
-       PHYEV_AN                = (1U << 18),   /* SATA async notification */
-       PHYEV_BIST_ACT          = (1U << 17),   /* BIST activate FIS */
-       PHYEV_SIG_FIS           = (1U << 16),   /* signature FIS */
-       PHYEV_POOF              = (1U << 12),   /* phy ready from 1 -> 0 */
-       PHYEV_IU_BIG            = (1U << 11),   /* IU too long err */
-       PHYEV_IU_SMALL          = (1U << 10),   /* IU too short err */
-       PHYEV_UNK_TAG           = (1U << 9),    /* unknown tag */
-       PHYEV_BROAD_CH          = (1U << 8),    /* broadcast(CHANGE) */
-       PHYEV_COMWAKE           = (1U << 7),    /* COMWAKE rx'd */
-       PHYEV_PORT_SEL          = (1U << 6),    /* port selector present */
-       PHYEV_HARD_RST          = (1U << 5),    /* hard reset rx'd */
-       PHYEV_ID_TMOUT          = (1U << 4),    /* identify timeout */
-       PHYEV_ID_FAIL           = (1U << 3),    /* identify failed */
-       PHYEV_ID_DONE           = (1U << 2),    /* identify done */
-       PHYEV_HARD_RST_DONE     = (1U << 1),    /* hard reset done */
-       PHYEV_RDY_CH            = (1U << 0),    /* phy ready changed state */
-
-       /* MVS_PCS */
-       PCS_EN_SATA_REG_SHIFT   = (16),         /* Enable SATA Register Set */
-       PCS_EN_PORT_XMT_SHIFT   = (12),         /* Enable Port Transmit */
-       PCS_EN_PORT_XMT_SHIFT2  = (8),          /* For 6480 */
-       PCS_SATA_RETRY          = (1U << 8),    /* retry ctl FIS on R_ERR */
-       PCS_RSP_RX_EN           = (1U << 7),    /* raw response rx */
-       PCS_SELF_CLEAR          = (1U << 5),    /* self-clearing int mode */
-       PCS_FIS_RX_EN           = (1U << 4),    /* FIS rx enable */
-       PCS_CMD_STOP_ERR        = (1U << 3),    /* cmd stop-on-err enable */
-       PCS_CMD_RST             = (1U << 1),    /* reset cmd issue */
-       PCS_CMD_EN              = (1U << 0),    /* enable cmd issue */
-
-       /* Port n Attached Device Info */
-       PORT_DEV_SSP_TRGT       = (1U << 19),
-       PORT_DEV_SMP_TRGT       = (1U << 18),
-       PORT_DEV_STP_TRGT       = (1U << 17),
-       PORT_DEV_SSP_INIT       = (1U << 11),
-       PORT_DEV_SMP_INIT       = (1U << 10),
-       PORT_DEV_STP_INIT       = (1U << 9),
-       PORT_PHY_ID_MASK        = (0xFFU << 24),
-       PORT_DEV_TRGT_MASK      = (0x7U << 17),
-       PORT_DEV_INIT_MASK      = (0x7U << 9),
-       PORT_DEV_TYPE_MASK      = (0x7U << 0),
-
-       /* Port n PHY Status */
-       PHY_RDY                 = (1U << 2),
-       PHY_DW_SYNC             = (1U << 1),
-       PHY_OOB_DTCTD           = (1U << 0),
-
-       /* VSR */
-       /* PHYMODE 6 (CDB) */
-       PHY_MODE6_LATECLK       = (1U << 29),   /* Lock Clock */
-       PHY_MODE6_DTL_SPEED     = (1U << 27),   /* Digital Loop Speed */
-       PHY_MODE6_FC_ORDER      = (1U << 26),   /* Fibre Channel Mode Order*/
-       PHY_MODE6_MUCNT_EN      = (1U << 24),   /* u Count Enable */
-       PHY_MODE6_SEL_MUCNT_LEN = (1U << 22),   /* Training Length Select */
-       PHY_MODE6_SELMUPI       = (1U << 20),   /* Phase Multi Select (init) */
-       PHY_MODE6_SELMUPF       = (1U << 18),   /* Phase Multi Select (final) */
-       PHY_MODE6_SELMUFF       = (1U << 16),   /* Freq Loop Multi Sel(final) */
-       PHY_MODE6_SELMUFI       = (1U << 14),   /* Freq Loop Multi Sel(init) */
-       PHY_MODE6_FREEZE_LOOP   = (1U << 12),   /* Freeze Rx CDR Loop */
-       PHY_MODE6_INT_RXFOFFS   = (1U << 3),    /* Rx CDR Freq Loop Enable */
-       PHY_MODE6_FRC_RXFOFFS   = (1U << 2),    /* Initial Rx CDR Offset */
-       PHY_MODE6_STAU_0D8      = (1U << 1),    /* Rx CDR Freq Loop Saturate */
-       PHY_MODE6_RXSAT_DIS     = (1U << 0),    /* Saturate Ctl */
-};
-
-enum mvs_info_flags {
-       MVF_MSI                 = (1U << 0),    /* MSI is enabled */
-       MVF_PHY_PWR_FIX         = (1U << 1),    /* bug workaround */
-};
-
-enum sas_cmd_port_registers {
-       CMD_CMRST_OOB_DET       = 0x100, /* COMRESET OOB detect register */
-       CMD_CMWK_OOB_DET        = 0x104, /* COMWAKE OOB detect register */
-       CMD_CMSAS_OOB_DET       = 0x108, /* COMSAS OOB detect register */
-       CMD_BRST_OOB_DET        = 0x10c, /* burst OOB detect register */
-       CMD_OOB_SPACE           = 0x110, /* OOB space control register */
-       CMD_OOB_BURST           = 0x114, /* OOB burst control register */
-       CMD_PHY_TIMER           = 0x118, /* PHY timer control register */
-       CMD_PHY_CONFIG0         = 0x11c, /* PHY config register 0 */
-       CMD_PHY_CONFIG1         = 0x120, /* PHY config register 1 */
-       CMD_SAS_CTL0            = 0x124, /* SAS control register 0 */
-       CMD_SAS_CTL1            = 0x128, /* SAS control register 1 */
-       CMD_SAS_CTL2            = 0x12c, /* SAS control register 2 */
-       CMD_SAS_CTL3            = 0x130, /* SAS control register 3 */
-       CMD_ID_TEST             = 0x134, /* ID test register */
-       CMD_PL_TIMER            = 0x138, /* PL timer register */
-       CMD_WD_TIMER            = 0x13c, /* WD timer register */
-       CMD_PORT_SEL_COUNT      = 0x140, /* port selector count register */
-       CMD_APP_MEM_CTL         = 0x144, /* Application Memory Control */
-       CMD_XOR_MEM_CTL         = 0x148, /* XOR Block Memory Control */
-       CMD_DMA_MEM_CTL         = 0x14c, /* DMA Block Memory Control */
-       CMD_PORT_MEM_CTL0       = 0x150, /* Port Memory Control 0 */
-       CMD_PORT_MEM_CTL1       = 0x154, /* Port Memory Control 1 */
-       CMD_SATA_PORT_MEM_CTL0  = 0x158, /* SATA Port Memory Control 0 */
-       CMD_SATA_PORT_MEM_CTL1  = 0x15c, /* SATA Port Memory Control 1 */
-       CMD_XOR_MEM_BIST_CTL    = 0x160, /* XOR Memory BIST Control */
-       CMD_XOR_MEM_BIST_STAT   = 0x164, /* XOR Memroy BIST Status */
-       CMD_DMA_MEM_BIST_CTL    = 0x168, /* DMA Memory BIST Control */
-       CMD_DMA_MEM_BIST_STAT   = 0x16c, /* DMA Memory BIST Status */
-       CMD_PORT_MEM_BIST_CTL   = 0x170, /* Port Memory BIST Control */
-       CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */
-       CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */
-       CMD_STP_MEM_BIST_CTL    = 0x17c, /* STP Memory BIST Control */
-       CMD_STP_MEM_BIST_STAT0  = 0x180, /* STP Memory BIST Status 0 */
-       CMD_STP_MEM_BIST_STAT1  = 0x184, /* STP Memory BIST Status 1 */
-       CMD_RESET_COUNT         = 0x188, /* Reset Count */
-       CMD_MONTR_DATA_SEL      = 0x18C, /* Monitor Data/Select */
-       CMD_PLL_PHY_CONFIG      = 0x190, /* PLL/PHY Configuration */
-       CMD_PHY_CTL             = 0x194, /* PHY Control and Status */
-       CMD_PHY_TEST_COUNT0     = 0x198, /* Phy Test Count 0 */
-       CMD_PHY_TEST_COUNT1     = 0x19C, /* Phy Test Count 1 */
-       CMD_PHY_TEST_COUNT2     = 0x1A0, /* Phy Test Count 2 */
-       CMD_APP_ERR_CONFIG      = 0x1A4, /* Application Error Configuration */
-       CMD_PND_FIFO_CTL0       = 0x1A8, /* Pending FIFO Control 0 */
-       CMD_HOST_CTL            = 0x1AC, /* Host Control Status */
-       CMD_HOST_WR_DATA        = 0x1B0, /* Host Write Data */
-       CMD_HOST_RD_DATA        = 0x1B4, /* Host Read Data */
-       CMD_PHY_MODE_21         = 0x1B8, /* Phy Mode 21 */
-       CMD_SL_MODE0            = 0x1BC, /* SL Mode 0 */
-       CMD_SL_MODE1            = 0x1C0, /* SL Mode 1 */
-       CMD_PND_FIFO_CTL1       = 0x1C4, /* Pending FIFO Control 1 */
-};
-
-/* SAS/SATA configuration port registers, aka phy registers */
-enum sas_sata_config_port_regs {
-       PHYR_IDENTIFY           = 0x00, /* info for IDENTIFY frame */
-       PHYR_ADDR_LO            = 0x04, /* my SAS address (low) */
-       PHYR_ADDR_HI            = 0x08, /* my SAS address (high) */
-       PHYR_ATT_DEV_INFO       = 0x0C, /* attached device info */
-       PHYR_ATT_ADDR_LO        = 0x10, /* attached dev SAS addr (low) */
-       PHYR_ATT_ADDR_HI        = 0x14, /* attached dev SAS addr (high) */
-       PHYR_SATA_CTL           = 0x18, /* SATA control */
-       PHYR_PHY_STAT           = 0x1C, /* PHY status */
-       PHYR_SATA_SIG0          = 0x20, /*port SATA signature FIS(Byte 0-3) */
-       PHYR_SATA_SIG1          = 0x24, /*port SATA signature FIS(Byte 4-7) */
-       PHYR_SATA_SIG2          = 0x28, /*port SATA signature FIS(Byte 8-11) */
-       PHYR_SATA_SIG3          = 0x2c, /*port SATA signature FIS(Byte 12-15) */
-       PHYR_R_ERR_COUNT        = 0x30, /* port R_ERR count register */
-       PHYR_CRC_ERR_COUNT      = 0x34, /* port CRC error count register */
-       PHYR_WIDE_PORT          = 0x38, /* wide port participating */
-       PHYR_CURRENT0           = 0x80, /* current connection info 0 */
-       PHYR_CURRENT1           = 0x84, /* current connection info 1 */
-       PHYR_CURRENT2           = 0x88, /* current connection info 2 */
-};
-
-/*  SAS/SATA Vendor Specific Port Registers */
-enum sas_sata_vsp_regs {
-       VSR_PHY_STAT            = 0x00, /* Phy Status */
-       VSR_PHY_MODE1           = 0x01, /* phy tx */
-       VSR_PHY_MODE2           = 0x02, /* tx scc */
-       VSR_PHY_MODE3           = 0x03, /* pll */
-       VSR_PHY_MODE4           = 0x04, /* VCO */
-       VSR_PHY_MODE5           = 0x05, /* Rx */
-       VSR_PHY_MODE6           = 0x06, /* CDR */
-       VSR_PHY_MODE7           = 0x07, /* Impedance */
-       VSR_PHY_MODE8           = 0x08, /* Voltage */
-       VSR_PHY_MODE9           = 0x09, /* Test */
-       VSR_PHY_MODE10          = 0x0A, /* Power */
-       VSR_PHY_MODE11          = 0x0B, /* Phy Mode */
-       VSR_PHY_VS0             = 0x0C, /* Vednor Specific 0 */
-       VSR_PHY_VS1             = 0x0D, /* Vednor Specific 1 */
-};
-
-enum pci_cfg_registers {
-       PCR_PHY_CTL     = 0x40,
-       PCR_PHY_CTL2    = 0x90,
-       PCR_DEV_CTRL    = 0xE8,
-};
-
-enum pci_cfg_register_bits {
-       PCTL_PWR_ON     = (0xFU << 24),
-       PCTL_OFF        = (0xFU << 12),
-       PRD_REQ_SIZE    = (0x4000),
-       PRD_REQ_MASK    = (0x00007000),
-};
-
-enum nvram_layout_offsets {
-       NVR_SIG         = 0x00,         /* 0xAA, 0x55 */
-       NVR_SAS_ADDR    = 0x02,         /* 8-byte SAS address */
-};
-
-enum chip_flavors {
-       chip_6320,
-       chip_6440,
-       chip_6480,
-};
-
-enum port_type {
-       PORT_TYPE_SAS   =  (1L << 1),
-       PORT_TYPE_SATA  =  (1L << 0),
-};
-
-/* Command Table Format */
-enum ct_format {
-       /* SSP */
-       SSP_F_H         =  0x00,
-       SSP_F_IU        =  0x18,
-       SSP_F_MAX       =  0x4D,
-       /* STP */
-       STP_CMD_FIS     =  0x00,
-       STP_ATAPI_CMD   =  0x40,
-       STP_F_MAX       =  0x10,
-       /* SMP */
-       SMP_F_T         =  0x00,
-       SMP_F_DEP       =  0x01,
-       SMP_F_MAX       =  0x101,
-};
-
-enum status_buffer {
-       SB_EIR_OFF      =  0x00,        /* Error Information Record */
-       SB_RFB_OFF      =  0x08,        /* Response Frame Buffer */
-       SB_RFB_MAX      =  0x400,       /* RFB size*/
-};
-
-enum error_info_rec {
-       CMD_ISS_STPD    = (1U << 31),   /* Cmd Issue Stopped */
-       CMD_PI_ERR      = (1U << 30),   /* Protection info error.  see flags2 */
-       RSP_OVER        = (1U << 29),   /* rsp buffer overflow */
-       RETRY_LIM       = (1U << 28),   /* FIS/frame retry limit exceeded */
-       UNK_FIS         = (1U << 27),   /* unknown FIS */
-       DMA_TERM        = (1U << 26),   /* DMA terminate primitive rx'd */
-       SYNC_ERR        = (1U << 25),   /* SYNC rx'd during frame xmit */
-       TFILE_ERR       = (1U << 24),   /* SATA taskfile Error bit set */
-       R_ERR           = (1U << 23),   /* SATA returned R_ERR prim */
-       RD_OFS          = (1U << 20),   /* Read DATA frame invalid offset */
-       XFER_RDY_OFS    = (1U << 19),   /* XFER_RDY offset error */
-       UNEXP_XFER_RDY  = (1U << 18),   /* unexpected XFER_RDY error */
-       DATA_OVER_UNDER = (1U << 16),   /* data overflow/underflow */
-       INTERLOCK       = (1U << 15),   /* interlock error */
-       NAK             = (1U << 14),   /* NAK rx'd */
-       ACK_NAK_TO      = (1U << 13),   /* ACK/NAK timeout */
-       CXN_CLOSED      = (1U << 12),   /* cxn closed w/out ack/nak */
-       OPEN_TO         = (1U << 11),   /* I_T nexus lost, open cxn timeout */
-       PATH_BLOCKED    = (1U << 10),   /* I_T nexus lost, pathway blocked */
-       NO_DEST         = (1U << 9),    /* I_T nexus lost, no destination */
-       STP_RES_BSY     = (1U << 8),    /* STP resources busy */
-       BREAK           = (1U << 7),    /* break received */
-       BAD_DEST        = (1U << 6),    /* bad destination */
-       BAD_PROTO       = (1U << 5),    /* protocol not supported */
-       BAD_RATE        = (1U << 4),    /* cxn rate not supported */
-       WRONG_DEST      = (1U << 3),    /* wrong destination error */
-       CREDIT_TO       = (1U << 2),    /* credit timeout */
-       WDOG_TO         = (1U << 1),    /* watchdog timeout */
-       BUF_PAR         = (1U << 0),    /* buffer parity error */
-};
-
-enum error_info_rec_2 {
-       SLOT_BSY_ERR    = (1U << 31),   /* Slot Busy Error */
-       GRD_CHK_ERR     = (1U << 14),   /* Guard Check Error */
-       APP_CHK_ERR     = (1U << 13),   /* Application Check error */
-       REF_CHK_ERR     = (1U << 12),   /* Reference Check Error */
-       USR_BLK_NM      = (1U << 0),    /* User Block Number */
-};
-
-struct mvs_chip_info {
-       u32             n_phy;
-       u32             srs_sz;
-       u32             slot_width;
-};
-
-struct mvs_err_info {
-       __le32                  flags;
-       __le32                  flags2;
-};
-
-struct mvs_prd {
-       __le64                  addr;           /* 64-bit buffer address */
-       __le32                  reserved;
-       __le32                  len;            /* 16-bit length */
-};
-
-struct mvs_cmd_hdr {
-       __le32                  flags;          /* PRD tbl len; SAS, SATA ctl */
-       __le32                  lens;           /* cmd, max resp frame len */
-       __le32                  tags;           /* targ port xfer tag; tag */
-       __le32                  data_len;       /* data xfer len */
-       __le64                  cmd_tbl;        /* command table address */
-       __le64                  open_frame;     /* open addr frame address */
-       __le64                  status_buf;     /* status buffer address */
-       __le64                  prd_tbl;        /* PRD tbl address */
-       __le32                  reserved[4];
-};
-
-struct mvs_port {
-       struct asd_sas_port     sas_port;
-       u8                      port_attached;
-       u8                      taskfileset;
-       u8                      wide_port_phymap;
-       struct list_head        list;
-};
-
-struct mvs_phy {
-       struct mvs_port         *port;
-       struct asd_sas_phy      sas_phy;
-       struct sas_identify     identify;
-       struct scsi_device      *sdev;
-       u64             dev_sas_addr;
-       u64             att_dev_sas_addr;
-       u32             att_dev_info;
-       u32             dev_info;
-       u32             phy_type;
-       u32             phy_status;
-       u32             irq_status;
-       u32             frame_rcvd_size;
-       u8              frame_rcvd[32];
-       u8              phy_attached;
-       enum sas_linkrate       minimum_linkrate;
-       enum sas_linkrate       maximum_linkrate;
-};
-
-struct mvs_slot_info {
-       struct list_head        list;
-       struct sas_task         *task;
-       u32                     n_elem;
-       u32                     tx;
-
-       /* DMA buffer for storing cmd tbl, open addr frame, status buffer,
-        * and PRD table
-        */
-       void                    *buf;
-       dma_addr_t              buf_dma;
-#if _MV_DUMP
-       u32                     cmd_size;
-#endif
-
-       void                    *response;
-       struct mvs_port         *port;
+struct mvs_task_exec_info {
+       struct sas_task *task;
+       struct mvs_cmd_hdr *hdr;
+       struct mvs_port *port;
+       u32 tag;
+       int n_elem;
 };
 
-struct mvs_info {
-       unsigned long           flags;
-
-       spinlock_t              lock;           /* host-wide lock */
-       struct pci_dev          *pdev;          /* our device */
-       void __iomem            *regs;          /* enhanced mode registers */
-       void __iomem            *peri_regs;     /* peripheral registers */
-
-       u8                      sas_addr[SAS_ADDR_SIZE];
-       struct sas_ha_struct    sas;            /* SCSI/SAS glue */
-       struct Scsi_Host        *shost;
-
-       __le32                  *tx;            /* TX (delivery) DMA ring */
-       dma_addr_t              tx_dma;
-       u32                     tx_prod;        /* cached next-producer idx */
-
-       __le32                  *rx;            /* RX (completion) DMA ring */
-       dma_addr_t              rx_dma;
-       u32                     rx_cons;        /* RX consumer idx */
-
-       __le32                  *rx_fis;        /* RX'd FIS area */
-       dma_addr_t              rx_fis_dma;
-
-       struct mvs_cmd_hdr      *slot;  /* DMA command header slots */
-       dma_addr_t              slot_dma;
-
-       const struct mvs_chip_info *chip;
+static void mvs_release_task(struct mvs_info *mvi, int phy_no);
+static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i);
+static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
+                                       int get_st);
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
+static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task,
+                               u32 slot_idx);
 
-       u8                      tags[MVS_SLOTS];
-       struct mvs_slot_info    slot_info[MVS_SLOTS];
-                               /* further per-slot information */
-       struct mvs_phy          phy[MVS_MAX_PHYS];
-       struct mvs_port         port[MVS_MAX_PHYS];
-#ifdef MVS_USE_TASKLET
-       struct tasklet_struct   tasklet;
-#endif
-};
+static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
+{
+       if (task->lldd_task) {
+               struct mvs_slot_info *slot;
+               slot = (struct mvs_slot_info *) task->lldd_task;
+               *tag = slot - mvi->slot_info;
+               return 1;
+       }
+       return 0;
+}
 
-static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
-                          void *funcdata);
-static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port);
-static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val);
-static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port);
-static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val);
-static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val);
-static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port);
+static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
+{
+       void *bitmap = (void *) &mvi->tags;
+       clear_bit(tag, bitmap);
+}
 
-static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i);
-static void mvs_detect_porttype(struct mvs_info *mvi, int i);
-static void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
-static void mvs_release_task(struct mvs_info *mvi, int phy_no);
+static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
+{
+       mvs_tag_clear(mvi, tag);
+}
 
-static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
-static void mvs_scan_start(struct Scsi_Host *);
-static int mvs_slave_configure(struct scsi_device *sdev);
+static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
+{
+       void *bitmap = (void *) &mvi->tags;
+       set_bit(tag, bitmap);
+}
 
-static struct scsi_transport_template *mvs_stt;
+static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
+{
+       unsigned int index, tag;
+       void *bitmap = (void *) &mvi->tags;
 
-static const struct mvs_chip_info mvs_chips[] = {
-       [chip_6320] =           { 2, 16, 9  },
-       [chip_6440] =           { 4, 16, 9  },
-       [chip_6480] =           { 8, 32, 10 },
-};
+       index = find_first_zero_bit(bitmap, MVS_SLOTS);
+       tag = index;
+       if (tag >= MVS_SLOTS)
+               return -SAS_QUEUE_FULL;
+       mvs_tag_set(mvi, tag);
+       *tag_out = tag;
+       return 0;
+}
 
-static struct scsi_host_template mvs_sht = {
-       .module                 = THIS_MODULE,
-       .name                   = DRV_NAME,
-       .queuecommand           = sas_queuecommand,
-       .target_alloc           = sas_target_alloc,
-       .slave_configure        = mvs_slave_configure,
-       .slave_destroy          = sas_slave_destroy,
-       .scan_finished          = mvs_scan_finished,
-       .scan_start             = mvs_scan_start,
-       .change_queue_depth     = sas_change_queue_depth,
-       .change_queue_type      = sas_change_queue_type,
-       .bios_param             = sas_bios_param,
-       .can_queue              = 1,
-       .cmd_per_lun            = 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,
-       .slave_alloc            = sas_slave_alloc,
-       .target_destroy         = sas_target_destroy,
-       .ioctl                  = sas_ioctl,
-};
+void mvs_tag_init(struct mvs_info *mvi)
+{
+       int i;
+       for (i = 0; i < MVS_SLOTS; ++i)
+               mvs_tag_clear(mvi, i);
+}
 
 static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
 {
@@ -848,959 +223,270 @@ static void mvs_hba_cq_dump(struct mvs_info *mvi)
 #endif
 }
 
-static void mvs_hba_interrupt_enable(struct mvs_info *mvi)
+/* FIXME: locking? */
+int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata)
 {
-       void __iomem *regs = mvi->regs;
+       struct mvs_info *mvi = sas_phy->ha->lldd_ha;
+       int rc = 0, phy_id = sas_phy->id;
        u32 tmp;
 
-       tmp = mr32(GBL_CTL);
-
-       mw32(GBL_CTL, tmp | INT_EN);
-}
+       tmp = mvs_read_phy_ctl(mvi, phy_id);
 
-static void mvs_hba_interrupt_disable(struct mvs_info *mvi)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp;
+       switch (func) {
+       case PHY_FUNC_SET_LINK_RATE:{
+                       struct sas_phy_linkrates *rates = funcdata;
+                       u32 lrmin = 0, lrmax = 0;
 
-       tmp = mr32(GBL_CTL);
+                       lrmin = (rates->minimum_linkrate << 8);
+                       lrmax = (rates->maximum_linkrate << 12);
 
-       mw32(GBL_CTL, tmp & ~INT_EN);
-}
+                       if (lrmin) {
+                               tmp &= ~(0xf << 8);
+                               tmp |= lrmin;
+                       }
+                       if (lrmax) {
+                               tmp &= ~(0xf << 12);
+                               tmp |= lrmax;
+                       }
+                       mvs_write_phy_ctl(mvi, phy_id, tmp);
+                       break;
+               }
 
-static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
+       case PHY_FUNC_HARD_RESET:
+               if (tmp & PHY_RST_HARD)
+                       break;
+               mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD);
+               break;
 
-/* move to PCI layer or libata core? */
-static int pci_go_64(struct pci_dev *pdev)
-{
-       int rc;
+       case PHY_FUNC_LINK_RESET:
+               mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST);
+               break;
 
-       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
-               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-               if (rc) {
-                       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-                       if (rc) {
-                               dev_printk(KERN_ERR, &pdev->dev,
-                                          "64-bit DMA enable failed\n");
-                               return rc;
-                       }
-               }
-       } else {
-               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (rc) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "32-bit DMA enable failed\n");
-                       return rc;
-               }
-               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (rc) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "32-bit consistent DMA enable failed\n");
-                       return rc;
-               }
+       case PHY_FUNC_DISABLE:
+       case PHY_FUNC_RELEASE_SPINUP_HOLD:
+       default:
+               rc = -EOPNOTSUPP;
        }
 
        return rc;
 }
 
-static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
+static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
 {
-       if (task->lldd_task) {
-               struct mvs_slot_info *slot;
-               slot = (struct mvs_slot_info *) task->lldd_task;
-               *tag = slot - mvi->slot_info;
-               return 1;
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
+
+       if (!phy->phy_attached)
+               return;
+
+       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;
+               sphy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
        }
-       return 0;
-}
 
-static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
-{
-       void *bitmap = (void *) &mvi->tags;
-       clear_bit(tag, bitmap);
-}
+       if (phy->phy_type & PORT_TYPE_SAS) {
+               struct sas_identify_frame *id;
 
-static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
-{
-       mvs_tag_clear(mvi, tag);
+               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) {
+               /* TODO */
+       }
+       mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
+       mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
+                                  PORTE_BYTES_DMAED);
 }
 
-static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
+int mvs_slave_configure(struct scsi_device *sdev)
 {
-       void *bitmap = (void *) &mvi->tags;
-       set_bit(tag, bitmap);
-}
+       struct domain_device *dev = sdev_to_domain_dev(sdev);
+       int ret = sas_slave_configure(sdev);
 
-static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
-{
-       unsigned int index, tag;
-       void *bitmap = (void *) &mvi->tags;
+       if (ret)
+               return ret;
 
-       index = find_first_zero_bit(bitmap, MVS_SLOTS);
-       tag = index;
-       if (tag >= MVS_SLOTS)
-               return -SAS_QUEUE_FULL;
-       mvs_tag_set(mvi, tag);
-       *tag_out = tag;
+       if (dev_is_sata(dev)) {
+               /* struct ata_port *ap = dev->sata_dev.ap; */
+               /* struct ata_device *adev = ap->link.device; */
+
+               /* clamp at no NCQ for the time being */
+               /* adev->flags |= ATA_DFLAG_NCQ_OFF; */
+               scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
+       }
        return 0;
 }
 
-static void mvs_tag_init(struct mvs_info *mvi)
+void mvs_scan_start(struct Scsi_Host *shost)
 {
        int i;
-       for (i = 0; i < MVS_SLOTS; ++i)
-               mvs_tag_clear(mvi, i);
+       struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
+
+       for (i = 0; i < mvi->chip->n_phy; ++i) {
+               mvs_bytes_dmaed(mvi, i);
+       }
 }
 
-#ifndef MVS_DISABLE_NVRAM
-static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data)
+int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
-       int timeout = 1000;
-
-       if (addr & ~SPI_ADDR_MASK)
-               return -EINVAL;
-
-       writel(addr, regs + SPI_CMD);
-       writel(TWSI_RD, regs + SPI_CTL);
-
-       while (timeout-- > 0) {
-               if (readl(regs + SPI_CTL) & TWSI_RDY) {
-                       *data = readl(regs + SPI_DATA);
-                       return 0;
-               }
-
-               udelay(10);
-       }
-
-       return -EBUSY;
+       /* give the phy enabling interrupt event time to come in (1s
+        * is empirically about all it takes) */
+       if (time < HZ)
+               return 0;
+       /* Wait for discovery to finish */
+       scsi_flush_work(shost);
+       return 1;
 }
 
-static int mvs_eep_read_buf(void __iomem *regs, u32 addr,
-                           void *buf, u32 buflen)
+static int mvs_task_prep_smp(struct mvs_info *mvi,
+                            struct mvs_task_exec_info *tei)
 {
-       u32 addr_end, tmp_addr, i, j;
-       u32 tmp = 0;
-       int rc;
-       u8 *tmp8, *buf8 = buf;
-
-       addr_end = addr + buflen;
-       tmp_addr = ALIGN(addr, 4);
-       if (addr > 0xff)
-               return -EINVAL;
-
-       j = addr & 0x3;
-       if (j) {
-               rc = mvs_eep_read(regs, tmp_addr, &tmp);
-               if (rc)
-                       return rc;
+       int elem, rc, i;
+       struct sas_task *task = tei->task;
+       struct mvs_cmd_hdr *hdr = tei->hdr;
+       struct scatterlist *sg_req, *sg_resp;
+       u32 req_len, resp_len, tag = tei->tag;
+       void *buf_tmp;
+       u8 *buf_oaf;
+       dma_addr_t buf_tmp_dma;
+       struct mvs_prd *buf_prd;
+       struct scatterlist *sg;
+       struct mvs_slot_info *slot = &mvi->slot_info[tag];
+       struct asd_sas_port *sas_port = task->dev->port;
+       u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+#if _MV_DUMP
+       u8 *buf_cmd;
+       void *from;
+#endif
+       /*
+        * DMA-map SMP request, response buffers
+        */
+       sg_req = &task->smp_task.smp_req;
+       elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE);
+       if (!elem)
+               return -ENOMEM;
+       req_len = sg_dma_len(sg_req);
 
-               tmp8 = (u8 *)&tmp;
-               for (i = j; i < 4; i++)
-                       *buf8++ = tmp8[i];
+       sg_resp = &task->smp_task.smp_resp;
+       elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE);
+       if (!elem) {
+               rc = -ENOMEM;
+               goto err_out;
+       }
+       resp_len = sg_dma_len(sg_resp);
 
-               tmp_addr += 4;
+       /* must be in dwords */
+       if ((req_len & 0x3) || (resp_len & 0x3)) {
+               rc = -EINVAL;
+               goto err_out_2;
        }
 
-       for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) {
-               rc = mvs_eep_read(regs, tmp_addr, &tmp);
-               if (rc)
-                       return rc;
+       /*
+        * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+        */
 
-               memcpy(buf8, &tmp, 4);
-               buf8 += 4;
-       }
+       /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
+       buf_tmp = slot->buf;
+       buf_tmp_dma = slot->buf_dma;
 
-       if (tmp_addr < addr_end) {
-               rc = mvs_eep_read(regs, tmp_addr, &tmp);
-               if (rc)
-                       return rc;
+#if _MV_DUMP
+       buf_cmd = buf_tmp;
+       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+       buf_tmp += req_len;
+       buf_tmp_dma += req_len;
+       slot->cmd_size = req_len;
+#else
+       hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
+#endif
 
-               tmp8 = (u8 *)&tmp;
-               j = addr_end - tmp_addr;
-               for (i = 0; i < j; i++)
-                       *buf8++ = tmp8[i];
+       /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+       buf_oaf = buf_tmp;
+       hdr->open_frame = cpu_to_le64(buf_tmp_dma);
 
-               tmp_addr += 4;
-       }
+       buf_tmp += MVS_OAF_SZ;
+       buf_tmp_dma += MVS_OAF_SZ;
 
-       return 0;
-}
-#endif
+       /* region 3: PRD table ********************************************* */
+       buf_prd = buf_tmp;
+       if (tei->n_elem)
+               hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+       else
+               hdr->prd_tbl = 0;
 
-static int mvs_nvram_read(struct mvs_info *mvi, u32 addr,
-                         void *buf, u32 buflen)
-{
-#ifndef MVS_DISABLE_NVRAM
-       void __iomem *regs = mvi->regs;
-       int rc, i;
-       u32 sum;
-       u8 hdr[2], *tmp;
-       const char *msg;
+       i = sizeof(struct mvs_prd) * tei->n_elem;
+       buf_tmp += i;
+       buf_tmp_dma += i;
 
-       rc = mvs_eep_read_buf(regs, addr, &hdr, 2);
-       if (rc) {
-               msg = "nvram hdr read failed";
-               goto err_out;
-       }
-       rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen);
-       if (rc) {
-               msg = "nvram read failed";
-               goto err_out;
-       }
+       /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+       slot->response = buf_tmp;
+       hdr->status_buf = cpu_to_le64(buf_tmp_dma);
 
-       if (hdr[0] != 0x5A) {
-               /* entry id */
-               msg = "invalid nvram entry id";
-               rc = -ENOENT;
-               goto err_out;
-       }
+       /*
+        * Fill in TX ring and command slot header
+        */
+       slot->tx = mvi->tx_prod;
+       mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
+                                       TXQ_MODE_I | tag |
+                                       (sas_port->phy_mask << TXQ_PHY_SHIFT));
 
-       tmp = buf;
-       sum = ((u32)hdr[0]) + ((u32)hdr[1]);
-       for (i = 0; i < buflen; i++)
-               sum += ((u32)tmp[i]);
+       hdr->flags |= flags;
+       hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
+       hdr->tags = cpu_to_le32(tag);
+       hdr->data_len = 0;
 
-       if (sum) {
-               msg = "nvram checksum failure";
-               rc = -EILSEQ;
-               goto err_out;
+       /* generate open address frame hdr (first 12 bytes) */
+       buf_oaf[0] = (1 << 7) | (0 << 4) | 0x01; /* initiator, SMP, ftype 1h */
+       buf_oaf[1] = task->dev->linkrate & 0xf;
+       *(u16 *)(buf_oaf + 2) = 0xFFFF;         /* SAS SPEC */
+       memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
+
+       /* fill in PRD (scatter/gather) table, if any */
+       for_each_sg(task->scatter, sg, tei->n_elem, i) {
+               buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
+               buf_prd->len = cpu_to_le32(sg_dma_len(sg));
+               buf_prd++;
        }
 
+#if _MV_DUMP
+       /* copy cmd table */
+       from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
+       memcpy(buf_cmd, from + sg_req->offset, req_len);
+       kunmap_atomic(from, KM_IRQ0);
+#endif
        return 0;
 
+err_out_2:
+       pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1,
+                    PCI_DMA_FROMDEVICE);
 err_out:
-       dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
+       pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1,
+                    PCI_DMA_TODEVICE);
        return rc;
-#else
-       /* FIXME , For SAS target mode */
-       memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
-       return 0;
-#endif
 }
 
-static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
+static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
 {
-       struct mvs_phy *phy = &mvi->phy[i];
-       struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
-
-       if (!phy->phy_attached)
-               return;
-
-       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;
-               sphy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
-       }
-
-       if (phy->phy_type & PORT_TYPE_SAS) {
-               struct sas_identify_frame *id;
+       struct ata_queued_cmd *qc = task->uldd_task;
 
-               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) {
-               /* TODO */
+       if (qc) {
+               if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+                       qc->tf.command == ATA_CMD_FPDMA_READ) {
+                       *tag = qc->tag;
+                       return 1;
+               }
        }
-       mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
-       mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
-                                  PORTE_BYTES_DMAED);
-}
 
-static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
-{
-       /* give the phy enabling interrupt event time to come in (1s
-        * is empirically about all it takes) */
-       if (time < HZ)
-               return 0;
-       /* Wait for discovery to finish */
-       scsi_flush_work(shost);
-       return 1;
+       return 0;
 }
 
-static void mvs_scan_start(struct Scsi_Host *shost)
-{
-       int i;
-       struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
-
-       for (i = 0; i < mvi->chip->n_phy; ++i) {
-               mvs_bytes_dmaed(mvi, i);
-       }
-}
-
-static int mvs_slave_configure(struct scsi_device *sdev)
-{
-       struct domain_device *dev = sdev_to_domain_dev(sdev);
-       int ret = sas_slave_configure(sdev);
-
-       if (ret)
-               return ret;
-
-       if (dev_is_sata(dev)) {
-               /* struct ata_port *ap = dev->sata_dev.ap; */
-               /* struct ata_device *adev = ap->link.device; */
-
-               /* clamp at no NCQ for the time being */
-               /* adev->flags |= ATA_DFLAG_NCQ_OFF; */
-               scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
-       }
-       return 0;
-}
-
-static void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
-{
-       struct pci_dev *pdev = mvi->pdev;
-       struct sas_ha_struct *sas_ha = &mvi->sas;
-       struct mvs_phy *phy = &mvi->phy[phy_no];
-       struct asd_sas_phy *sas_phy = &phy->sas_phy;
-
-       phy->irq_status = mvs_read_port_irq_stat(mvi, phy_no);
-       /*
-       * events is port event now ,
-       * we need check the interrupt status which belongs to per port.
-       */
-       dev_printk(KERN_DEBUG, &pdev->dev,
-               "Port %d Event = %X\n",
-               phy_no, phy->irq_status);
-
-       if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) {
-               mvs_release_task(mvi, phy_no);
-               if (!mvs_is_phy_ready(mvi, phy_no)) {
-                       sas_phy_disconnected(sas_phy);
-                       sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
-                       dev_printk(KERN_INFO, &pdev->dev,
-                               "Port %d Unplug Notice\n", phy_no);
-
-               } else
-                       mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL);
-       }
-       if (!(phy->irq_status & PHYEV_DEC_ERR)) {
-               if (phy->irq_status & PHYEV_COMWAKE) {
-                       u32 tmp = mvs_read_port_irq_mask(mvi, phy_no);
-                       mvs_write_port_irq_mask(mvi, phy_no,
-                                               tmp | PHYEV_SIG_FIS);
-               }
-               if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
-                       phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
-                       if (phy->phy_status) {
-                               mvs_detect_porttype(mvi, phy_no);
-
-                               if (phy->phy_type & PORT_TYPE_SATA) {
-                                       u32 tmp = mvs_read_port_irq_mask(mvi,
-                                                               phy_no);
-                                       tmp &= ~PHYEV_SIG_FIS;
-                                       mvs_write_port_irq_mask(mvi,
-                                                               phy_no, tmp);
-                               }
-
-                               mvs_update_phyinfo(mvi, phy_no, 0);
-                               sas_ha->notify_phy_event(sas_phy,
-                                                       PHYE_OOB_DONE);
-                               mvs_bytes_dmaed(mvi, phy_no);
-                       } else {
-                               dev_printk(KERN_DEBUG, &pdev->dev,
-                                       "plugin interrupt but phy is gone\n");
-                               mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET,
-                                                       NULL);
-                       }
-               } else if (phy->irq_status & PHYEV_BROAD_CH) {
-                       mvs_release_task(mvi, phy_no);
-                       sas_ha->notify_port_event(sas_phy,
-                                               PORTE_BROADCAST_RCVD);
-               }
-       }
-       mvs_write_port_irq_stat(mvi, phy_no, phy->irq_status);
-}
-
-static void mvs_int_sata(struct mvs_info *mvi)
-{
-       u32 tmp;
-       void __iomem *regs = mvi->regs;
-       tmp = mr32(INT_STAT_SRS);
-       mw32(INT_STAT_SRS, tmp & 0xFFFF);
-}
-
-static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task,
-                               u32 slot_idx)
-{
-       void __iomem *regs = mvi->regs;
-       struct domain_device *dev = task->dev;
-       struct asd_sas_port *sas_port = dev->port;
-       struct mvs_port *port = mvi->slot_info[slot_idx].port;
-       u32 reg_set, phy_mask;
-
-       if (!sas_protocol_ata(task->task_proto)) {
-               reg_set = 0;
-               phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
-                               sas_port->phy_mask;
-       } else {
-               reg_set = port->taskfileset;
-               phy_mask = sas_port->phy_mask;
-       }
-       mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx |
-                                       (TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) |
-                                       (phy_mask << TXQ_PHY_SHIFT) |
-                                       (reg_set << TXQ_SRS_SHIFT));
-
-       mw32(TX_PROD_IDX, mvi->tx_prod);
-       mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
-}
-
-static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
-                       u32 slot_idx, int err)
-{
-       struct mvs_port *port = mvi->slot_info[slot_idx].port;
-       struct task_status_struct *tstat = &task->task_status;
-       struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
-       int stat = SAM_GOOD;
-
-       resp->frame_len = sizeof(struct dev_to_host_fis);
-       memcpy(&resp->ending_fis[0],
-              SATA_RECEIVED_D2H_FIS(port->taskfileset),
-              sizeof(struct dev_to_host_fis));
-       tstat->buf_valid_size = sizeof(*resp);
-       if (unlikely(err))
-               stat = SAS_PROTO_RESPONSE;
-       return stat;
-}
-
-static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
-{
-       u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
-       mvs_tag_clear(mvi, slot_idx);
-}
-
-static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
-                         struct mvs_slot_info *slot, u32 slot_idx)
-{
-       if (!sas_protocol_ata(task->task_proto))
-               if (slot->n_elem)
-                       pci_unmap_sg(mvi->pdev, task->scatter,
-                                    slot->n_elem, task->data_dir);
-
-       switch (task->task_proto) {
-       case SAS_PROTOCOL_SMP:
-               pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1,
-                            PCI_DMA_FROMDEVICE);
-               pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1,
-                            PCI_DMA_TODEVICE);
-               break;
-
-       case SAS_PROTOCOL_SATA:
-       case SAS_PROTOCOL_STP:
-       case SAS_PROTOCOL_SSP:
-       default:
-               /* do nothing */
-               break;
-       }
-       list_del(&slot->list);
-       task->lldd_task = NULL;
-       slot->task = NULL;
-       slot->port = NULL;
-}
-
-static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
-                        u32 slot_idx)
-{
-       struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
-       u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
-       u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4));
-       int stat = SAM_CHECK_COND;
-
-       if (err_dw1 & SLOT_BSY_ERR) {
-               stat = SAS_QUEUE_FULL;
-               mvs_slot_reset(mvi, task, slot_idx);
-       }
-       switch (task->task_proto) {
-       case SAS_PROTOCOL_SSP:
-               break;
-       case SAS_PROTOCOL_SMP:
-               break;
-       case SAS_PROTOCOL_SATA:
-       case SAS_PROTOCOL_STP:
-       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
-               if (err_dw0 & TFILE_ERR)
-                       stat = mvs_sata_done(mvi, task, slot_idx, 1);
-               break;
-       default:
-               break;
-       }
-
-       mvs_hexdump(16, (u8 *) slot->response, 0);
-       return stat;
-}
-
-static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
-{
-       u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
-       struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
-       struct sas_task *task = slot->task;
-       struct task_status_struct *tstat;
-       struct mvs_port *port;
-       bool aborted;
-       void *to;
-
-       if (unlikely(!task || !task->lldd_task))
-               return -1;
-
-       mvs_hba_cq_dump(mvi);
-
-       spin_lock(&task->task_state_lock);
-       aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
-       if (!aborted) {
-               task->task_state_flags &=
-                   ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
-               task->task_state_flags |= SAS_TASK_STATE_DONE;
-       }
-       spin_unlock(&task->task_state_lock);
-
-       if (aborted) {
-               mvs_slot_task_free(mvi, task, slot, slot_idx);
-               mvs_slot_free(mvi, rx_desc);
-               return -1;
-       }
-
-       port = slot->port;
-       tstat = &task->task_status;
-       memset(tstat, 0, sizeof(*tstat));
-       tstat->resp = SAS_TASK_COMPLETE;
-
-       if (unlikely(!port->port_attached || flags)) {
-               mvs_slot_err(mvi, task, slot_idx);
-               if (!sas_protocol_ata(task->task_proto))
-                       tstat->stat = SAS_PHY_DOWN;
-               goto out;
-       }
-
-       /* error info record present */
-       if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
-               tstat->stat = mvs_slot_err(mvi, task, slot_idx);
-               goto out;
-       }
-
-       switch (task->task_proto) {
-       case SAS_PROTOCOL_SSP:
-               /* hw says status == 0, datapres == 0 */
-               if (rx_desc & RXQ_GOOD) {
-                       tstat->stat = SAM_GOOD;
-                       tstat->resp = SAS_TASK_COMPLETE;
-               }
-               /* response frame present */
-               else if (rx_desc & RXQ_RSP) {
-                       struct ssp_response_iu *iu =
-                           slot->response + sizeof(struct mvs_err_info);
-                       sas_ssp_task_response(&mvi->pdev->dev, task, iu);
-               }
-
-               /* should never happen? */
-               else
-                       tstat->stat = SAM_CHECK_COND;
-               break;
-
-       case SAS_PROTOCOL_SMP: {
-                       struct scatterlist *sg_resp = &task->smp_task.smp_resp;
-                       tstat->stat = SAM_GOOD;
-                       to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
-                       memcpy(to + sg_resp->offset,
-                               slot->response + sizeof(struct mvs_err_info),
-                               sg_dma_len(sg_resp));
-                       kunmap_atomic(to, KM_IRQ0);
-                       break;
-               }
-
-       case SAS_PROTOCOL_SATA:
-       case SAS_PROTOCOL_STP:
-       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
-                       tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
-                       break;
-               }
-
-       default:
-               tstat->stat = SAM_CHECK_COND;
-               break;
-       }
-
-out:
-       mvs_slot_task_free(mvi, task, slot, slot_idx);
-       if (unlikely(tstat->stat != SAS_QUEUE_FULL))
-               mvs_slot_free(mvi, rx_desc);
-
-       spin_unlock(&mvi->lock);
-       task->task_done(task);
-       spin_lock(&mvi->lock);
-       return tstat->stat;
-}
-
-static void mvs_release_task(struct mvs_info *mvi, int phy_no)
-{
-       struct list_head *pos, *n;
-       struct mvs_slot_info *slot;
-       struct mvs_phy *phy = &mvi->phy[phy_no];
-       struct mvs_port *port = phy->port;
-       u32 rx_desc;
-
-       if (!port)
-               return;
-
-       list_for_each_safe(pos, n, &port->list) {
-               slot = container_of(pos, struct mvs_slot_info, list);
-               rx_desc = (u32) (slot - mvi->slot_info);
-               mvs_slot_complete(mvi, rx_desc, 1);
-       }
-}
-
-static void mvs_int_full(struct mvs_info *mvi)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp, stat;
-       int i;
-
-       stat = mr32(INT_STAT);
-
-       mvs_int_rx(mvi, false);
-
-       for (i = 0; i < MVS_MAX_PORTS; i++) {
-               tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
-               if (tmp)
-                       mvs_int_port(mvi, i, tmp);
-       }
-
-       if (stat & CINT_SRS)
-               mvs_int_sata(mvi);
-
-       mw32(INT_STAT, stat);
-}
-
-static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
-{
-       void __iomem *regs = mvi->regs;
-       u32 rx_prod_idx, rx_desc;
-       bool attn = false;
-       struct pci_dev *pdev = mvi->pdev;
-
-       /* the first dword in the RX ring is special: it contains
-        * a mirror of the hardware's RX producer index, so that
-        * we don't have to stall the CPU reading that register.
-        * The actual RX ring is offset by one dword, due to this.
-        */
-       rx_prod_idx = mvi->rx_cons;
-       mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
-       if (mvi->rx_cons == 0xfff)      /* h/w hasn't touched RX ring yet */
-               return 0;
-
-       /* The CMPL_Q may come late, read from register and try again
-       * note: if coalescing is enabled,
-       * it will need to read from register every time for sure
-       */
-       if (mvi->rx_cons == rx_prod_idx)
-               mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
-
-       if (mvi->rx_cons == rx_prod_idx)
-               return 0;
-
-       while (mvi->rx_cons != rx_prod_idx) {
-
-               /* increment our internal RX consumer pointer */
-               rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
-
-               rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
-
-               if (likely(rx_desc & RXQ_DONE))
-                       mvs_slot_complete(mvi, rx_desc, 0);
-               if (rx_desc & RXQ_ATTN) {
-                       attn = true;
-                       dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n",
-                               rx_desc);
-               } else if (rx_desc & RXQ_ERR) {
-                       if (!(rx_desc & RXQ_DONE))
-                               mvs_slot_complete(mvi, rx_desc, 0);
-                       dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n",
-                               rx_desc);
-               } else if (rx_desc & RXQ_SLOT_RESET) {
-                       dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n",
-                               rx_desc);
-                       mvs_slot_free(mvi, rx_desc);
-               }
-       }
-
-       if (attn && self_clear)
-               mvs_int_full(mvi);
-
-       return 0;
-}
-
-#ifdef MVS_USE_TASKLET
-static void mvs_tasklet(unsigned long data)
-{
-       struct mvs_info *mvi = (struct mvs_info *) data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&mvi->lock, flags);
-
-#ifdef MVS_DISABLE_MSI
-       mvs_int_full(mvi);
-#else
-       mvs_int_rx(mvi, true);
-#endif
-       spin_unlock_irqrestore(&mvi->lock, flags);
-}
-#endif
-
-static irqreturn_t mvs_interrupt(int irq, void *opaque)
-{
-       struct mvs_info *mvi = opaque;
-       void __iomem *regs = mvi->regs;
-       u32 stat;
-
-       stat = mr32(GBL_INT_STAT);
-
-       if (stat == 0 || stat == 0xffffffff)
-               return IRQ_NONE;
-
-       /* clear CMD_CMPLT ASAP */
-       mw32_f(INT_STAT, CINT_DONE);
-
-#ifndef MVS_USE_TASKLET
-       spin_lock(&mvi->lock);
-
-       mvs_int_full(mvi);
-
-       spin_unlock(&mvi->lock);
-#else
-       tasklet_schedule(&mvi->tasklet);
-#endif
-       return IRQ_HANDLED;
-}
-
-#ifndef MVS_DISABLE_MSI
-static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
-{
-       struct mvs_info *mvi = opaque;
-
-#ifndef MVS_USE_TASKLET
-       spin_lock(&mvi->lock);
-
-       mvs_int_rx(mvi, true);
-
-       spin_unlock(&mvi->lock);
-#else
-       tasklet_schedule(&mvi->tasklet);
-#endif
-       return IRQ_HANDLED;
-}
-#endif
-
-struct mvs_task_exec_info {
-       struct sas_task *task;
-       struct mvs_cmd_hdr *hdr;
-       struct mvs_port *port;
-       u32 tag;
-       int n_elem;
-};
-
-static int mvs_task_prep_smp(struct mvs_info *mvi,
-                            struct mvs_task_exec_info *tei)
-{
-       int elem, rc, i;
-       struct sas_task *task = tei->task;
-       struct mvs_cmd_hdr *hdr = tei->hdr;
-       struct scatterlist *sg_req, *sg_resp;
-       u32 req_len, resp_len, tag = tei->tag;
-       void *buf_tmp;
-       u8 *buf_oaf;
-       dma_addr_t buf_tmp_dma;
-       struct mvs_prd *buf_prd;
-       struct scatterlist *sg;
-       struct mvs_slot_info *slot = &mvi->slot_info[tag];
-       struct asd_sas_port *sas_port = task->dev->port;
-       u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-#if _MV_DUMP
-       u8 *buf_cmd;
-       void *from;
-#endif
-       /*
-        * DMA-map SMP request, response buffers
-        */
-       sg_req = &task->smp_task.smp_req;
-       elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE);
-       if (!elem)
-               return -ENOMEM;
-       req_len = sg_dma_len(sg_req);
-
-       sg_resp = &task->smp_task.smp_resp;
-       elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE);
-       if (!elem) {
-               rc = -ENOMEM;
-               goto err_out;
-       }
-       resp_len = sg_dma_len(sg_resp);
-
-       /* must be in dwords */
-       if ((req_len & 0x3) || (resp_len & 0x3)) {
-               rc = -EINVAL;
-               goto err_out_2;
-       }
-
-       /*
-        * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
-        */
-
-       /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
-       buf_tmp = slot->buf;
-       buf_tmp_dma = slot->buf_dma;
-
-#if _MV_DUMP
-       buf_cmd = buf_tmp;
-       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
-       buf_tmp += req_len;
-       buf_tmp_dma += req_len;
-       slot->cmd_size = req_len;
-#else
-       hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
-#endif
-
-       /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
-       buf_oaf = buf_tmp;
-       hdr->open_frame = cpu_to_le64(buf_tmp_dma);
-
-       buf_tmp += MVS_OAF_SZ;
-       buf_tmp_dma += MVS_OAF_SZ;
-
-       /* region 3: PRD table ********************************************* */
-       buf_prd = buf_tmp;
-       if (tei->n_elem)
-               hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
-       else
-               hdr->prd_tbl = 0;
-
-       i = sizeof(struct mvs_prd) * tei->n_elem;
-       buf_tmp += i;
-       buf_tmp_dma += i;
-
-       /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
-       slot->response = buf_tmp;
-       hdr->status_buf = cpu_to_le64(buf_tmp_dma);
-
-       /*
-        * Fill in TX ring and command slot header
-        */
-       slot->tx = mvi->tx_prod;
-       mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
-                                       TXQ_MODE_I | tag |
-                                       (sas_port->phy_mask << TXQ_PHY_SHIFT));
-
-       hdr->flags |= flags;
-       hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
-       hdr->tags = cpu_to_le32(tag);
-       hdr->data_len = 0;
-
-       /* generate open address frame hdr (first 12 bytes) */
-       buf_oaf[0] = (1 << 7) | (0 << 4) | 0x01; /* initiator, SMP, ftype 1h */
-       buf_oaf[1] = task->dev->linkrate & 0xf;
-       *(u16 *)(buf_oaf + 2) = 0xFFFF;         /* SAS SPEC */
-       memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
-
-       /* fill in PRD (scatter/gather) table, if any */
-       for_each_sg(task->scatter, sg, tei->n_elem, i) {
-               buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
-               buf_prd->len = cpu_to_le32(sg_dma_len(sg));
-               buf_prd++;
-       }
-
-#if _MV_DUMP
-       /* copy cmd table */
-       from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
-       memcpy(buf_cmd, from + sg_req->offset, req_len);
-       kunmap_atomic(from, KM_IRQ0);
-#endif
-       return 0;
-
-err_out_2:
-       pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1,
-                    PCI_DMA_FROMDEVICE);
-err_out:
-       pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1,
-                    PCI_DMA_TODEVICE);
-       return rc;
-}
-
-static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp, offs;
-       u8 *tfs = &port->taskfileset;
-
-       if (*tfs == MVS_ID_NOT_MAPPED)
-               return;
-
-       offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
-       if (*tfs < 16) {
-               tmp = mr32(PCS);
-               mw32(PCS, tmp & ~offs);
-       } else {
-               tmp = mr32(CTL);
-               mw32(CTL, tmp & ~offs);
-       }
-
-       tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
-       if (tmp)
-               mw32(INT_STAT_SRS, tmp);
-
-       *tfs = MVS_ID_NOT_MAPPED;
-}
-
-static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
-{
-       int i;
-       u32 tmp, offs;
-       void __iomem *regs = mvi->regs;
-
-       if (port->taskfileset != MVS_ID_NOT_MAPPED)
-               return 0;
-
-       tmp = mr32(PCS);
-
-       for (i = 0; i < mvi->chip->srs_sz; i++) {
-               if (i == 16)
-                       tmp = mr32(CTL);
-               offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
-               if (!(tmp & offs)) {
-                       port->taskfileset = i;
-
-                       if (i < 16)
-                               mw32(PCS, tmp | offs);
-                       else
-                               mw32(CTL, tmp | offs);
-                       tmp = mr32(INT_STAT_SRS) & (1U << i);
-                       if (tmp)
-                               mw32(INT_STAT_SRS, tmp);
-                       return 0;
-               }
-       }
-       return MVS_ID_NOT_MAPPED;
-}
-
-static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
-{
-       struct ata_queued_cmd *qc = task->uldd_task;
-
-       if (qc) {
-               if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
-                       qc->tf.command == ATA_CMD_FPDMA_READ) {
-                       *tag = qc->tag;
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static int mvs_task_prep_ata(struct mvs_info *mvi,
-                            struct mvs_task_exec_info *tei)
+static int mvs_task_prep_ata(struct mvs_info *mvi,
+                            struct mvs_task_exec_info *tei)
 {
        struct sas_task *task = tei->task;
        struct domain_device *dev = task->dev;
@@ -2037,7 +723,7 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
        return 0;
 }
 
-static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
+int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
 {
        struct domain_device *dev = task->dev;
        struct mvs_info *mvi = dev->port->ha->lldd_ha;
@@ -2055,823 +741,900 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
                dev = t->dev;
                tei.port = &mvi->port[dev->port->id];
 
-               if (!tei.port->port_attached) {
-                       if (sas_protocol_ata(t->task_proto)) {
-                               rc = SAS_PHY_DOWN;
-                               goto out_done;
-                       } else {
-                               struct task_status_struct *ts = &t->task_status;
-                               ts->resp = SAS_TASK_UNDELIVERED;
-                               ts->stat = SAS_PHY_DOWN;
-                               t->task_done(t);
-                               if (n > 1)
-                                       t = list_entry(t->list.next,
-                                                       struct sas_task, list);
-                               continue;
-                       }
-               }
+               if (!tei.port->port_attached) {
+                       if (sas_protocol_ata(t->task_proto)) {
+                               rc = SAS_PHY_DOWN;
+                               goto out_done;
+                       } else {
+                               struct task_status_struct *ts = &t->task_status;
+                               ts->resp = SAS_TASK_UNDELIVERED;
+                               ts->stat = SAS_PHY_DOWN;
+                               t->task_done(t);
+                               if (n > 1)
+                                       t = list_entry(t->list.next,
+                                                       struct sas_task, list);
+                               continue;
+                       }
+               }
+
+               if (!sas_protocol_ata(t->task_proto)) {
+                       if (t->num_scatter) {
+                               n_elem = pci_map_sg(mvi->pdev, t->scatter,
+                                                   t->num_scatter,
+                                                   t->data_dir);
+                               if (!n_elem) {
+                                       rc = -ENOMEM;
+                                       goto err_out;
+                               }
+                       }
+               } else {
+                       n_elem = t->num_scatter;
+               }
+
+               rc = mvs_tag_alloc(mvi, &tag);
+               if (rc)
+                       goto err_out;
+
+               slot = &mvi->slot_info[tag];
+               t->lldd_task = NULL;
+               slot->n_elem = n_elem;
+               memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
+               tei.task = t;
+               tei.hdr = &mvi->slot[tag];
+               tei.tag = tag;
+               tei.n_elem = n_elem;
+
+               switch (t->task_proto) {
+               case SAS_PROTOCOL_SMP:
+                       rc = mvs_task_prep_smp(mvi, &tei);
+                       break;
+               case SAS_PROTOCOL_SSP:
+                       rc = mvs_task_prep_ssp(mvi, &tei);
+                       break;
+               case SAS_PROTOCOL_SATA:
+               case SAS_PROTOCOL_STP:
+               case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+                       rc = mvs_task_prep_ata(mvi, &tei);
+                       break;
+               default:
+                       dev_printk(KERN_ERR, &pdev->dev,
+                               "unknown sas_task proto: 0x%x\n",
+                               t->task_proto);
+                       rc = -EINVAL;
+                       break;
+               }
+
+               if (rc)
+                       goto err_out_tag;
+
+               slot->task = t;
+               slot->port = tei.port;
+               t->lldd_task = (void *) slot;
+               list_add_tail(&slot->list, &slot->port->list);
+               /* TODO: select normal or high priority */
+
+               spin_lock(&t->task_state_lock);
+               t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+               spin_unlock(&t->task_state_lock);
+
+               mvs_hba_memory_dump(mvi, tag, t->task_proto);
+
+               ++pass;
+               mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
+               if (n > 1)
+                       t = list_entry(t->list.next, struct sas_task, list);
+       } while (--n);
+
+       rc = 0;
+       goto out_done;
+
+err_out_tag:
+       mvs_tag_free(mvi, tag);
+err_out:
+       dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc);
+       if (!sas_protocol_ata(t->task_proto))
+               if (n_elem)
+                       pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
+                                    t->data_dir);
+out_done:
+       if (pass)
+               mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
+       spin_unlock_irqrestore(&mvi->lock, flags);
+       return rc;
+}
+
+static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
+{
+       u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
+       mvs_tag_clear(mvi, slot_idx);
+}
+
+static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
+                         struct mvs_slot_info *slot, u32 slot_idx)
+{
+       if (!sas_protocol_ata(task->task_proto))
+               if (slot->n_elem)
+                       pci_unmap_sg(mvi->pdev, task->scatter,
+                                    slot->n_elem, task->data_dir);
+
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SMP:
+               pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1,
+                            PCI_DMA_FROMDEVICE);
+               pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1,
+                            PCI_DMA_TODEVICE);
+               break;
+
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
+       case SAS_PROTOCOL_SSP:
+       default:
+               /* do nothing */
+               break;
+       }
+       list_del(&slot->list);
+       task->lldd_task = NULL;
+       slot->task = NULL;
+       slot->port = NULL;
+}
+
+static void mvs_update_wideport(struct mvs_info *mvi, int i)
+{
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct mvs_port *port = phy->port;
+       int j, no;
+
+       for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy)
+               if (no & 1) {
+                       mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
+                       mvs_write_port_cfg_data(mvi, no,
+                                               port->wide_port_phymap);
+               } else {
+                       mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
+                       mvs_write_port_cfg_data(mvi, no, 0);
+               }
+}
+
+static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
+{
+       u32 tmp;
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct mvs_port *port = phy->port;;
+
+       tmp = mvs_read_phy_ctl(mvi, i);
+
+       if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
+               if (!port)
+                       phy->phy_attached = 1;
+               return tmp;
+       }
+
+       if (port) {
+               if (phy->phy_type & PORT_TYPE_SAS) {
+                       port->wide_port_phymap &= ~(1U << i);
+                       if (!port->wide_port_phymap)
+                               port->port_attached = 0;
+                       mvs_update_wideport(mvi, i);
+               } else if (phy->phy_type & PORT_TYPE_SATA)
+                       port->port_attached = 0;
+               mvs_free_reg_set(mvi, phy->port);
+               phy->port = NULL;
+               phy->phy_attached = 0;
+               phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+       }
+       return 0;
+}
+
+static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
+{
+       u32 *s = (u32 *) buf;
+
+       if (!s)
+               return NULL;
+
+       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
+       s[3] = mvs_read_port_cfg_data(mvi, i);
+
+       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
+       s[2] = mvs_read_port_cfg_data(mvi, i);
+
+       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
+       s[1] = mvs_read_port_cfg_data(mvi, i);
+
+       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
+       s[0] = mvs_read_port_cfg_data(mvi, i);
+
+       return (void *)s;
+}
+
+static u32 mvs_is_sig_fis_received(u32 irq_status)
+{
+       return irq_status & PHYEV_SIG_FIS;
+}
+
+static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
+                                       int get_st)
+{
+       struct mvs_phy *phy = &mvi->phy[i];
+       struct pci_dev *pdev = mvi->pdev;
+       u32 tmp;
+       u64 tmp64;
+
+       mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
+       phy->dev_info = mvs_read_port_cfg_data(mvi, i);
 
-               if (!sas_protocol_ata(t->task_proto)) {
-                       if (t->num_scatter) {
-                               n_elem = pci_map_sg(mvi->pdev, t->scatter,
-                                                   t->num_scatter,
-                                                   t->data_dir);
-                               if (!n_elem) {
-                                       rc = -ENOMEM;
-                                       goto err_out;
-                               }
-                       }
-               } else {
-                       n_elem = t->num_scatter;
-               }
+       mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
+       phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32;
 
-               rc = mvs_tag_alloc(mvi, &tag);
-               if (rc)
-                       goto err_out;
+       mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
+       phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
 
-               slot = &mvi->slot_info[tag];
-               t->lldd_task = NULL;
-               slot->n_elem = n_elem;
-               memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
-               tei.task = t;
-               tei.hdr = &mvi->slot[tag];
-               tei.tag = tag;
-               tei.n_elem = n_elem;
+       if (get_st) {
+               phy->irq_status = mvs_read_port_irq_stat(mvi, i);
+               phy->phy_status = mvs_is_phy_ready(mvi, i);
+       }
 
-               switch (t->task_proto) {
-               case SAS_PROTOCOL_SMP:
-                       rc = mvs_task_prep_smp(mvi, &tei);
-                       break;
-               case SAS_PROTOCOL_SSP:
-                       rc = mvs_task_prep_ssp(mvi, &tei);
-                       break;
-               case SAS_PROTOCOL_SATA:
-               case SAS_PROTOCOL_STP:
-               case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
-                       rc = mvs_task_prep_ata(mvi, &tei);
-                       break;
-               default:
-                       dev_printk(KERN_ERR, &pdev->dev,
-                               "unknown sas_task proto: 0x%x\n",
-                               t->task_proto);
-                       rc = -EINVAL;
-                       break;
-               }
+       if (phy->phy_status) {
+               u32 phy_st;
+               struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
 
-               if (rc)
-                       goto err_out_tag;
+               mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
+               phy_st = mvs_read_port_cfg_data(mvi, i);
 
-               slot->task = t;
-               slot->port = tei.port;
-               t->lldd_task = (void *) slot;
-               list_add_tail(&slot->list, &slot->port->list);
-               /* TODO: select normal or high priority */
+               sas_phy->linkrate =
+                       (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+                               PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+               phy->minimum_linkrate =
+                       (phy->phy_status &
+                               PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8;
+               phy->maximum_linkrate =
+                       (phy->phy_status &
+                               PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12;
 
-               spin_lock(&t->task_state_lock);
-               t->task_state_flags |= SAS_TASK_AT_INITIATOR;
-               spin_unlock(&t->task_state_lock);
+               if (phy->phy_type & PORT_TYPE_SAS) {
+                       /* Updated attached_sas_addr */
+                       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
+                       phy->att_dev_sas_addr =
+                               (u64) mvs_read_port_cfg_data(mvi, i) << 32;
+                       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
+                       phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
+                       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
+                       phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
+                       phy->identify.device_type =
+                           phy->att_dev_info & PORT_DEV_TYPE_MASK;
 
-               mvs_hba_memory_dump(mvi, tag, t->task_proto);
+                       if (phy->identify.device_type == SAS_END_DEV)
+                               phy->identify.target_port_protocols =
+                                                       SAS_PROTOCOL_SSP;
+                       else if (phy->identify.device_type != NO_DEVICE)
+                               phy->identify.target_port_protocols =
+                                                       SAS_PROTOCOL_SMP;
+                       if (phy_st & PHY_OOB_DTCTD)
+                               sas_phy->oob_mode = SAS_OOB_MODE;
+                       phy->frame_rcvd_size =
+                           sizeof(struct sas_identify_frame);
+               } else if (phy->phy_type & PORT_TYPE_SATA) {
+                       phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
+                       if (mvs_is_sig_fis_received(phy->irq_status)) {
+                               phy->att_dev_sas_addr = i;      /* temp */
+                               if (phy_st & PHY_OOB_DTCTD)
+                                       sas_phy->oob_mode = SATA_OOB_MODE;
+                               phy->frame_rcvd_size =
+                                   sizeof(struct dev_to_host_fis);
+                               mvs_get_d2h_reg(mvi, i,
+                                               (void *)sas_phy->frame_rcvd);
+                       } else {
+                               dev_printk(KERN_DEBUG, &pdev->dev,
+                                       "No sig fis\n");
+                               phy->phy_type &= ~(PORT_TYPE_SATA);
+                               goto out_done;
+                       }
+               }
+               tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
+               memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
 
-               ++pass;
-               mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
-               if (n > 1)
-                       t = list_entry(t->list.next, struct sas_task, list);
-       } while (--n);
+               dev_printk(KERN_DEBUG, &pdev->dev,
+                       "phy[%d] Get Attached Address 0x%llX ,"
+                       " SAS Address 0x%llX\n",
+                       i,
+                       (unsigned long long)phy->att_dev_sas_addr,
+                       (unsigned long long)phy->dev_sas_addr);
+               dev_printk(KERN_DEBUG, &pdev->dev,
+                       "Rate = %x , type = %d\n",
+                       sas_phy->linkrate, phy->phy_type);
 
-       rc = 0;
-       goto out_done;
+               /* workaround for HW phy decoding error on 1.5g disk drive */
+               mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
+               tmp = mvs_read_port_vsr_data(mvi, i);
+               if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+                    PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
+                       SAS_LINK_RATE_1_5_GBPS)
+                       tmp &= ~PHY_MODE6_LATECLK;
+               else
+                       tmp |= PHY_MODE6_LATECLK;
+               mvs_write_port_vsr_data(mvi, i, tmp);
 
-err_out_tag:
-       mvs_tag_free(mvi, tag);
-err_out:
-       dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc);
-       if (!sas_protocol_ata(t->task_proto))
-               if (n_elem)
-                       pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
-                                    t->data_dir);
+       }
 out_done:
-       if (pass)
-               mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
-       spin_unlock_irqrestore(&mvi->lock, flags);
-       return rc;
+       if (get_st)
+               mvs_write_port_irq_stat(mvi, i, phy->irq_status);
 }
 
-static int mvs_task_abort(struct sas_task *task)
+void mvs_port_formed(struct asd_sas_phy *sas_phy)
 {
-       int rc;
+       struct sas_ha_struct *sas_ha = sas_phy->ha;
+       struct mvs_info *mvi = sas_ha->lldd_ha;
+       struct asd_sas_port *sas_port = sas_phy->port;
+       struct mvs_phy *phy = sas_phy->lldd_phy;
+       struct mvs_port *port = &mvi->port[sas_port->id];
        unsigned long flags;
-       struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
-       struct pci_dev *pdev = mvi->pdev;
-       int tag;
 
-       spin_lock_irqsave(&task->task_state_lock, flags);
-       if (task->task_state_flags & SAS_TASK_STATE_DONE) {
-               rc = TMF_RESP_FUNC_COMPLETE;
-               spin_unlock_irqrestore(&task->task_state_lock, flags);
-               goto out_done;
+       spin_lock_irqsave(&mvi->lock, flags);
+       port->port_attached = 1;
+       phy->port = port;
+       port->taskfileset = MVS_ID_NOT_MAPPED;
+       if (phy->phy_type & PORT_TYPE_SAS) {
+               port->wide_port_phymap = sas_port->phy_mask;
+               mvs_update_wideport(mvi, sas_phy->id);
        }
-       spin_unlock_irqrestore(&task->task_state_lock, flags);
+       spin_unlock_irqrestore(&mvi->lock, flags);
+}
+
+int mvs_I_T_nexus_reset(struct domain_device *dev)
+{
+       return TMF_RESP_FUNC_FAILED;
+}
+
+static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
+                       u32 slot_idx, int err)
+{
+       struct mvs_port *port = mvi->slot_info[slot_idx].port;
+       struct task_status_struct *tstat = &task->task_status;
+       struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf;
+       int stat = SAM_GOOD;
+
+       resp->frame_len = sizeof(struct dev_to_host_fis);
+       memcpy(&resp->ending_fis[0],
+              SATA_RECEIVED_D2H_FIS(port->taskfileset),
+              sizeof(struct dev_to_host_fis));
+       tstat->buf_valid_size = sizeof(*resp);
+       if (unlikely(err))
+               stat = SAS_PROTO_RESPONSE;
+       return stat;
+}
+
+static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
+                        u32 slot_idx)
+{
+       struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
+       u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
+       u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4));
+       int stat = SAM_CHECK_COND;
 
+       if (err_dw1 & SLOT_BSY_ERR) {
+               stat = SAS_QUEUE_FULL;
+               mvs_slot_reset(mvi, task, slot_idx);
+       }
        switch (task->task_proto) {
-       case SAS_PROTOCOL_SMP:
-               dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n");
-               break;
        case SAS_PROTOCOL_SSP:
-               dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n");
+               break;
+       case SAS_PROTOCOL_SMP:
                break;
        case SAS_PROTOCOL_SATA:
        case SAS_PROTOCOL_STP:
-       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{
-               dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n");
-#if _MV_DUMP
-               dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n");
-               mvs_hexdump(sizeof(struct host_to_dev_fis),
-                               (void *)&task->ata_task.fis, 0);
-               dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
-               mvs_hexdump(16, task->ata_task.atapi_packet, 0);
-#endif
-               spin_lock_irqsave(&task->task_state_lock, flags);
-               if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) {
-                       /* TODO */
-                       ;
-               }
-               spin_unlock_irqrestore(&task->task_state_lock, flags);
+       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+               if (err_dw0 & TFILE_ERR)
+                       stat = mvs_sata_done(mvi, task, slot_idx, 1);
                break;
-       }
        default:
                break;
        }
 
-       if (mvs_find_tag(mvi, task, &tag)) {
-               spin_lock_irqsave(&mvi->lock, flags);
-               mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag);
-               spin_unlock_irqrestore(&mvi->lock, flags);
-       }
-       if (!mvs_task_exec(task, 1, GFP_ATOMIC))
-               rc = TMF_RESP_FUNC_COMPLETE;
-       else
-               rc = TMF_RESP_FUNC_FAILED;
-out_done:
-       return rc;
+       mvs_hexdump(16, (u8 *) slot->response, 0);
+       return stat;
 }
 
-static void mvs_free(struct mvs_info *mvi)
+static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
 {
-       int i;
+       u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
+       struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
+       struct sas_task *task = slot->task;
+       struct task_status_struct *tstat;
+       struct mvs_port *port;
+       bool aborted;
+       void *to;
 
-       if (!mvi)
-               return;
+       if (unlikely(!task || !task->lldd_task))
+               return -1;
 
-       for (i = 0; i < MVS_SLOTS; i++) {
-               struct mvs_slot_info *slot = &mvi->slot_info[i];
+       mvs_hba_cq_dump(mvi);
 
-               if (slot->buf)
-                       dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ,
-                                         slot->buf, slot->buf_dma);
+       spin_lock(&task->task_state_lock);
+       aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
+       if (!aborted) {
+               task->task_state_flags &=
+                   ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+               task->task_state_flags |= SAS_TASK_STATE_DONE;
        }
+       spin_unlock(&task->task_state_lock);
 
-       if (mvi->tx)
-               dma_free_coherent(&mvi->pdev->dev,
-                                 sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
-                                 mvi->tx, mvi->tx_dma);
-       if (mvi->rx_fis)
-               dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
-                                 mvi->rx_fis, mvi->rx_fis_dma);
-       if (mvi->rx)
-               dma_free_coherent(&mvi->pdev->dev,
-                                 sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
-                                 mvi->rx, mvi->rx_dma);
-       if (mvi->slot)
-               dma_free_coherent(&mvi->pdev->dev,
-                                 sizeof(*mvi->slot) * MVS_SLOTS,
-                                 mvi->slot, mvi->slot_dma);
-#ifdef MVS_ENABLE_PERI
-       if (mvi->peri_regs)
-               iounmap(mvi->peri_regs);
-#endif
-       if (mvi->regs)
-               iounmap(mvi->regs);
-       if (mvi->shost)
-               scsi_host_put(mvi->shost);
-       kfree(mvi->sas.sas_port);
-       kfree(mvi->sas.sas_phy);
-       kfree(mvi);
-}
+       if (aborted) {
+               mvs_slot_task_free(mvi, task, slot, slot_idx);
+               mvs_slot_free(mvi, rx_desc);
+               return -1;
+       }
 
-/* FIXME: locking? */
-static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
-                          void *funcdata)
-{
-       struct mvs_info *mvi = sas_phy->ha->lldd_ha;
-       int rc = 0, phy_id = sas_phy->id;
-       u32 tmp;
+       port = slot->port;
+       tstat = &task->task_status;
+       memset(tstat, 0, sizeof(*tstat));
+       tstat->resp = SAS_TASK_COMPLETE;
 
-       tmp = mvs_read_phy_ctl(mvi, phy_id);
+       if (unlikely(!port->port_attached || flags)) {
+               mvs_slot_err(mvi, task, slot_idx);
+               if (!sas_protocol_ata(task->task_proto))
+                       tstat->stat = SAS_PHY_DOWN;
+               goto out;
+       }
 
-       switch (func) {
-       case PHY_FUNC_SET_LINK_RATE:{
-                       struct sas_phy_linkrates *rates = funcdata;
-                       u32 lrmin = 0, lrmax = 0;
+       /* error info record present */
+       if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
+               tstat->stat = mvs_slot_err(mvi, task, slot_idx);
+               goto out;
+       }
 
-                       lrmin = (rates->minimum_linkrate << 8);
-                       lrmax = (rates->maximum_linkrate << 12);
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SSP:
+               /* hw says status == 0, datapres == 0 */
+               if (rx_desc & RXQ_GOOD) {
+                       tstat->stat = SAM_GOOD;
+                       tstat->resp = SAS_TASK_COMPLETE;
+               }
+               /* response frame present */
+               else if (rx_desc & RXQ_RSP) {
+                       struct ssp_response_iu *iu =
+                           slot->response + sizeof(struct mvs_err_info);
+                       sas_ssp_task_response(&mvi->pdev->dev, task, iu);
+               }
 
-                       if (lrmin) {
-                               tmp &= ~(0xf << 8);
-                               tmp |= lrmin;
-                       }
-                       if (lrmax) {
-                               tmp &= ~(0xf << 12);
-                               tmp |= lrmax;
-                       }
-                       mvs_write_phy_ctl(mvi, phy_id, tmp);
+               /* should never happen? */
+               else
+                       tstat->stat = SAM_CHECK_COND;
+               break;
+
+       case SAS_PROTOCOL_SMP: {
+                       struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+                       tstat->stat = SAM_GOOD;
+                       to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
+                       memcpy(to + sg_resp->offset,
+                               slot->response + sizeof(struct mvs_err_info),
+                               sg_dma_len(sg_resp));
+                       kunmap_atomic(to, KM_IRQ0);
                        break;
                }
 
-       case PHY_FUNC_HARD_RESET:
-               if (tmp & PHY_RST_HARD)
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
+       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
+                       tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0);
                        break;
-               mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD);
-               break;
-
-       case PHY_FUNC_LINK_RESET:
-               mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST);
-               break;
+               }
 
-       case PHY_FUNC_DISABLE:
-       case PHY_FUNC_RELEASE_SPINUP_HOLD:
        default:
-               rc = -EOPNOTSUPP;
+               tstat->stat = SAM_CHECK_COND;
+               break;
        }
 
-       return rc;
-}
-
-static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
-{
-       struct mvs_phy *phy = &mvi->phy[phy_id];
-       struct asd_sas_phy *sas_phy = &phy->sas_phy;
+out:
+       mvs_slot_task_free(mvi, task, slot, slot_idx);
+       if (unlikely(tstat->stat != SAS_QUEUE_FULL))
+               mvs_slot_free(mvi, rx_desc);
 
-       sas_phy->enabled = (phy_id < mvi->chip->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_id;
-       sas_phy->sas_addr = &mvi->sas_addr[0];
-       sas_phy->frame_rcvd = &phy->frame_rcvd[0];
-       sas_phy->ha = &mvi->sas;
-       sas_phy->lldd_phy = phy;
+       spin_unlock(&mvi->lock);
+       task->task_done(task);
+       spin_lock(&mvi->lock);
+       return tstat->stat;
 }
 
-static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
-                                           const struct pci_device_id *ent)
+static void mvs_release_task(struct mvs_info *mvi, int phy_no)
 {
-       struct mvs_info *mvi;
-       unsigned long res_start, res_len, res_flag;
-       struct asd_sas_phy **arr_phy;
-       struct asd_sas_port **arr_port;
-       const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
-       int i;
-
-       /*
-        * alloc and init our per-HBA mvs_info struct
-        */
-
-       mvi = kzalloc(sizeof(*mvi), GFP_KERNEL);
-       if (!mvi)
-               return NULL;
-
-       spin_lock_init(&mvi->lock);
-#ifdef MVS_USE_TASKLET
-       tasklet_init(&mvi->tasklet, mvs_tasklet, (unsigned long)mvi);
-#endif
-       mvi->pdev = pdev;
-       mvi->chip = chip;
-
-       if (pdev->device == 0x6440 && pdev->revision == 0)
-               mvi->flags |= MVF_PHY_PWR_FIX;
-
-       /*
-        * alloc and init SCSI, SAS glue
-        */
-
-       mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *));
-       if (!mvi->shost)
-               goto err_out;
+       struct list_head *pos, *n;
+       struct mvs_slot_info *slot;
+       struct mvs_phy *phy = &mvi->phy[phy_no];
+       struct mvs_port *port = phy->port;
+       u32 rx_desc;
 
-       arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
-       arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
-       if (!arr_phy || !arr_port)
-               goto err_out;
+       if (!port)
+               return;
 
-       for (i = 0; i < MVS_MAX_PHYS; i++) {
-               mvs_phy_init(mvi, i);
-               arr_phy[i] = &mvi->phy[i].sas_phy;
-               arr_port[i] = &mvi->port[i].sas_port;
-               mvi->port[i].taskfileset = MVS_ID_NOT_MAPPED;
-               mvi->port[i].wide_port_phymap = 0;
-               mvi->port[i].port_attached = 0;
-               INIT_LIST_HEAD(&mvi->port[i].list);
+       list_for_each_safe(pos, n, &port->list) {
+               slot = container_of(pos, struct mvs_slot_info, list);
+               rx_desc = (u32) (slot - mvi->slot_info);
+               mvs_slot_complete(mvi, rx_desc, 1);
        }
+}
 
-       SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
-       mvi->shost->transportt = mvs_stt;
-       mvi->shost->max_id = 21;
-       mvi->shost->max_lun = ~0;
-       mvi->shost->max_channel = 0;
-       mvi->shost->max_cmd_len = 16;
-
-       mvi->sas.sas_ha_name = DRV_NAME;
-       mvi->sas.dev = &pdev->dev;
-       mvi->sas.lldd_module = THIS_MODULE;
-       mvi->sas.sas_addr = &mvi->sas_addr[0];
-       mvi->sas.sas_phy = arr_phy;
-       mvi->sas.sas_port = arr_port;
-       mvi->sas.num_phys = chip->n_phy;
-       mvi->sas.lldd_max_execute_num = 1;
-       mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
-       mvi->shost->can_queue = MVS_CAN_QUEUE;
-       mvi->shost->cmd_per_lun = MVS_SLOTS / mvi->sas.num_phys;
-       mvi->sas.lldd_ha = mvi;
-       mvi->sas.core.shost = mvi->shost;
-
-       mvs_tag_init(mvi);
-
-       /*
-        * ioremap main and peripheral registers
-        */
-
-#ifdef MVS_ENABLE_PERI
-       res_start = pci_resource_start(pdev, 2);
-       res_len = pci_resource_len(pdev, 2);
-       if (!res_start || !res_len)
-               goto err_out;
-
-       mvi->peri_regs = ioremap_nocache(res_start, res_len);
-       if (!mvi->peri_regs)
-               goto err_out;
-#endif
-
-       res_start = pci_resource_start(pdev, 4);
-       res_len = pci_resource_len(pdev, 4);
-       if (!res_start || !res_len)
-               goto err_out;
-
-       res_flag = pci_resource_flags(pdev, 4);
-       if (res_flag & IORESOURCE_CACHEABLE)
-               mvi->regs = ioremap(res_start, res_len);
-       else
-               mvi->regs = ioremap_nocache(res_start, res_len);
-
-       if (!mvi->regs)
-               goto err_out;
+static void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
+{
+       struct pci_dev *pdev = mvi->pdev;
+       struct sas_ha_struct *sas_ha = &mvi->sas;
+       struct mvs_phy *phy = &mvi->phy[phy_no];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
+       phy->irq_status = mvs_read_port_irq_stat(mvi, phy_no);
        /*
-        * alloc and init our DMA areas
-        */
-
-       mvi->tx = dma_alloc_coherent(&pdev->dev,
-                                    sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
-                                    &mvi->tx_dma, GFP_KERNEL);
-       if (!mvi->tx)
-               goto err_out;
-       memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
-
-       mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
-                                        &mvi->rx_fis_dma, GFP_KERNEL);
-       if (!mvi->rx_fis)
-               goto err_out;
-       memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
-
-       mvi->rx = dma_alloc_coherent(&pdev->dev,
-                                    sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1),
-                                    &mvi->rx_dma, GFP_KERNEL);
-       if (!mvi->rx)
-               goto err_out;
-       memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1));
-
-       mvi->rx[0] = cpu_to_le32(0xfff);
-       mvi->rx_cons = 0xfff;
-
-       mvi->slot = dma_alloc_coherent(&pdev->dev,
-                                      sizeof(*mvi->slot) * MVS_SLOTS,
-                                      &mvi->slot_dma, GFP_KERNEL);
-       if (!mvi->slot)
-               goto err_out;
-       memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS);
+       * events is port event now ,
+       * we need check the interrupt status which belongs to per port.
+       */
+       dev_printk(KERN_DEBUG, &pdev->dev,
+               "Port %d Event = %X\n",
+               phy_no, phy->irq_status);
 
-       for (i = 0; i < MVS_SLOTS; i++) {
-               struct mvs_slot_info *slot = &mvi->slot_info[i];
+       if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) {
+               mvs_release_task(mvi, phy_no);
+               if (!mvs_is_phy_ready(mvi, phy_no)) {
+                       sas_phy_disconnected(sas_phy);
+                       sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
+                       dev_printk(KERN_INFO, &pdev->dev,
+                               "Port %d Unplug Notice\n", phy_no);
 
-               slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
-                                              &slot->buf_dma, GFP_KERNEL);
-               if (!slot->buf)
-                       goto err_out;
-               memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
+               } else
+                       mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL);
        }
+       if (!(phy->irq_status & PHYEV_DEC_ERR)) {
+               if (phy->irq_status & PHYEV_COMWAKE) {
+                       u32 tmp = mvs_read_port_irq_mask(mvi, phy_no);
+                       mvs_write_port_irq_mask(mvi, phy_no,
+                                               tmp | PHYEV_SIG_FIS);
+               }
+               if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
+                       phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
+                       if (phy->phy_status) {
+                               mvs_detect_porttype(mvi, phy_no);
 
-       /* finally, read NVRAM to get our SAS address */
-       if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
-               goto err_out;
-       return mvi;
-
-err_out:
-       mvs_free(mvi);
-       return NULL;
-}
-
-static u32 mvs_cr32(void __iomem *regs, u32 addr)
-{
-       mw32(CMD_ADDR, addr);
-       return mr32(CMD_DATA);
-}
-
-static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
-{
-       mw32(CMD_ADDR, addr);
-       mw32(CMD_DATA, val);
-}
+                               if (phy->phy_type & PORT_TYPE_SATA) {
+                                       u32 tmp = mvs_read_port_irq_mask(mvi,
+                                                               phy_no);
+                                       tmp &= ~PHYEV_SIG_FIS;
+                                       mvs_write_port_irq_mask(mvi,
+                                                               phy_no, tmp);
+                               }
 
-static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
-{
-       void __iomem *regs = mvi->regs;
-       return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4):
-               mr32(P4_SER_CTLSTAT + (port - 4) * 4);
+                               mvs_update_phyinfo(mvi, phy_no, 0);
+                               sas_ha->notify_phy_event(sas_phy,
+                                                       PHYE_OOB_DONE);
+                               mvs_bytes_dmaed(mvi, phy_no);
+                       } else {
+                               dev_printk(KERN_DEBUG, &pdev->dev,
+                                       "plugin interrupt but phy is gone\n");
+                               mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET,
+                                                       NULL);
+                       }
+               } else if (phy->irq_status & PHYEV_BROAD_CH) {
+                       mvs_release_task(mvi, phy_no);
+                       sas_ha->notify_port_event(sas_phy,
+                                               PORTE_BROADCAST_RCVD);
+               }
+       }
+       mvs_write_port_irq_stat(mvi, phy_no, phy->irq_status);
 }
 
-static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
 {
        void __iomem *regs = mvi->regs;
-       if (port < 4)
-               mw32(P0_SER_CTLSTAT + port * 4, val);
-       else
-               mw32(P4_SER_CTLSTAT + (port - 4) * 4, val);
-}
-
-static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port)
-{
-       void __iomem *regs = mvi->regs + off;
-       void __iomem *regs2 = mvi->regs + off2;
-       return (port < 4)?readl(regs + port * 8):
-               readl(regs2 + (port - 4) * 8);
-}
+       u32 rx_prod_idx, rx_desc;
+       bool attn = false;
+       struct pci_dev *pdev = mvi->pdev;
 
-static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
-                               u32 port, u32 val)
-{
-       void __iomem *regs = mvi->regs + off;
-       void __iomem *regs2 = mvi->regs + off2;
-       if (port < 4)
-               writel(val, regs + port * 8);
-       else
-               writel(val, regs2 + (port - 4) * 8);
-}
+       /* the first dword in the RX ring is special: it contains
+        * a mirror of the hardware's RX producer index, so that
+        * we don't have to stall the CPU reading that register.
+        * The actual RX ring is offset by one dword, due to this.
+        */
+       rx_prod_idx = mvi->rx_cons;
+       mvi->rx_cons = le32_to_cpu(mvi->rx[0]);
+       if (mvi->rx_cons == 0xfff)      /* h/w hasn't touched RX ring yet */
+               return 0;
 
-static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
-{
-       return mvs_read_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port);
-}
+       /* The CMPL_Q may come late, read from register and try again
+       * note: if coalescing is enabled,
+       * it will need to read from register every time for sure
+       */
+       if (mvi->rx_cons == rx_prod_idx)
+               mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
 
-static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val)
-{
-       mvs_write_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port, val);
-}
+       if (mvi->rx_cons == rx_prod_idx)
+               return 0;
 
-static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr)
-{
-       mvs_write_port(mvi, MVS_P0_CFG_ADDR, MVS_P4_CFG_ADDR, port, addr);
-}
+       while (mvi->rx_cons != rx_prod_idx) {
 
-static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
-{
-       return mvs_read_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port);
-}
+               /* increment our internal RX consumer pointer */
+               rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1);
 
-static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val)
-{
-       mvs_write_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port, val);
-}
+               rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]);
 
-static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr)
-{
-       mvs_write_port(mvi, MVS_P0_VSR_ADDR, MVS_P4_VSR_ADDR, port, addr);
-}
+               if (likely(rx_desc & RXQ_DONE))
+                       mvs_slot_complete(mvi, rx_desc, 0);
+               if (rx_desc & RXQ_ATTN) {
+                       attn = true;
+                       dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n",
+                               rx_desc);
+               } else if (rx_desc & RXQ_ERR) {
+                       if (!(rx_desc & RXQ_DONE))
+                               mvs_slot_complete(mvi, rx_desc, 0);
+                       dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n",
+                               rx_desc);
+               } else if (rx_desc & RXQ_SLOT_RESET) {
+                       dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n",
+                               rx_desc);
+                       mvs_slot_free(mvi, rx_desc);
+               }
+       }
 
-static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
-{
-       return mvs_read_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port);
-}
+       if (attn && self_clear)
+               mvs_int_full(mvi);
 
-static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
-{
-       mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val);
+       return 0;
 }
 
-static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
+#ifndef MVS_DISABLE_NVRAM
+static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data)
 {
-       return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port);
-}
+       int timeout = 1000;
 
-static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
-{
-       mvs_write_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port, val);
-}
+       if (addr & ~SPI_ADDR_MASK)
+               return -EINVAL;
 
-static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp;
+       writel(addr, regs + SPI_CMD);
+       writel(TWSI_RD, regs + SPI_CTL);
 
-       /* workaround for SATA R-ERR, to ignore phy glitch */
-       tmp = mvs_cr32(regs, CMD_PHY_TIMER);
-       tmp &= ~(1 << 9);
-       tmp |= (1 << 10);
-       mvs_cw32(regs, CMD_PHY_TIMER, tmp);
+       while (timeout-- > 0) {
+               if (readl(regs + SPI_CTL) & TWSI_RDY) {
+                       *data = readl(regs + SPI_DATA);
+                       return 0;
+               }
 
-       /* enable retry 127 times */
-       mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
+               udelay(10);
+       }
 
-       /* extend open frame timeout to max */
-       tmp = mvs_cr32(regs, CMD_SAS_CTL0);
-       tmp &= ~0xffff;
-       tmp |= 0x3fff;
-       mvs_cw32(regs, CMD_SAS_CTL0, tmp);
+       return -EBUSY;
+}
 
-       /* workaround for WDTIMEOUT , set to 550 ms */
-       mvs_cw32(regs, CMD_WD_TIMER, 0x86470);
+static int mvs_eep_read_buf(void __iomem *regs, u32 addr,
+                           void *buf, u32 buflen)
+{
+       u32 addr_end, tmp_addr, i, j;
+       u32 tmp = 0;
+       int rc;
+       u8 *tmp8, *buf8 = buf;
 
-       /* not to halt for different port op during wideport link change */
-       mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
+       addr_end = addr + buflen;
+       tmp_addr = ALIGN(addr, 4);
+       if (addr > 0xff)
+               return -EINVAL;
 
-       /* workaround for Seagate disk not-found OOB sequence, recv
-        * COMINIT before sending out COMWAKE */
-       tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
-       tmp &= 0x0000ffff;
-       tmp |= 0x00fa0000;
-       mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
+       j = addr & 0x3;
+       if (j) {
+               rc = mvs_eep_read(regs, tmp_addr, &tmp);
+               if (rc)
+                       return rc;
 
-       tmp = mvs_cr32(regs, CMD_PHY_TIMER);
-       tmp &= 0x1fffffff;
-       tmp |= (2U << 29);      /* 8 ms retry */
-       mvs_cw32(regs, CMD_PHY_TIMER, tmp);
+               tmp8 = (u8 *)&tmp;
+               for (i = j; i < 4; i++)
+                       *buf8++ = tmp8[i];
 
-       /* TEST - for phy decoding error, adjust voltage levels */
-       mw32(P0_VSR_ADDR + 0, 0x8);
-       mw32(P0_VSR_DATA + 0, 0x2F0);
+               tmp_addr += 4;
+       }
 
-       mw32(P0_VSR_ADDR + 8, 0x8);
-       mw32(P0_VSR_DATA + 8, 0x2F0);
+       for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) {
+               rc = mvs_eep_read(regs, tmp_addr, &tmp);
+               if (rc)
+                       return rc;
 
-       mw32(P0_VSR_ADDR + 16, 0x8);
-       mw32(P0_VSR_DATA + 16, 0x2F0);
+               memcpy(buf8, &tmp, 4);
+               buf8 += 4;
+       }
 
-       mw32(P0_VSR_ADDR + 24, 0x8);
-       mw32(P0_VSR_DATA + 24, 0x2F0);
+       if (tmp_addr < addr_end) {
+               rc = mvs_eep_read(regs, tmp_addr, &tmp);
+               if (rc)
+                       return rc;
 
-}
+               tmp8 = (u8 *)&tmp;
+               j = addr_end - tmp_addr;
+               for (i = 0; i < j; i++)
+                       *buf8++ = tmp8[i];
 
-static void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
-{
-       void __iomem *regs = mvi->regs;
-       u32 tmp;
+               tmp_addr += 4;
+       }
 
-       tmp = mr32(PCS);
-       if (mvi->chip->n_phy <= 4)
-               tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
-       else
-               tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
-       mw32(PCS, tmp);
+       return 0;
 }
+#endif
 
-static void mvs_detect_porttype(struct mvs_info *mvi, int i)
+int mvs_nvram_read(struct mvs_info *mvi, u32 addr, void *buf, u32 buflen)
 {
+#ifndef MVS_DISABLE_NVRAM
        void __iomem *regs = mvi->regs;
-       u32 reg;
-       struct mvs_phy *phy = &mvi->phy[i];
-
-       /* TODO check & save device type */
-       reg = mr32(GBL_PORT_TYPE);
-
-       if (reg & MODE_SAS_SATA & (1 << i))
-               phy->phy_type |= PORT_TYPE_SAS;
-       else
-               phy->phy_type |= PORT_TYPE_SATA;
-}
-
-static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
-{
-       u32 *s = (u32 *) buf;
-
-       if (!s)
-               return NULL;
+       int rc, i;
+       u32 sum;
+       u8 hdr[2], *tmp;
+       const char *msg;
 
-       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
-       s[3] = mvs_read_port_cfg_data(mvi, i);
+       rc = mvs_eep_read_buf(regs, addr, &hdr, 2);
+       if (rc) {
+               msg = "nvram hdr read failed";
+               goto err_out;
+       }
+       rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen);
+       if (rc) {
+               msg = "nvram read failed";
+               goto err_out;
+       }
 
-       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
-       s[2] = mvs_read_port_cfg_data(mvi, i);
+       if (hdr[0] != 0x5A) {
+               /* entry id */
+               msg = "invalid nvram entry id";
+               rc = -ENOENT;
+               goto err_out;
+       }
 
-       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
-       s[1] = mvs_read_port_cfg_data(mvi, i);
+       tmp = buf;
+       sum = ((u32)hdr[0]) + ((u32)hdr[1]);
+       for (i = 0; i < buflen; i++)
+               sum += ((u32)tmp[i]);
 
-       mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
-       s[0] = mvs_read_port_cfg_data(mvi, i);
+       if (sum) {
+               msg = "nvram checksum failure";
+               rc = -EILSEQ;
+               goto err_out;
+       }
 
-       return (void *)s;
-}
+       return 0;
 
-static u32 mvs_is_sig_fis_received(u32 irq_status)
-{
-       return irq_status & PHYEV_SIG_FIS;
+err_out:
+       dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
+       return rc;
+#else
+       /* FIXME , For SAS target mode */
+       memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
+       return 0;
+#endif
 }
 
-static void mvs_update_wideport(struct mvs_info *mvi, int i)
+static void mvs_int_sata(struct mvs_info *mvi)
 {
-       struct mvs_phy *phy = &mvi->phy[i];
-       struct mvs_port *port = phy->port;
-       int j, no;
-
-       for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy)
-               if (no & 1) {
-                       mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
-                       mvs_write_port_cfg_data(mvi, no,
-                                               port->wide_port_phymap);
-               } else {
-                       mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
-                       mvs_write_port_cfg_data(mvi, no, 0);
-               }
+       u32 tmp;
+       void __iomem *regs = mvi->regs;
+       tmp = mr32(INT_STAT_SRS);
+       mw32(INT_STAT_SRS, tmp & 0xFFFF);
 }
 
-static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
+static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task,
+                               u32 slot_idx)
 {
-       u32 tmp;
-       struct mvs_phy *phy = &mvi->phy[i];
-       struct mvs_port *port = phy->port;;
-
-       tmp = mvs_read_phy_ctl(mvi, i);
-
-       if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
-               if (!port)
-                       phy->phy_attached = 1;
-               return tmp;
-       }
+       void __iomem *regs = mvi->regs;
+       struct domain_device *dev = task->dev;
+       struct asd_sas_port *sas_port = dev->port;
+       struct mvs_port *port = mvi->slot_info[slot_idx].port;
+       u32 reg_set, phy_mask;
 
-       if (port) {
-               if (phy->phy_type & PORT_TYPE_SAS) {
-                       port->wide_port_phymap &= ~(1U << i);
-                       if (!port->wide_port_phymap)
-                               port->port_attached = 0;
-                       mvs_update_wideport(mvi, i);
-               } else if (phy->phy_type & PORT_TYPE_SATA)
-                       port->port_attached = 0;
-               mvs_free_reg_set(mvi, phy->port);
-               phy->port = NULL;
-               phy->phy_attached = 0;
-               phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+       if (!sas_protocol_ata(task->task_proto)) {
+               reg_set = 0;
+               phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap :
+                               sas_port->phy_mask;
+       } else {
+               reg_set = port->taskfileset;
+               phy_mask = sas_port->phy_mask;
        }
-       return 0;
+       mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx |
+                                       (TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) |
+                                       (phy_mask << TXQ_PHY_SHIFT) |
+                                       (reg_set << TXQ_SRS_SHIFT));
+
+       mw32(TX_PROD_IDX, mvi->tx_prod);
+       mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
 }
 
-static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
-                                       int get_st)
+void mvs_int_full(struct mvs_info *mvi)
 {
-       struct mvs_phy *phy = &mvi->phy[i];
-       struct pci_dev *pdev = mvi->pdev;
-       u32 tmp;
-       u64 tmp64;
-
-       mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
-       phy->dev_info = mvs_read_port_cfg_data(mvi, i);
+       void __iomem *regs = mvi->regs;
+       u32 tmp, stat;
+       int i;
 
-       mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
-       phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32;
+       stat = mr32(INT_STAT);
 
-       mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
-       phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
+       mvs_int_rx(mvi, false);
 
-       if (get_st) {
-               phy->irq_status = mvs_read_port_irq_stat(mvi, i);
-               phy->phy_status = mvs_is_phy_ready(mvi, i);
+       for (i = 0; i < MVS_MAX_PORTS; i++) {
+               tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
+               if (tmp)
+                       mvs_int_port(mvi, i, tmp);
        }
 
-       if (phy->phy_status) {
-               u32 phy_st;
-               struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
-
-               mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
-               phy_st = mvs_read_port_cfg_data(mvi, i);
-
-               sas_phy->linkrate =
-                       (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
-                               PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
-               phy->minimum_linkrate =
-                       (phy->phy_status &
-                               PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8;
-               phy->maximum_linkrate =
-                       (phy->phy_status &
-                               PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12;
+       if (stat & CINT_SRS)
+               mvs_int_sata(mvi);
 
-               if (phy->phy_type & PORT_TYPE_SAS) {
-                       /* Updated attached_sas_addr */
-                       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
-                       phy->att_dev_sas_addr =
-                               (u64) mvs_read_port_cfg_data(mvi, i) << 32;
-                       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
-                       phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
-                       mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
-                       phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
-                       phy->identify.device_type =
-                           phy->att_dev_info & PORT_DEV_TYPE_MASK;
+       mw32(INT_STAT, stat);
+}
 
-                       if (phy->identify.device_type == SAS_END_DEV)
-                               phy->identify.target_port_protocols =
-                                                       SAS_PROTOCOL_SSP;
-                       else if (phy->identify.device_type != NO_DEVICE)
-                               phy->identify.target_port_protocols =
-                                                       SAS_PROTOCOL_SMP;
-                       if (phy_st & PHY_OOB_DTCTD)
-                               sas_phy->oob_mode = SAS_OOB_MODE;
-                       phy->frame_rcvd_size =
-                           sizeof(struct sas_identify_frame);
-               } else if (phy->phy_type & PORT_TYPE_SATA) {
-                       phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
-                       if (mvs_is_sig_fis_received(phy->irq_status)) {
-                               phy->att_dev_sas_addr = i;      /* temp */
-                               if (phy_st & PHY_OOB_DTCTD)
-                                       sas_phy->oob_mode = SATA_OOB_MODE;
-                               phy->frame_rcvd_size =
-                                   sizeof(struct dev_to_host_fis);
-                               mvs_get_d2h_reg(mvi, i,
-                                               (void *)sas_phy->frame_rcvd);
-                       } else {
-                               dev_printk(KERN_DEBUG, &pdev->dev,
-                                       "No sig fis\n");
-                               phy->phy_type &= ~(PORT_TYPE_SATA);
-                               goto out_done;
-                       }
-               }
-               tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
-               memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
+#ifndef MVS_DISABLE_MSI
+static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
+{
+       struct mvs_info *mvi = opaque;
 
-               dev_printk(KERN_DEBUG, &pdev->dev,
-                       "phy[%d] Get Attached Address 0x%llX ,"
-                       " SAS Address 0x%llX\n",
-                       i,
-                       (unsigned long long)phy->att_dev_sas_addr,
-                       (unsigned long long)phy->dev_sas_addr);
-               dev_printk(KERN_DEBUG, &pdev->dev,
-                       "Rate = %x , type = %d\n",
-                       sas_phy->linkrate, phy->phy_type);
+#ifndef MVS_USE_TASKLET
+       spin_lock(&mvi->lock);
 
-               /* workaround for HW phy decoding error on 1.5g disk drive */
-               mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
-               tmp = mvs_read_port_vsr_data(mvi, i);
-               if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
-                    PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
-                       SAS_LINK_RATE_1_5_GBPS)
-                       tmp &= ~PHY_MODE6_LATECLK;
-               else
-                       tmp |= PHY_MODE6_LATECLK;
-               mvs_write_port_vsr_data(mvi, i, tmp);
+       mvs_int_rx(mvi, true);
 
-       }
-out_done:
-       if (get_st)
-               mvs_write_port_irq_stat(mvi, i, phy->irq_status);
+       spin_unlock(&mvi->lock);
+#else
+       tasklet_schedule(&mvi->tasklet);
+#endif
+       return IRQ_HANDLED;
 }
+#endif
 
-static void mvs_port_formed(struct asd_sas_phy *sas_phy)
+int mvs_task_abort(struct sas_task *task)
 {
-       struct sas_ha_struct *sas_ha = sas_phy->ha;
-       struct mvs_info *mvi = sas_ha->lldd_ha;
-       struct asd_sas_port *sas_port = sas_phy->port;
-       struct mvs_phy *phy = sas_phy->lldd_phy;
-       struct mvs_port *port = &mvi->port[sas_port->id];
+       int rc;
        unsigned long flags;
+       struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
+       struct pci_dev *pdev = mvi->pdev;
+       int tag;
 
-       spin_lock_irqsave(&mvi->lock, flags);
-       port->port_attached = 1;
-       phy->port = port;
-       port->taskfileset = MVS_ID_NOT_MAPPED;
-       if (phy->phy_type & PORT_TYPE_SAS) {
-               port->wide_port_phymap = sas_port->phy_mask;
-               mvs_update_wideport(mvi, sas_phy->id);
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+               rc = TMF_RESP_FUNC_COMPLETE;
+               spin_unlock_irqrestore(&task->task_state_lock, flags);
+               goto out_done;
        }
-       spin_unlock_irqrestore(&mvi->lock, flags);
-}
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-static int mvs_I_T_nexus_reset(struct domain_device *dev)
-{
-       return TMF_RESP_FUNC_FAILED;
+       switch (task->task_proto) {
+       case SAS_PROTOCOL_SMP:
+               dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n");
+               break;
+       case SAS_PROTOCOL_SSP:
+               dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n");
+               break;
+       case SAS_PROTOCOL_SATA:
+       case SAS_PROTOCOL_STP:
+       case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{
+               dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n");
+#if _MV_DUMP
+               dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n");
+               mvs_hexdump(sizeof(struct host_to_dev_fis),
+                               (void *)&task->ata_task.fis, 0);
+               dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
+               mvs_hexdump(16, task->ata_task.atapi_packet, 0);
+#endif
+               spin_lock_irqsave(&task->task_state_lock, flags);
+               if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) {
+                       /* TODO */
+                       ;
+               }
+               spin_unlock_irqrestore(&task->task_state_lock, flags);
+               break;
+       }
+       default:
+               break;
+       }
+
+       if (mvs_find_tag(mvi, task, &tag)) {
+               spin_lock_irqsave(&mvi->lock, flags);
+               mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag);
+               spin_unlock_irqrestore(&mvi->lock, flags);
+       }
+       if (!mvs_task_exec(task, 1, GFP_ATOMIC))
+               rc = TMF_RESP_FUNC_COMPLETE;
+       else
+               rc = TMF_RESP_FUNC_FAILED;
+out_done:
+       return rc;
 }
 
-static int __devinit mvs_hw_init(struct mvs_info *mvi)
+int __devinit mvs_hw_init(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
        int i;
@@ -3041,7 +1804,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
        return 0;
 }
 
-static void __devinit mvs_print_info(struct mvs_info *mvi)
+void __devinit mvs_print_info(struct mvs_info *mvi)
 {
        struct pci_dev *pdev = mvi->pdev;
        static int printed_version;
@@ -3053,170 +1816,3 @@ static void __devinit mvs_print_info(struct mvs_info *mvi)
                   mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr));
 }
 
-static int __devinit mvs_pci_init(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
-{
-       int rc;
-       struct mvs_info *mvi;
-       irq_handler_t irq_handler = mvs_interrupt;
-
-       rc = pci_enable_device(pdev);
-       if (rc)
-               return rc;
-
-       pci_set_master(pdev);
-
-       rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc)
-               goto err_out_disable;
-
-       rc = pci_go_64(pdev);
-       if (rc)
-               goto err_out_regions;
-
-       mvi = mvs_alloc(pdev, ent);
-       if (!mvi) {
-               rc = -ENOMEM;
-               goto err_out_regions;
-       }
-
-       rc = mvs_hw_init(mvi);
-       if (rc)
-               goto err_out_mvi;
-
-#ifndef MVS_DISABLE_MSI
-       if (!pci_enable_msi(pdev)) {
-               u32 tmp;
-               void __iomem *regs = mvi->regs;
-               mvi->flags |= MVF_MSI;
-               irq_handler = mvs_msi_interrupt;
-               tmp = mr32(PCS);
-               mw32(PCS, tmp | PCS_SELF_CLEAR);
-       }
-#endif
-
-       rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi);
-       if (rc)
-               goto err_out_msi;
-
-       rc = scsi_add_host(mvi->shost, &pdev->dev);
-       if (rc)
-               goto err_out_irq;
-
-       rc = sas_register_ha(&mvi->sas);
-       if (rc)
-               goto err_out_shost;
-
-       pci_set_drvdata(pdev, mvi);
-
-       mvs_print_info(mvi);
-
-       mvs_hba_interrupt_enable(mvi);
-
-       scsi_scan_host(mvi->shost);
-
-       return 0;
-
-err_out_shost:
-       scsi_remove_host(mvi->shost);
-err_out_irq:
-       free_irq(pdev->irq, mvi);
-err_out_msi:
-       if (mvi->flags |= MVF_MSI)
-               pci_disable_msi(pdev);
-err_out_mvi:
-       mvs_free(mvi);
-err_out_regions:
-       pci_release_regions(pdev);
-err_out_disable:
-       pci_disable_device(pdev);
-       return rc;
-}
-
-static void __devexit mvs_pci_remove(struct pci_dev *pdev)
-{
-       struct mvs_info *mvi = pci_get_drvdata(pdev);
-
-       pci_set_drvdata(pdev, NULL);
-
-       if (mvi) {
-               sas_unregister_ha(&mvi->sas);
-               mvs_hba_interrupt_disable(mvi);
-               sas_remove_host(mvi->shost);
-               scsi_remove_host(mvi->shost);
-
-               free_irq(pdev->irq, mvi);
-               if (mvi->flags & MVF_MSI)
-                       pci_disable_msi(pdev);
-               mvs_free(mvi);
-               pci_release_regions(pdev);
-       }
-       pci_disable_device(pdev);
-}
-
-static struct sas_domain_function_template mvs_transport_ops = {
-       .lldd_execute_task      = mvs_task_exec,
-       .lldd_control_phy       = mvs_phy_control,
-       .lldd_abort_task        = mvs_task_abort,
-       .lldd_port_formed       = mvs_port_formed,
-       .lldd_I_T_nexus_reset   = mvs_I_T_nexus_reset,
-};
-
-static struct pci_device_id __devinitdata mvs_pci_table[] = {
-       { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
-       { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
-       {
-               .vendor         = PCI_VENDOR_ID_MARVELL,
-               .device         = 0x6440,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = 0x6480,
-               .class          = 0,
-               .class_mask     = 0,
-               .driver_data    = chip_6480,
-       },
-       { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
-       { PCI_VDEVICE(MARVELL, 0x6480), chip_6480 },
-
-       { }     /* terminate list */
-};
-
-static struct pci_driver mvs_pci_driver = {
-       .name           = DRV_NAME,
-       .id_table       = mvs_pci_table,
-       .probe          = mvs_pci_init,
-       .remove         = __devexit_p(mvs_pci_remove),
-};
-
-static int __init mvs_init(void)
-{
-       int rc;
-
-       mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);
-       if (!mvs_stt)
-               return -ENOMEM;
-
-       rc = pci_register_driver(&mvs_pci_driver);
-       if (rc)
-               goto err_out;
-
-       return 0;
-
-err_out:
-       sas_release_transport(mvs_stt);
-       return rc;
-}
-
-static void __exit mvs_exit(void)
-{
-       pci_unregister_driver(&mvs_pci_driver);
-       sas_release_transport(mvs_stt);
-}
-
-module_init(mvs_init);
-module_exit(mvs_exit);
-
-MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
-MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
-MODULE_VERSION(DRV_VERSION);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, mvs_pci_table);
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
new file mode 100644 (file)
index 0000000..7a954a9
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+       mv_sas.h - Marvell 88SE6440 SAS/SATA support
+
+       Copyright 2007 Red Hat, Inc.
+       Copyright 2008 Marvell. <kewei@marvell.com>
+
+       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,
+       or (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty
+       of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+       See the GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public
+       License along with this program; see the file COPYING.  If not,
+       write to the Free Software Foundation, 675 Mass Ave, Cambridge,
+       MA 02139, USA.
+
+ */
+
+#ifndef _MV_SAS_H_
+#define _MV_SAS_H_
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/vmalloc.h>
+#include <scsi/libsas.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/sas_ata.h>
+#include <linux/version.h>
+#include "mv_defs.h"
+
+#define DRV_NAME       "mvsas"
+#define DRV_VERSION    "0.5.2"
+#define _MV_DUMP       0
+#define MVS_DISABLE_NVRAM
+#define MVS_DISABLE_MSI
+
+#define MVS_ID_NOT_MAPPED      0x7f
+#define MVS_CHIP_SLOT_SZ       (1U << mvi->chip->slot_width)
+
+#define for_each_phy(__lseq_mask, __mc, __lseq, __rest)                        \
+       for ((__mc) = (__lseq_mask), (__lseq) = 0;                      \
+                                       (__mc) != 0 && __rest;          \
+                                       (++__lseq), (__mc) >>= 1)
+
+struct mvs_chip_info {
+       u32             n_phy;
+       u32             srs_sz;
+       u32             slot_width;
+};
+
+struct mvs_err_info {
+       __le32                  flags;
+       __le32                  flags2;
+};
+
+struct mvs_cmd_hdr {
+       __le32                  flags;  /* PRD tbl len; SAS, SATA ctl */
+       __le32                  lens;   /* cmd, max resp frame len */
+       __le32                  tags;   /* targ port xfer tag; tag */
+       __le32                  data_len;       /* data xfer len */
+       __le64                  cmd_tbl;        /* command table address */
+       __le64                  open_frame;     /* open addr frame address */
+       __le64                  status_buf;     /* status buffer address */
+       __le64                  prd_tbl;                /* PRD tbl address */
+       __le32                  reserved[4];
+};
+
+struct mvs_port {
+       struct asd_sas_port     sas_port;
+       u8                      port_attached;
+       u8                      taskfileset;
+       u8                      wide_port_phymap;
+       struct list_head        list;
+};
+
+struct mvs_phy {
+       struct mvs_port         *port;
+       struct asd_sas_phy      sas_phy;
+       struct sas_identify     identify;
+       struct scsi_device      *sdev;
+       u64             dev_sas_addr;
+       u64             att_dev_sas_addr;
+       u32             att_dev_info;
+       u32             dev_info;
+       u32             phy_type;
+       u32             phy_status;
+       u32             irq_status;
+       u32             frame_rcvd_size;
+       u8              frame_rcvd[32];
+       u8              phy_attached;
+       enum sas_linkrate       minimum_linkrate;
+       enum sas_linkrate       maximum_linkrate;
+};
+
+struct mvs_slot_info {
+       struct list_head list;
+       struct sas_task *task;
+       u32 n_elem;
+       u32 tx;
+
+       /* DMA buffer for storing cmd tbl, open addr frame, status buffer,
+        * and PRD table
+        */
+       void *buf;
+       dma_addr_t buf_dma;
+#if _MV_DUMP
+       u32 cmd_size;
+#endif
+
+       void *response;
+       struct mvs_port *port;
+};
+
+struct mvs_info {
+       unsigned long flags;
+
+       /* host-wide lock */
+       spinlock_t lock;
+
+       /* our device */
+       struct pci_dev *pdev;
+
+       /* enhanced mode registers */
+       void __iomem *regs;
+
+       /* peripheral registers */
+       void __iomem *peri_regs;
+
+       u8 sas_addr[SAS_ADDR_SIZE];
+
+       /* SCSI/SAS glue */
+       struct sas_ha_struct sas;
+       struct Scsi_Host *shost;
+
+       /* TX (delivery) DMA ring */
+       __le32 *tx;
+       dma_addr_t tx_dma;
+
+       /* cached next-producer idx */
+       u32 tx_prod;
+
+       /* RX (completion) DMA ring */
+       __le32 *rx;
+       dma_addr_t rx_dma;
+
+       /* RX consumer idx */
+       u32 rx_cons;
+
+       /* RX'd FIS area */
+       __le32 *rx_fis;
+       dma_addr_t rx_fis_dma;
+
+       /* DMA command header slots */
+       struct mvs_cmd_hdr *slot;
+       dma_addr_t slot_dma;
+
+       const struct mvs_chip_info *chip;
+
+       u8 tags[MVS_SLOTS];
+       struct mvs_slot_info slot_info[MVS_SLOTS];
+                               /* further per-slot information */
+       struct mvs_phy phy[MVS_MAX_PHYS];
+       struct mvs_port port[MVS_MAX_PHYS];
+#ifdef MVS_USE_TASKLET
+       struct tasklet_struct tasklet;
+#endif
+};
+
+int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+                       void *funcdata);
+int mvs_slave_configure(struct scsi_device *sdev);
+void mvs_scan_start(struct Scsi_Host *shost);
+int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time);
+int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags);
+int mvs_task_abort(struct sas_task *task);
+void mvs_port_formed(struct asd_sas_phy *sas_phy);
+int mvs_I_T_nexus_reset(struct domain_device *dev);
+void mvs_int_full(struct mvs_info *mvi);
+void mvs_tag_init(struct mvs_info *mvi);
+int mvs_nvram_read(struct mvs_info *mvi, u32 addr, void *buf, u32 buflen);
+int __devinit mvs_hw_init(struct mvs_info *mvi);
+void __devinit mvs_print_info(struct mvs_info *mvi);
+void mvs_hba_interrupt_enable(struct mvs_info *mvi);
+void mvs_hba_interrupt_disable(struct mvs_info *mvi);
+void mvs_detect_porttype(struct mvs_info *mvi, int i);
+u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port);
+void mvs_enable_xmt(struct mvs_info *mvi, int PhyId);
+void __devinit mvs_phy_hacks(struct mvs_info *mvi);
+void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port);
+
+#endif