aboutsummaryrefslogtreecommitdiff
path: root/drivers/ata
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/Kconfig23
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c193
-rw-r--r--drivers/ata/ata_generic.c6
-rw-r--r--drivers/ata/ata_piix.c41
-rw-r--r--drivers/ata/libata-acpi.c150
-rw-r--r--drivers/ata/libata-core.c47
-rw-r--r--drivers/ata/libata-eh.c209
-rw-r--r--drivers/ata/libata-pmp.c51
-rw-r--r--drivers/ata/libata-scsi.c25
-rw-r--r--drivers/ata/libata-sff.c151
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--drivers/ata/pata_acpi.c6
-rw-r--r--drivers/ata/pata_ali.c10
-rw-r--r--drivers/ata/pata_amd.c14
-rw-r--r--drivers/ata/pata_at32.c2
-rw-r--r--drivers/ata/pata_bf54x.c5
-rw-r--r--drivers/ata/pata_cypress.c8
-rw-r--r--drivers/ata/pata_icside.c2
-rw-r--r--drivers/ata/pata_legacy.c50
-rw-r--r--drivers/ata/pata_ns87410.c6
-rw-r--r--drivers/ata/pata_ns87415.c4
-rw-r--r--drivers/ata/pata_pcmcia.c2
-rw-r--r--drivers/ata/pata_qdi.c16
-rw-r--r--drivers/ata/pata_rb532_cf.c4
-rw-r--r--drivers/ata/pata_scc.c5
-rw-r--r--drivers/ata/pata_sch.c206
-rw-r--r--drivers/ata/pata_sl82c105.c2
-rw-r--r--drivers/ata/pata_via.c14
-rw-r--r--drivers/ata/pata_winbond.c6
-rw-r--r--drivers/ata/sata_fsl.c224
-rw-r--r--drivers/ata/sata_inic162x.c646
-rw-r--r--drivers/ata/sata_mv.c957
-rw-r--r--drivers/ata/sata_promise.c148
-rw-r--r--drivers/ata/sata_sil24.c12
-rw-r--r--drivers/ata/sata_uli.c1
36 files changed, 2273 insertions, 976 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 1c11df9a5f3..ae8494944c4 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -205,8 +205,8 @@ config SATA_VITESSE
If unsure, say N.
config SATA_INIC162X
- tristate "Initio 162x SATA support (HIGHLY EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Initio 162x SATA support"
+ depends on PCI
help
This option enables support for Initio 162x Serial ATA.
@@ -651,9 +651,17 @@ config PATA_WINBOND_VLB
Support for the Winbond W83759A controller on Vesa Local Bus
systems.
+config HAVE_PATA_PLATFORM
+ bool
+ help
+ This is an internal configuration node for any machine that
+ uses pata-platform driver to enable the relevant driver in the
+ configuration structure without having to submit endless patches
+ to update the PATA_PLATFORM entry.
+
config PATA_PLATFORM
tristate "Generic platform device PATA support"
- depends on EMBEDDED || ARCH_RPC || PPC
+ depends on EMBEDDED || ARCH_RPC || PPC || HAVE_PATA_PLATFORM
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems.
@@ -697,6 +705,15 @@ config PATA_SCC
If unsure, say N.
+config PATA_SCH
+ tristate "Intel SCH PATA support"
+ depends on PCI
+ help
+ This option enables support for Intel SCH PATA on the Intel
+ SCH (US15W, US15L, UL11L) series host controllers.
+
+ If unsure, say N.
+
config PATA_BF54X
tristate "Blackfin 54x ATAPI support"
depends on BF542 || BF548 || BF549
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index b693d829383..674965fa326 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_PATA_SIS) += pata_sis.o
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
+obj-$(CONFIG_PATA_SCH) += pata_sch.o
obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 8cace9aa9c0..5e6468a7ca4 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -89,6 +89,8 @@ enum {
board_ahci_sb600 = 3,
board_ahci_mv = 4,
board_ahci_sb700 = 5,
+ board_ahci_mcp65 = 6,
+ board_ahci_nopmp = 7,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -190,6 +192,7 @@ enum {
AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */
AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */
+ AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */
/* ap->flags bits */
@@ -253,6 +256,8 @@ static void ahci_pmp_attach(struct ata_port *ap);
static void ahci_pmp_detach(struct ata_port *ap);
static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
+static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
@@ -329,6 +334,12 @@ static struct ata_port_operations ahci_p5wdh_ops = {
.hardreset = ahci_p5wdh_hardreset,
};
+static struct ata_port_operations ahci_sb600_ops = {
+ .inherits = &ahci_ops,
+ .softreset = ahci_sb600_softreset,
+ .pmp_softreset = ahci_sb600_softreset,
+};
+
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
static const struct ata_port_info ahci_port_info[] = {
@@ -359,11 +370,11 @@ static const struct ata_port_info ahci_port_info[] = {
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
- AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP),
+ AHCI_HFLAG_SECT255),
.flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
- .port_ops = &ahci_ops,
+ .port_ops = &ahci_sb600_ops,
},
/* board_ahci_mv */
{
@@ -377,8 +388,23 @@ static const struct ata_port_info ahci_port_info[] = {
},
/* board_ahci_sb700 */
{
- AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
- AHCI_HFLAG_NO_PMP),
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_sb600_ops,
+ },
+ /* board_ahci_mcp65 */
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
+ /* board_ahci_nopmp */
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_PMP),
.flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
@@ -438,14 +464,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
/* NVIDIA */
- { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 }, /* MCP65 */
{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */
@@ -502,15 +528,15 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */
{ PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */
{ PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd0), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd1), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd2), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd3), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */
/* SiS */
- { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
- { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
- { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x1184), board_ahci_nopmp }, /* SiS 966 */
+ { PCI_VDEVICE(SI, 0x1185), board_ahci_nopmp }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x0186), board_ahci_nopmp }, /* SiS 968 */
/* Marvell */
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
@@ -624,12 +650,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
cap &= ~HOST_CAP_NCQ;
}
+ if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can do NCQ, turning on CAP_NCQ\n");
+ cap |= HOST_CAP_NCQ;
+ }
+
if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do PMP, turning off CAP_PMP\n");
cap &= ~HOST_CAP_PMP;
}
+ if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
+ port_map != 1) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
+ port_map, 1);
+ port_map = 1;
+ }
+
/*
* Temporary Marvell 6145 hack: PATA port presence
* is asserted through the standard AHCI port
@@ -1262,21 +1302,11 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
return 0;
}
-static int ahci_check_ready(struct ata_link *link)
-{
- void __iomem *port_mmio = ahci_port_base(link->ap);
- u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
-
- if (!(status & ATA_BUSY))
- return 1;
- return 0;
-}
-
-static int ahci_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
+ int pmp, unsigned long deadline,
+ int (*check_ready)(struct ata_link *link))
{
struct ata_port *ap = link->ap;
- int pmp = sata_srst_pmp(link);
const char *reason = NULL;
unsigned long now, msecs;
struct ata_taskfile tf;
@@ -1314,7 +1344,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
/* wait for link to become ready */
- rc = ata_wait_after_reset(link, deadline, ahci_check_ready);
+ rc = ata_wait_after_reset(link, deadline, check_ready);
/* link occupied, -ENODEV too is an error */
if (rc) {
reason = "device not ready";
@@ -1330,6 +1360,72 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
return rc;
}
+static int ahci_check_ready(struct ata_link *link)
+{
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
+
+ return ata_check_ready(status);
+}
+
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int pmp = sata_srst_pmp(link);
+
+ DPRINTK("ENTER\n");
+
+ return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
+}
+
+static int ahci_sb600_check_ready(struct ata_link *link)
+{
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
+ u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
+
+ /*
+ * There is no need to check TFDATA if BAD PMP is found due to HW bug,
+ * which can save timeout delay.
+ */
+ if (irq_status & PORT_IRQ_BAD_PMP)
+ return -EIO;
+
+ return ata_check_ready(status);
+}
+
+static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int pmp = sata_srst_pmp(link);
+ int rc;
+ u32 irq_sts;
+
+ DPRINTK("ENTER\n");
+
+ rc = ahci_do_softreset(link, class, pmp, deadline,
+ ahci_sb600_check_ready);
+
+ /*
+ * Soft reset fails on some ATI chips with IPMS set when PMP
+ * is enabled but SATA HDD/ODD is connected to SATA port,
+ * do soft reset again to port 0.
+ */
+ if (rc == -EIO) {
+ irq_sts = readl(port_mmio + PORT_IRQ_STAT);
+ if (irq_sts & PORT_IRQ_BAD_PMP) {
+ ata_link_printk(link, KERN_WARNING,
+ "failed due to HW bug, retry pmp=0\n");
+ rc = ahci_do_softreset(link, class, 0, deadline,
+ ahci_check_ready);
+ }
+ }
+
+ return rc;
+}
+
static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
@@ -1681,7 +1777,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
struct ahci_host_priv *hpriv;
unsigned int i, handled = 0;
void __iomem *mmio;
- u32 irq_stat, irq_ack = 0;
+ u32 irq_stat, irq_masked;
VPRINTK("ENTER\n");
@@ -1690,16 +1786,17 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
/* sigh. 0xffffffff is a valid return from h/w */
irq_stat = readl(mmio + HOST_IRQ_STAT);
- irq_stat &= hpriv->port_map;
if (!irq_stat)
return IRQ_NONE;
+ irq_masked = irq_stat & hpriv->port_map;
+
spin_lock(&host->lock);
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
- if (!(irq_stat & (1 << i)))
+ if (!(irq_masked & (1 << i)))
continue;
ap = host->ports[i];
@@ -1713,14 +1810,20 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
"interrupt on disabled port %u\n", i);
}
- irq_ack |= (1 << i);
- }
-
- if (irq_ack) {
- writel(irq_ack, mmio + HOST_IRQ_STAT);
handled = 1;
}
+ /* HOST_IRQ_STAT behaves as level triggered latch meaning that
+ * it should be cleared after all the port events are cleared;
+ * otherwise, it will raise a spurious interrupt after each
+ * valid one. Please read section 10.6.2 of ahci 1.1 for more
+ * information.
+ *
+ * Also, use the unmasked value to clear interrupt as spurious
+ * pending event on a dummy port might cause screaming IRQ.
+ */
+ writel(irq_stat, mmio + HOST_IRQ_STAT);
+
spin_unlock(&host->lock);
VPRINTK("EXIT\n");
@@ -2120,7 +2223,8 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_port_info pi = ahci_port_info[ent->driver_data];
+ unsigned int board_id = ent->driver_data;
+ struct ata_port_info pi = ahci_port_info[board_id];
const struct ata_port_info *ppi[] = { &pi, NULL };
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
@@ -2169,6 +2273,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENOMEM;
hpriv->flags |= (unsigned long)pi.private_data;
+ /* MCP65 revision A1 and A2 can't do MSI */
+ if (board_id == board_ahci_mcp65 &&
+ (pdev->revision == 0xa1 || pdev->revision == 0xa2))
+ hpriv->flags |= AHCI_HFLAG_NO_MSI;
+
if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
pci_intx(pdev, 1);
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 47aeccd52fa..75a406f5e69 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -152,6 +152,12 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
if (dev->vendor == PCI_VENDOR_ID_AL)
ata_pci_bmdma_clear_simplex(dev);
+ if (dev->vendor == PCI_VENDOR_ID_ATI) {
+ int rc = pcim_enable_device(dev);
+ if (rc < 0)
+ return rc;
+ pcim_pin_device(dev);
+ }
return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL);
}
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index ea2c7649d39..a90ae03f56b 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -247,10 +247,11 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller 2 IDE (ICH8) */
{ 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
- /* Mobile SATA Controller IDE (ICH8M) */
- { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* Mobile SATA Controller IDE (ICH8M), Apple */
{ 0x8086, 0x2828, 0x106b, 0x00a0, 0, 0, ich8m_apple_sata },
+ { 0x8086, 0x2828, 0x106b, 0x00a1, 0, 0, ich8m_apple_sata },
+ /* Mobile SATA Controller IDE (ICH8M) */
+ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (ICH9) */
{ 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (ICH9) */
@@ -526,7 +527,7 @@ static struct ata_port_info piix_port_info[] = {
[ich8m_apple_sata] =
{
- .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
+ .flags = PIIX_SATA_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA6,
@@ -573,6 +574,8 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
{ 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
+ { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */
+ { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */
{ 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */
/* end marker */
{ 0, }
@@ -1040,6 +1043,13 @@ static int piix_broken_suspend(void)
},
},
{
+ .ident = "TECRA M4",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M4"),
+ },
+ },
+ {
.ident = "TECRA M5",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
@@ -1348,6 +1358,8 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
struct piix_host_priv *hpriv = host->private_data;
+ struct ata_device *dev0 = &host->ports[0]->link.device[0];
+ u32 scontrol;
int i;
/* check for availability */
@@ -1366,6 +1378,29 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
return;
hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
+
+ /* SCR access via SIDPR doesn't work on some configurations.
+ * Give it a test drive by inhibiting power save modes which
+ * we'll do anyway.
+ */
+ scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+
+ /* if IPM is already 3, SCR access is probably working. Don't
+ * un-inhibit power save modes as BIOS might have inhibited
+ * them for a reason.
+ */
+ if ((scontrol & 0xf00) != 0x300) {
+ scontrol |= 0x300;
+ piix_sidpr_write(dev0, SCR_CONTROL, scontrol);
+ scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+
+ if ((scontrol & 0xf00) != 0x300) {
+ dev_printk(KERN_INFO, host->dev, "SCR access via "
+ "SIDPR is available but doesn't work\n");
+ return;
+ }
+ }
+
host->ports[0]->ops = &piix_sidpr_sata_ops;
host->ports[1]->ops = &piix_sidpr_sata_ops;
}
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 70b77e0899a..3ff8b14420d 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -118,19 +118,82 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
}
+static void ata_acpi_eject_device(acpi_handle handle)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
+ &arg_list, NULL)))
+ printk(KERN_ERR "Failed to evaluate _EJ0!\n");
+}
+
+/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
+static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
+{
+ if (dev)
+ dev->flags |= ATA_DFLAG_DETACH;
+ else {
+ struct ata_link *tlink;
+ struct ata_device *tdev;
+
+ ata_port_for_each_link(tlink, ap)
+ ata_link_for_each_dev(tdev, tlink)
+ tdev->flags |= ATA_DFLAG_DETACH;
+ }
+
+ ata_port_schedule_eh(ap);
+}
+
+/**
+ * ata_acpi_handle_hotplug - ACPI event handler backend
+ * @ap: ATA port ACPI event occurred
+ * @dev: ATA device ACPI event occurred (can be NULL)
+ * @event: ACPI event which occurred
+ * @is_dock_event: boolean indicating whether the event was a dock one
+ *
+ * All ACPI bay / device realted events end up in this function. If
+ * the event is port-wide @dev is NULL. If the event is specific to a
+ * device, @dev points to it.
+ *
+ * Hotplug (as opposed to unplug) notification is always handled as
+ * port-wide while unplug only kills the target device on device-wide
+ * event.
+ *
+ * LOCKING:
+ * ACPI notify handler context. May sleep.
+ */
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
- u32 event)
+ u32 event, int is_dock_event)
{
char event_string[12];
char *envp[] = { event_string, NULL };
- struct ata_eh_info *ehi;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
struct kobject *kobj = NULL;
int wait = 0;
unsigned long flags;
+ acpi_handle handle, tmphandle;
+ unsigned long sta;
+ acpi_status status;
+
+ if (dev) {
+ if (dev->sdev)
+ kobj = &dev->sdev->sdev_gendev.kobj;
+ handle = dev->acpi_handle;
+ } else {
+ kobj = &ap->dev->kobj;
+ handle = ap->acpi_handle;
+ }
- if (!ap)
- ap = dev->link->ap;
- ehi = &ap->link.eh_info;
+ status = acpi_get_handle(handle, "_EJ0", &tmphandle);
+ if (ACPI_FAILURE(status))
+ /* This device does not support hotplug */
+ return;
spin_lock_irqsave(ap->lock, flags);
@@ -138,57 +201,80 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
ata_ehi_push_desc(ehi, "ACPI event");
- ata_ehi_hotplugged(ehi);
- ata_port_freeze(ap);
- break;
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status)) {
+ ata_port_printk(ap, KERN_ERR,
+ "acpi: failed to determine bay status (0x%x)\n",
+ status);
+ break;
+ }
+
+ if (sta) {
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
+ } else {
+ /* The device has gone - unplug it */
+ ata_acpi_detach_device(ap, dev);
+ wait = 1;
+ }
+ break;
case ACPI_NOTIFY_EJECT_REQUEST:
ata_ehi_push_desc(ehi, "ACPI event");
- if (dev)
- dev->flags |= ATA_DFLAG_DETACH;
- else {
- struct ata_link *tlink;
- struct ata_device *tdev;
-
- ata_port_for_each_link(tlink, ap)
- ata_link_for_each_dev(tdev, tlink)
- tdev->flags |= ATA_DFLAG_DETACH;
- }
- ata_port_schedule_eh(ap);
+ if (!is_dock_event)
+ break;
+
+ /* undock event - immediate unplug */
+ ata_acpi_detach_device(ap, dev);
wait = 1;
break;
}
- if (dev) {
- if (dev->sdev)
- kobj = &dev->sdev->sdev_gendev.kobj;
- } else
- kobj = &ap->dev->kobj;
+ /* make sure kobj doesn't go away while ap->lock is released */
+ kobject_get(kobj);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ if (wait) {
+ ata_port_wait_eh(ap);
+ ata_acpi_eject_device(handle);
+ }
- if (kobj) {
+ if (kobj && !is_dock_event) {
sprintf(event_string, "BAY_EVENT=%d", event);
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
}
- spin_unlock_irqrestore(ap->lock, flags);
+ kobject_put(kobj);
+}
- if (wait)
- ata_port_wait_eh(ap);
+static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_device *dev = data;
+
+ ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1);
+}
+
+static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_port *ap = data;
+
+ ata_acpi_handle_hotplug(ap, NULL, event, 1);
}
static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
{
struct ata_device *dev = data;
- ata_acpi_handle_hotplug(NULL, dev, event);
+ ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0);
}
static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
{
struct ata_port *ap = data;
- ata_acpi_handle_hotplug(ap, NULL, event);
+ ata_acpi_handle_hotplug(ap, NULL, event, 0);
}
/**
@@ -229,7 +315,7 @@ void ata_acpi_associate(struct ata_host *host)
ata_acpi_ap_notify, ap);
/* we might be on a docking station */
register_hotplug_dock_device(ap->acpi_handle,
- ata_acpi_ap_notify, ap);
+ ata_acpi_ap_notify_dock, ap);
}
for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
@@ -241,7 +327,7 @@ void ata_acpi_associate(struct ata_host *host)
ata_acpi_dev_notify, dev);
/* we might be on a docking station */
register_hotplug_dock_device(dev->acpi_handle,
- ata_acpi_dev_notify, dev);
+ ata_acpi_dev_notify_dock, dev);
}
}
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 3bc48853820..303fc0d2b97 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2126,6 +2126,13 @@ int ata_dev_configure(struct ata_device *dev)
dev->horkage |= ata_dev_blacklisted(dev);
ata_force_horkage(dev);
+ if (dev->horkage & ATA_HORKAGE_DISABLE) {
+ ata_dev_printk(dev, KERN_INFO,
+ "unsupported device, disabling\n");
+ ata_dev_disable(dev);
+ return 0;
+ }
+
/* let ACPI work its magic */
rc = ata_acpi_on_devcfg(dev);
if (rc)
@@ -3490,22 +3497,11 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
if ((rc = sata_link_debounce(link, params, deadline)))
return rc;
- /* Clear SError. PMP and some host PHYs require this to
- * operate and clearing should be done before checking PHY
- * online status to avoid race condition (hotplugging between
- * link resume and status check).
- */
+ /* clear SError, some PHYs require this even for SRST to work */
if (!(rc = sata_scr_read(link, SCR_ERROR, &serror)))
rc = sata_scr_write(link, SCR_ERROR, serror);
- if (rc == 0 || rc == -EINVAL) {
- unsigned long flags;
- spin_lock_irqsave(link->ap->lock, flags);
- link->eh_info.serror = 0;
- spin_unlock_irqrestore(link->ap->lock, flags);
- rc = 0;
- }
- return rc;
+ return rc != -EINVAL ? rc : 0;
}
/**
@@ -3653,9 +3649,13 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
if (check_ready)
rc = ata_wait_ready(link, deadline, check_ready);
out:
- if (rc && rc != -EAGAIN)
+ if (rc && rc != -EAGAIN) {
+ /* online is set iff link is online && reset succeeded */
+ if (online)
+ *online = false;
ata_link_printk(link, KERN_ERR,
"COMRESET failed (errno=%d)\n", rc);
+ }
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
}
@@ -3700,8 +3700,14 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class,
*/
void ata_std_postreset(struct ata_link *link, unsigned int *classes)
{
+ u32 serror;
+
DPRINTK("ENTER\n");
+ /* reset complete, clear SError */
+ if (!sata_scr_read(link, SCR_ERROR, &serror))
+ sata_scr_write(link, SCR_ERROR, serror);
+
/* print link status */
sata_print_link_status(link);
@@ -3894,8 +3900,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA },
{ "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA },
/* Odd clown on sil3726/4726 PMPs */
- { "Config Disk", NULL, ATA_HORKAGE_NODMA |
- ATA_HORKAGE_SKIP_PM },
+ { "Config Disk", NULL, ATA_HORKAGE_DISABLE },
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
@@ -4292,7 +4297,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
}
/**
- * ata_check_atapi_dma - Check whether ATAPI DMA can be supported
+ * atapi_check_dma - Check whether ATAPI DMA can be supported
* @qc: Metadata associated with taskfile to check
*
* Allow low-level driver to filter ATA PACKET commands, returning
@@ -4305,7 +4310,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
* RETURNS: 0 when ATAPI DMA can be used
* nonzero otherwise
*/
-int ata_check_atapi_dma(struct ata_queued_cmd *qc)
+int atapi_check_dma(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -5398,7 +5403,7 @@ static void ata_host_stop(struct device *gendev, void *res)
*/
static void ata_finalize_port_ops(struct ata_port_operations *ops)
{
- static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+ static DEFINE_SPINLOCK(lock);
const struct ata_port_operations *cur;
void **begin = (void **)ops;
void **end = (void **)&ops->inherits;
@@ -5616,7 +5621,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
spin_lock_irqsave(ap->lock, flags);
ehi->probe_mask |= ATA_ALL_DEVICES;
- ehi->action |= ATA_EH_RESET;
+ ehi->action |= ATA_EH_RESET | ATA_EH_LPM;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
ap->pflags &= ~ATA_PFLAG_INITIALIZING;
@@ -5649,7 +5654,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
struct ata_port *ap = host->ports[i];
ata_scsi_scan_host(ap, 1);
- ata_lpm_schedule(ap, ap->pm_policy);
}
return 0;
@@ -6292,6 +6296,7 @@ EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
+EXPORT_SYMBOL_GPL(ata_eh_analyze_ncq_error);
EXPORT_SYMBOL_GPL(ata_do_eh);
EXPORT_SYMBOL_GPL(ata_std_error_handler);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 61dcd0026c6..7894d83ea1e 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1308,12 +1308,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
unsigned int err_mask = 0, action = 0;
u32 hotplug_mask;
- if (serror & SERR_PERSISTENT) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_RESET;
- }
- if (serror &
- (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) {
+ if (serror & (SERR_PERSISTENT | SERR_DATA)) {
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_RESET;
}
@@ -1357,7 +1352,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_analyze_ncq_error(struct ata_link *link)
+void ata_eh_analyze_ncq_error(struct ata_link *link)
{
struct ata_port *ap = link->ap;
struct ata_eh_context *ehc = &link->eh_context;
@@ -2047,19 +2042,11 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
unsigned int *classes, unsigned long deadline)
{
struct ata_device *dev;
- int rc;
ata_link_for_each_dev(dev, link)
classes[dev->devno] = ATA_DEV_UNKNOWN;
- rc = reset(link, classes, deadline);
-
- /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
- ata_link_for_each_dev(dev, link)
- if (classes[dev->devno] == ATA_DEV_UNKNOWN)
- classes[dev->devno] = ATA_DEV_NONE;
-
- return rc;
+ return reset(link, classes, deadline);
}
static int ata_eh_followup_srst_needed(struct ata_link *link,
@@ -2096,9 +2083,11 @@ int ata_eh_reset(struct ata_link *link, int classify,
ata_reset_fn_t reset;
unsigned long flags;
u32 sstatus;
- int rc;
+ int nr_known, rc;
- /* about to reset */
+ /*
+ * Prepare to reset
+ */
spin_lock_irqsave(ap->lock, flags);
ap->pflags |= ATA_PFLAG_RESETTING;
spin_unlock_irqrestore(ap->lock, flags);
@@ -2124,16 +2113,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
ap->ops->set_piomode(ap, dev);
}
- if (!softreset && !hardreset) {
- if (verbose)
- ata_link_printk(link, KERN_INFO, "no reset method "
- "available, skipping reset\n");
- if (!(lflags & ATA_LFLAG_ASSUME_CLASS))
- lflags |= ATA_LFLAG_ASSUME_ATA;
- goto done;
- }
-
/* prefer hardreset */
+ reset = NULL;
ehc->i.action &= ~ATA_EH_RESET;
if (hardreset) {
reset = hardreset;
@@ -2141,11 +2122,6 @@ int ata_eh_reset(struct ata_link *link, int classify,
} else if (softreset) {
reset = softreset;
ehc->i.action = ATA_EH_SOFTRESET;
- } else {
- ata_link_printk(link, KERN_ERR, "BUG: no reset method, "
- "please report to linux-ide@vger.kernel.org\n");
- dump_stack();
- return -EINVAL;
}
if (prereset) {
@@ -2165,55 +2141,71 @@ int ata_eh_reset(struct ata_link *link, int classify,
"prereset failed (errno=%d)\n", rc);
goto out;
}
- }
- /* prereset() might have cleared ATA_EH_RESET */
- if (!(ehc->i.action & ATA_EH_RESET)) {
- /* prereset told us not to reset, bang classes and return */
- ata_link_for_each_dev(dev, link)
- classes[dev->devno] = ATA_DEV_NONE;
- rc = 0;
- goto out;
+ /* prereset() might have cleared ATA_EH_RESET. If so,
+ * bang classes and return.
+ */
+ if (reset && !(ehc->i.action & ATA_EH_RESET)) {
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_NONE;
+ rc = 0;
+ goto out;
+ }
}
retry:
+ /*
+ * Perform reset
+ */
+ if (ata_is_host_link(link))
+ ata_eh_freeze_port(ap);
+
deadline = jiffies + ata_eh_reset_timeouts[try++];
- /* shut up during boot probing */
- if (verbose)
- ata_link_printk(link, KERN_INFO, "%s resetting link\n",
- reset == softreset ? "soft" : "hard");
+ if (reset) {
+ if (verbose)
+ ata_link_printk(link, KERN_INFO, "%s resetting link\n",
+ reset == softreset ? "soft" : "hard");
- /* mark that this EH session started with reset */
- if (reset == hardreset)
- ehc->i.flags |= ATA_EHI_DID_HARDRESET;
- else
- ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
+ /* mark that this EH session started with reset */
+ if (reset == hardreset)
+ ehc->i.flags |= ATA_EHI_DID_HARDRESET;
+ else
+ ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
- rc = ata_do_reset(link, reset, classes, deadline);
+ rc = ata_do_reset(link, reset, classes, deadline);
- if (reset == hardreset &&
- ata_eh_followup_srst_needed(link, rc, classify, classes)) {
- /* okay, let's do follow-up softreset */
- reset = softreset;
+ if (reset == hardreset &&
+ ata_eh_followup_srst_needed(link, rc, classify, classes)) {
+ /* okay, let's do follow-up softreset */
+ reset = softreset;
- if (!reset) {
- ata_link_printk(link, KERN_ERR,
- "follow-up softreset required "
- "but no softreset avaliable\n");
- rc = -EINVAL;
- goto fail;
+ if (!reset) {
+ ata_link_printk(link, KERN_ERR,
+ "follow-up softreset required "
+ "but no softreset avaliable\n");
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
+ rc = ata_do_reset(link, reset, classes, deadline);
}
- ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
- rc = ata_do_reset(link, reset, classes, deadline);
+ /* -EAGAIN can happen if we skipped followup SRST */
+ if (rc && rc != -EAGAIN)
+ goto fail;
+ } else {
+ if (verbose)
+ ata_link_printk(link, KERN_INFO, "no reset method "
+ "available, skipping reset\n");
+ if (!(lflags & ATA_LFLAG_ASSUME_CLASS))
+ lflags |= ATA_LFLAG_ASSUME_ATA;
}
- /* -EAGAIN can happen if we skipped followup SRST */
- if (rc && rc != -EAGAIN)
- goto fail;
-
- done:
+ /*
+ * Post-reset processing
+ */
ata_link_for_each_dev(dev, link) {
/* After the reset, the device state is PIO 0 and the
* controller state is undefined. Reset also wakes up
@@ -2236,9 +2228,53 @@ int ata_eh_reset(struct ata_link *link, int classify,
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
link->sata_spd = (sstatus >> 4) & 0xf;
+ /* thaw the port */
+ if (ata_is_host_link(link))
+ ata_eh_thaw_port(ap);
+
+ /* postreset() should clear hardware SError. Although SError
+ * is cleared during link resume, clearing SError here is
+ * necessary as some PHYs raise hotplug events after SRST.
+ * This introduces race condition where hotplug occurs between
+ * reset and here. This race is mediated by cross checking
+ * link onlineness and classification result later.
+ */
if (postreset)
postreset(link, classes);
+ /* clear cached SError */
+ spin_lock_irqsave(link->ap->lock, flags);
+ link->eh_info.serror = 0;
+ spin_unlock_irqrestore(link->ap->lock, flags);
+
+ /* Make sure onlineness and classification result correspond.
+ * Hotplug could have happened during reset and some
+ * controllers fail to wait while a drive is spinning up after
+ * being hotplugged causing misdetection. By cross checking
+ * link onlineness and classification result, those conditions
+ * can be reliably detected and retried.
+ */
+ nr_known = 0;
+ ata_link_for_each_dev(dev, link) {
+ /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
+ if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ classes[dev->devno] = ATA_DEV_NONE;
+ else
+ nr_known++;
+ }
+
+ if (classify && !nr_known && ata_link_online(link)) {
+ if (try < max_tries) {
+ ata_link_printk(link, KERN_WARNING, "link online but "
+ "device misclassified, retrying\n");
+ rc = -EAGAIN;
+ goto fail;
+ }
+ ata_link_printk(link, KERN_WARNING,
+ "link online but device misclassified, "
+ "device detection might fail\n");
+ }
+
/* reset successful, schedule revalidation */
ata_eh_done(link, NULL, ATA_EH_RESET);
ehc->i.action |= ATA_EH_REVALIDATE;
@@ -2587,7 +2623,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
struct ata_link *link;
struct ata_device *dev;
int nr_failed_devs, nr_disabled_devs;
- int reset, rc;
+ int rc;
unsigned long flags;
DPRINTK("ENTER\n");
@@ -2630,7 +2666,6 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = 0;
nr_failed_devs = 0;
nr_disabled_devs = 0;
- reset = 0;
/* if UNLOADING, finish immediately */
if (ap->pflags & ATA_PFLAG_UNLOADING)
@@ -2644,40 +2679,24 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (ata_eh_skip_recovery(link))
ehc->i.action = 0;
- /* do we need to reset? */
- if (ehc->i.action & ATA_EH_RESET)
- reset = 1;
-
ata_link_for_each_dev(dev, link)
ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
}
/* reset */
- if (reset) {
- /* if PMP is attached, this function only deals with
- * downstream links, port should stay thawed.
- */
- if (!sata_pmp_attached(ap))
- ata_eh_freeze_port(ap);
-
- ata_port_for_each_link(link, ap) {
- struct ata_eh_context *ehc = &link->eh_context;
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
- if (!(ehc->i.action & ATA_EH_RESET))
- continue;
+ if (!(ehc->i.action & ATA_EH_RESET))
+ continue;
- rc = ata_eh_reset(link, ata_link_nr_vacant(link),
- prereset, softreset, hardreset,
- postreset);
- if (rc) {
- ata_link_printk(link, KERN_ERR,
- "reset failed, giving up\n");
- goto out;
- }
+ rc = ata_eh_reset(link, ata_link_nr_vacant(link),
+ prereset, softreset, hardreset, postreset);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "reset failed, giving up\n");
+ goto out;
}
-
- if (!sata_pmp_attached(ap))
- ata_eh_thaw_port(ap);
}
/* the rest */
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index ff1822a7da3..7daf4c0f621 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -48,7 +48,7 @@ static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
tf.device = link->pmp;
err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
- SATA_PMP_SCR_TIMEOUT);
+ SATA_PMP_RW_TIMEOUT);
if (err_mask)
return err_mask;
@@ -88,7 +88,7 @@ static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
tf.lbah = (val >> 24) & 0xff;
return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
- SATA_PMP_SCR_TIMEOUT);
+ SATA_PMP_RW_TIMEOUT);
}
/**
@@ -257,19 +257,6 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info)
goto fail;
}
- /* turn off notification till fan-out ports are reset and configured */
- if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
- gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
-
- err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
- gscr[SATA_PMP_GSCR_FEAT_EN]);
- if (err_mask) {
- rc = -EIO;
- reason = "failed to write GSCR_FEAT_EN";
- goto fail;
- }
- }
-
if (print_info) {
ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
"0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
@@ -335,9 +322,12 @@ static void sata_pmp_quirks(struct ata_port *ap)
if (vendor == 0x1095 && devid == 0x3726) {
/* sil3726 quirks */
ata_port_for_each_link(link, ap) {
- /* class code report is unreliable */
+ /* Class code report is unreliable and SRST
+ * times out under certain configurations.
+ */
if (link->pmp < 5)
- link->flags |= ATA_LFLAG_ASSUME_ATA;
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
/* port 5 is for SEMB device and it doesn't like SRST */
if (link->pmp == 5)
@@ -700,8 +690,6 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
if (ehc->i.action & ATA_EH_RESET) {
struct ata_link *tlink;
- ata_eh_freeze_port(ap);
-
/* reset */
rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
postreset);
@@ -711,8 +699,6 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
goto fail;
}
- ata_eh_thaw_port(ap);
-
/* PMP is reset, SErrors cannot be trusted, scan all */
ata_port_for_each_link(tlink, ap) {
struct ata_eh_context *ehc = &tlink->eh_context;
@@ -864,6 +850,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
struct ata_link *pmp_link = &ap->link;
struct ata_device *pmp_dev = pmp_link->device;
struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+ u32 *gscr = pmp_dev->gscr;
struct ata_link *link;
struct ata_device *dev;
unsigned int err_mask;
@@ -901,6 +888,22 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
if (rc)
goto pmp_fail;
+ /* PHY event notification can disturb reset and other recovery
+ * operations. Turn it off.
+ */
+ if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
+ gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+
+ err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
+ gscr[SATA_PMP_GSCR_FEAT_EN]);
+ if (err_mask) {
+ ata_link_printk(pmp_link, KERN_WARNING,
+ "failed to disable NOTIFY (err_mask=0x%x)\n",
+ err_mask);
+ goto pmp_fail;
+ }
+ }
+
/* handle disabled links */
rc = sata_pmp_eh_handle_disabled_links(ap);
if (rc)
@@ -923,10 +926,10 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
/* enable notification */
if (pmp_dev->flags & ATA_DFLAG_AN) {
- pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+ gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
- err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN,
- pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]);
+ err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
+ gscr[SATA_PMP_GSCR_FEAT_EN]);
if (err_mask) {
ata_dev_printk(pmp_dev, KERN_ERR, "failed to write "
"PMP_FEAT_EN (Emask=0x%x)\n", err_mask);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3ce43920e45..57a43649a46 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1082,12 +1082,6 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
if (((cdb[4] >> 4) & 0xf) != 0)
goto invalid_fld; /* power conditions not supported */
- if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) {
- /* the device lacks PM support, finish without doing anything */
- scmd->result = SAM_STAT_GOOD;
- return 1;
- }
-
if (cdb[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
@@ -1643,6 +1637,7 @@ defer:
/**
* ata_scsi_rbuf_get - Map response buffer.
+ * @cmd: SCSI command containing buffer to be mapped.
* @flags: unsigned long variable to store irq enable status
* @copy_in: copy in from user buffer
*
@@ -1960,7 +1955,7 @@ static unsigned int ata_msense_ctl_mode(u8 *buf)
/**
* ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
- * @bufp: output buffer
+ * @buf: output buffer
*
* Generate a generic MODE SENSE r/w error recovery page.
*
@@ -2348,8 +2343,8 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *scmd = qc->scsicmd;
struct ata_device *dev = qc->dev;
- int using_pio = (dev->flags & ATA_DFLAG_PIO);
int nodata = (scmd->sc_data_direction == DMA_NONE);
+ int using_pio = !nodata && (dev->flags & ATA_DFLAG_PIO);
unsigned int nbytes;
memset(qc->cdb, 0, dev->cdb_len);
@@ -2367,7 +2362,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
ata_qc_set_pc_nbytes(qc);
/* check whether ATAPI DMA is safe */
- if (!using_pio && ata_check_atapi_dma(qc))
+ if (!nodata && !using_pio && atapi_check_dma(qc))
using_pio = 1;
/* Some controller variants snoop this value for Packet
@@ -2407,13 +2402,11 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
qc->tf.lbam = (nbytes & 0xFF);
qc->tf.lbah = (nbytes >> 8);
- if (using_pio || nodata) {
- /* no data, or PIO data xfer */
- if (nodata)
- qc->tf.protocol = ATAPI_PROT_NODATA;
- else
- qc->tf.protocol = ATAPI_PROT_PIO;
- } else {
+ if (nodata)
+ qc->tf.protocol = ATAPI_PROT_NODATA;
+ else if (using_pio)
+ qc->tf.protocol = ATAPI_PROT_PIO;
+ else {
/* DMA data xfer */
qc->tf.protocol = ATAPI_PROT_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 2ec65a8fda7..c0908c22548 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -247,7 +247,7 @@ u8 ata_sff_check_status(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-u8 ata_sff_altstatus(struct ata_port *ap)
+static u8 ata_sff_altstatus(struct ata_port *ap)
{
if (ap->ops->sff_check_altstatus)
return ap->ops->sff_check_altstatus(ap);
@@ -256,6 +256,93 @@ u8 ata_sff_altstatus(struct ata_port *ap)
}
/**
+ * ata_sff_irq_status - Check if the device is busy
+ * @ap: port where the device is
+ *
+ * Determine if the port is currently busy. Uses altstatus
+ * if available in order to avoid clearing shared IRQ status
+ * when finding an IRQ source. Non ctl capable devices don't
+ * share interrupt lines fortunately for us.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static u8 ata_sff_irq_status(struct ata_port *ap)
+{
+ u8 status;
+
+ if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+ status = ata_sff_altstatus(ap);
+ /* Not us: We are busy */
+ if (status & ATA_BUSY)
+ return status;
+ }
+ /* Clear INTRQ latch */
+ status = ap->ops->sff_check_status(ap);
+ return status;
+}
+
+/**
+ * ata_sff_sync - Flush writes
+ * @ap: Port to wait for.
+ *
+ * CAUTION:
+ * If we have an mmio device with no ctl and no altstatus
+ * method this will fail. No such devices are known to exist.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_sff_sync(struct ata_port *ap)
+{
+ if (ap->ops->sff_check_altstatus)
+ ap->ops->sff_check_altstatus(ap);
+ else if (ap->ioaddr.altstatus_addr)
+ ioread8(ap->ioaddr.altstatus_addr);
+}
+
+/**
+ * ata_sff_pause - Flush writes and wait 400nS
+ * @ap: Port to pause for.
+ *
+ * CAUTION:
+ * If we have an mmio device with no ctl and no altstatus
+ * method this will fail. No such devices are known to exist.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_sff_pause(struct ata_port *ap)
+{
+ ata_sff_sync(ap);
+ ndelay(400);
+}
+
+/**
+ * ata_sff_dma_pause - Pause before commencing DMA
+ * @ap: Port to pause for.
+ *
+ * Perform I/O fencing and ensure sufficient cycle delays occur
+ * for the HDMA1:0 transition
+ */
+
+void ata_sff_dma_pause(struct ata_port *ap)
+{
+ if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+ /* An altstatus read will cause the needed delay without
+ messing up the IRQ status */
+ ata_sff_altstatus(ap);
+ return;
+ }
+ /* There are no DMA controllers without ctl. BUG here to ensure
+ we never violate the HDMA1:0 transition timing and risk
+ corruption. */
+ BUG();
+}
+
+/**
* ata_sff_busy_sleep - sleep until BSY clears, or timeout
* @ap: port containing status register to be polled
* @tmout_pat: impatience timeout
@@ -314,11 +401,7 @@ static int ata_sff_check_ready(struct ata_link *link)
{
u8 status = link->ap->ops->sff_check_status(link->ap);
- if (!(status & ATA_BUSY))
- return 1;
- if (status == 0xff)
- return -ENODEV;
- return 0;
+ return ata_check_ready(status);
}
/**
@@ -746,7 +829,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
} else
ata_pio_sector(qc);
- ata_sff_altstatus(qc->ap); /* flush */
+ ata_sff_sync(qc->ap); /* flush */
}
/**
@@ -767,8 +850,9 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
WARN_ON(qc->dev->cdb_len < 12);
ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
- ata_sff_altstatus(ap); /* flush */
-
+ ata_sff_sync(ap);
+ /* FIXME: If the CDB is for DMA do we need to do the transition delay
+ or is bmdma_start guaranteed to do it ? */
switch (qc->tf.protocol) {
case ATAPI_PROT_PIO:
ap->hsm_task_state = HSM_ST;
@@ -909,7 +993,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
if (unlikely(__atapi_pio_bytes(qc, bytes)))
goto err_out;
- ata_sff_altstatus(ap); /* flush */
+ ata_sff_sync(ap); /* flush */
return;
@@ -1010,6 +1094,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
u8 status, int in_wq)
{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned long flags = 0;
int poll_next;
@@ -1041,9 +1126,12 @@ fsm_start:
if (likely(status & (ATA_ERR | ATA_DF)))
/* device stops HSM for abort/error */
qc->err_mask |= AC_ERR_DEV;
- else
+ else {
/* HSM violation. Let EH handle this */
+ ata_ehi_push_desc(ehi,
+ "ST_FIRST: !(DRQ|ERR|DF)");
qc->err_mask |= AC_ERR_HSM;
+ }
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1062,9 +1150,9 @@ fsm_start:
* the CDB.
*/
if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) {
- ata_port_printk(ap, KERN_WARNING,
- "DRQ=1 with device error, "
- "dev_stat 0x%X\n", status);
+ ata_ehi_push_desc(ehi, "ST_FIRST: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1121,9 +1209,9 @@ fsm_start:
* let the EH abort the command or reset the device.
*/
if (unlikely(status & (ATA_ERR | ATA_DF))) {
- ata_port_printk(ap, KERN_WARNING, "DRQ=1 with "
- "device error, dev_stat 0x%X\n",
- status);
+ ata_ehi_push_desc(ehi, "ST-ATAPI: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1142,13 +1230,17 @@ fsm_start:
if (likely(status & (ATA_ERR | ATA_DF)))
/* device stops HSM for abort/error */
qc->err_mask |= AC_ERR_DEV;
- else
+ else {
/* HSM violation. Let EH handle this.
* Phantom devices also trigger this
* condition. Mark hint.
*/
+ ata_ehi_push_desc(ehi, "ST-ATA: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM |
AC_ERR_NODEV_HINT;
+ }
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1173,8 +1265,12 @@ fsm_start:
status = ata_wait_idle(ap);
}
- if (status & (ATA_BUSY | ATA_DRQ))
+ if (status & (ATA_BUSY | ATA_DRQ)) {
+ ata_ehi_push_desc(ehi, "ST-ATA: "
+ "BUSY|DRQ persists on ERR|DF, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
+ }
/* ata_pio_sectors() might change the
* state to HSM_ST_LAST. so, the state
@@ -1493,14 +1589,10 @@ inline unsigned int ata_sff_host_intr(struct ata_port *ap,
goto idle_irq;
}
- /* check altstatus */
- status = ata_sff_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
- /* check main status, clearing INTRQ */
- status = ap->ops->sff_check_status(ap);
- if (unlikely(status & ATA_BUSY))
+ /* check main status, clearing INTRQ if needed */
+ status = ata_sff_irq_status(ap);
+ if (status & ATA_BUSY)
goto idle_irq;
/* ack bmdma irq events */
@@ -2034,7 +2126,7 @@ void ata_sff_error_handler(struct ata_port *ap)
ap->ops->bmdma_stop(qc);
}
- ata_sff_altstatus(ap);
+ ata_sff_sync(ap); /* FIXME: We don't need this */
ap->ops->sff_check_status(ap);
ap->ops->sff_irq_clear(ap);
@@ -2207,7 +2299,7 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc)
mmio + ATA_DMA_CMD);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
- ata_sff_altstatus(ap); /* dummy read */
+ ata_sff_dma_pause(ap);
}
/**
@@ -2726,7 +2818,8 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_prep);
EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep);
EXPORT_SYMBOL_GPL(ata_sff_dev_select);
EXPORT_SYMBOL_GPL(ata_sff_check_status);
-EXPORT_SYMBOL_GPL(ata_sff_altstatus);
+EXPORT_SYMBOL_GPL(ata_sff_dma_pause);
+EXPORT_SYMBOL_GPL(ata_sff_pause);
EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
EXPORT_SYMBOL_GPL(ata_sff_wait_ready);
EXPORT_SYMBOL_GPL(ata_sff_tf_load);
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 4514283937e..1cf803adbc9 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -106,7 +106,7 @@ extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
-extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
+extern int atapi_check_dma(struct ata_queued_cmd *qc);
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
extern void ata_dev_init(struct ata_device *dev);
extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index c5f91e62994..fbe60571155 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -259,6 +259,12 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
.port_ops = &pacpi_ops,
};
const struct ata_port_info *ppi[] = { &info, NULL };
+ if (pdev->vendor == PCI_VENDOR_ID_ATI) {
+ int rc = pcim_enable_device(pdev);
+ if (rc < 0)
+ return rc;
+ pcim_pin_device(pdev);
+ }
return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL);
}
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index fcabe46f262..0f3e659db99 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -177,11 +177,11 @@ static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, stru
u8 udma;
if (t != NULL) {
- t->setup = FIT(t->setup, 1, 8) & 7;
- t->act8b = FIT(t->act8b, 1, 8) & 7;
- t->rec8b = FIT(t->rec8b, 1, 16) & 15;
- t->active = FIT(t->active, 1, 8) & 7;
- t->recover = FIT(t->recover, 1, 16) & 15;
+ t->setup = clamp_val(t->setup, 1, 8) & 7;
+ t->act8b = clamp_val(t->act8b, 1, 8) & 7;
+ t->rec8b = clamp_val(t->rec8b, 1, 16) & 15;
+ t->active = clamp_val(t->active, 1, 8) & 7;
+ t->recover = clamp_val(t->recover, 1, 16) & 15;
pci_write_config_byte(pdev, cas, t->setup);
pci_write_config_byte(pdev, cbt, (t->act8b << 4) | t->rec8b);
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 26665c39648..57dd00f463d 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -84,32 +84,32 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
/* Configure the address set up timing */
pci_read_config_byte(pdev, offset + 0x0C, &t);
- t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(at.setup, 1, 4) - 1) << ((3 - dn) << 1));
+ t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(at.setup, 1, 4) - 1) << ((3 - dn) << 1));
pci_write_config_byte(pdev, offset + 0x0C , t);
/* Configure the 8bit I/O timing */
pci_write_config_byte(pdev, offset + 0x0E + (1 - (dn >> 1)),
- ((FIT(at.act8b, 1, 16) - 1) << 4) | (FIT(at.rec8b, 1, 16) - 1));
+ ((clamp_val(at.act8b, 1, 16) - 1) << 4) | (clamp_val(at.rec8b, 1, 16) - 1));
/* Drive timing */
pci_write_config_byte(pdev, offset + 0x08 + (3 - dn),
- ((FIT(at.active, 1, 16) - 1) << 4) | (FIT(at.recover, 1, 16) - 1));
+ ((clamp_val(at.active, 1, 16) - 1) << 4) | (clamp_val(at.recover, 1, 16) - 1));
switch (clock) {
case 1:
- t = at.udma ? (0xc0 | (FIT(at.udma, 2, 5) - 2)) : 0x03;
+ t = at.udma ? (0xc0 | (clamp_val(at.udma, 2, 5) - 2)) : 0x03;
break;
case 2:
- t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 2, 10)]) : 0x03;
+ t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 2, 10)]) : 0x03;
break;
case 3:
- t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 10)]) : 0x03;
+ t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 1, 10)]) : 0x03;
break;
case 4:
- t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 15)]) : 0x03;
+ t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 1, 15)]) : 0x03;
break;
default:
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
index 5e104385d6a..82fb6e27316 100644
--- a/drivers/ata/pata_at32.c
+++ b/drivers/ata/pata_at32.c
@@ -291,8 +291,6 @@ static int __init pata_at32_probe(struct platform_device *pdev)
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(struct at32_ide_info));
-
info->irq = irq;
info->cs = board->cs;
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index 9ab89732cf9..55516103626 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -911,7 +911,10 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
/* Reset all transfer count */
ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
- /* Set transfer length to buffer len */
+ /* Set ATAPI state machine contorl in terminate sequence */
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | END_ON_TERM);
+
+ /* Set transfer length to buffer len */
for_each_sg(qc->sg, sg, qc->n_elem, si) {
ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
}
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index a9c3218e22f..2ff62608ae3 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -62,14 +62,14 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
return;
}
- time_16 = FIT(t.recover, 0, 15) | (FIT(t.active, 0, 15) << 4);
- time_8 = FIT(t.act8b, 0, 15) | (FIT(t.rec8b, 0, 15) << 4);
+ time_16 = clamp_val(t.recover, 0, 15) | (clamp_val(t.active, 0, 15) << 4);
+ time_8 = clamp_val(t.act8b, 0, 15) | (clamp_val(t.rec8b, 0, 15) << 4);
if (adev->devno == 0) {
pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
addr &= ~0x0F; /* Mask bits */
- addr |= FIT(t.setup, 0, 15);
+ addr |= clamp_val(t.setup, 0, 15);
pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16);
@@ -79,7 +79,7 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
addr &= ~0xF0; /* Mask bits */
- addr |= (FIT(t.setup, 0, 15) << 4);
+ addr |= (clamp_val(t.setup, 0, 15) << 4);
pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16);
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index 17138436423..cf9e9848f8b 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -270,7 +270,7 @@ static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc)
disable_dma(state->dma);
/* see ata_bmdma_stop */
- ata_sff_altstatus(ap);
+ ata_sff_dma_pause(ap);
}
static u8 pata_icside_bmdma_status(struct ata_port *ap)
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 7af4b29cc42..fe7cc8ed4ea 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -343,8 +343,8 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Get the timing data in cycles. For now play safe at 50Mhz */
ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
- active = FIT(t.active, 2, 15);
- recover = FIT(t.recover, 4, 15);
+ active = clamp_val(t.active, 2, 15);
+ recover = clamp_val(t.recover, 4, 15);
inb(0x3E6);
inb(0x3E6);
@@ -377,8 +377,8 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Get the timing data in cycles. For now play safe at 50Mhz */
ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
- active = FIT(t.active, 2, 15);
- recover = FIT(t.recover, 2, 16);
+ active = clamp_val(t.active, 2, 15);
+ recover = clamp_val(t.recover, 2, 16);
recover &= 0x15;
inb(0x3E6);
@@ -462,9 +462,9 @@ static void opti82c611a_set_piomode(struct ata_port *ap,
ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
}
- active = FIT(t.active, 2, 17) - 2;
- recover = FIT(t.recover, 1, 16) - 1;
- setup = FIT(t.setup, 1, 4) - 1;
+ active = clamp_val(t.active, 2, 17) - 2;
+ recover = clamp_val(t.recover, 1, 16) - 1;
+ setup = clamp_val(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
rc = ioread8(ap->ioaddr.lbal_addr);
@@ -541,9 +541,9 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
}
- active = FIT(t.active, 2, 17) - 2;
- recover = FIT(t.recover, 1, 16) - 1;
- setup = FIT(t.setup, 1, 4) - 1;
+ active = clamp_val(t.active, 2, 17) - 2;
+ recover = clamp_val(t.recover, 1, 16) - 1;
+ setup = clamp_val(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
rc = ioread8(ap->ioaddr.lbal_addr);
@@ -624,11 +624,11 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (ld_qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
@@ -658,11 +658,11 @@ static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (ld_qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
@@ -695,11 +695,11 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (ld_qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
ld_qdi->clock[adev->devno] = timing;
@@ -830,8 +830,8 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
else
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
- active = (FIT(t.active, 3, 17) - 1) & 0x0F;
- recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
+ active = (clamp_val(t.active, 3, 17) - 1) & 0x0F;
+ recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F;
timing = (active << 4) | recovery;
winbond_writecfg(ld_winbond->timing, timing, reg);
@@ -842,7 +842,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
reg |= 0x08; /* FIFO off */
if (!ata_pio_need_iordy(adev))
reg |= 0x02; /* IORDY off */
- reg |= (FIT(t.setup, 0, 3) << 6);
+ reg |= (clamp_val(t.setup, 0, 3) << 6);
winbond_writecfg(ld_winbond->timing, timing + 1, reg);
}
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 76d2455bc45..be756b7ef07 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -91,9 +91,9 @@ static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev)
return;
}
- at.active = FIT(at.active, 2, 16) - 2;
- at.setup = FIT(at.setup, 1, 4) - 1;
- at.recover = FIT(at.recover, 1, 12) - 1;
+ at.active = clamp_val(at.active, 2, 16) - 2;
+ at.setup = clamp_val(at.setup, 1, 4) - 1;
+ at.recover = clamp_val(at.recover, 1, 12) - 1;
idetcr = (at.setup << 6) | (recoverbits[at.recover] << 3) | activebits[at.active];
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
index ae92b0049bd..e0aa7eaaee0 100644
--- a/drivers/ata/pata_ns87415.c
+++ b/drivers/ata/pata_ns87415.c
@@ -66,8 +66,8 @@ static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
ata_timing_compute(adev, adev->pio_mode, &t, T, 0);
- clocking = 17 - FIT(t.active, 2, 17);
- clocking |= (16 - FIT(t.recover, 1, 16)) << 4;
+ clocking = 17 - clamp_val(t.active, 2, 17);
+ clocking |= (16 - clamp_val(t.recover, 1, 16)) << 4;
/* Use the same timing for read and write bytes */
clocking |= (clocking << 8);
pci_write_config_word(dev, timing, clocking);
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 3d39f9dfec5..41b4361bbf6 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -414,6 +414,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
@@ -424,6 +425,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index bf45cf01775..97e5b090d7c 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -60,11 +60,11 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
@@ -84,11 +84,11 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c
index a108d259f19..f8b3ffc8ae9 100644
--- a/drivers/ata/pata_rb532_cf.c
+++ b/drivers/ata/pata_rb532_cf.c
@@ -57,7 +57,9 @@ static inline void rb532_pata_finish_io(struct ata_port *ap)
struct ata_host *ah = ap->host;
struct rb532_cf_info *info = ah->private_data;
- ata_sff_altstatus(ap);
+ /* FIXME: Keep previous delay. If this is merely a fence then
+ ata_sff_sync might be sufficient. */
+ ata_sff_dma_pause(ap);
ndelay(RB500_CF_IO_DELAY);
set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH);
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index e965b251ca2..bbf5aa345e6 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -726,7 +726,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
- ata_sff_altstatus(ap); /* dummy read */
+ ata_sff_dma_pause(ap); /* dummy read */
}
/**
@@ -747,7 +747,8 @@ static u8 scc_bmdma_status (struct ata_port *ap)
return host_stat;
/* errata A252,A308 workaround: Step4 */
- if ((ata_sff_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
+ if ((scc_check_altstatus(ap) & ATA_ERR)
+ && (int_status & INTSTS_INTRQ))
return (host_stat | ATA_DMA_INTR);
/* errata A308 workaround Step5 */
diff --git a/drivers/ata/pata_sch.c b/drivers/ata/pata_sch.c
new file mode 100644
index 00000000000..c8cc027789f
--- /dev/null
+++ b/drivers/ata/pata_sch.c
@@ -0,0 +1,206 @@
+/*
+ * pata_sch.c - Intel SCH PATA controllers
+ *
+ * Copyright (c) 2008 Alek Du <alek.du@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Supports:
+ * Intel SCH (AF82US15W, AF82US15L, AF82UL11L) chipsets -- see spec at:
+ * http://download.intel.com/design/chipsets/embedded/datashts/319537.pdf
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/dmi.h>
+
+#define DRV_NAME "pata_sch"
+#define DRV_VERSION "0.2"
+
+/* see SCH datasheet page 351 */
+enum {
+ D0TIM = 0x80, /* Device 0 Timing Register */
+ D1TIM = 0x84, /* Device 1 Timing Register */
+ PM = 0x07, /* PIO Mode Bit Mask */
+ MDM = (0x03 << 8), /* Multi-word DMA Mode Bit Mask */
+ UDM = (0x07 << 16), /* Ultra DMA Mode Bit Mask */
+ PPE = (1 << 30), /* Prefetch/Post Enable */
+ USD = (1 << 31), /* Use Synchronous DMA */
+};
+
+static int sch_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev);
+static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev);
+
+static const struct pci_device_id sch_pci_tbl[] = {
+ /* Intel SCH PATA Controller */
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SCH_IDE), 0 },
+ { } /* terminate list */
+};
+
+static struct pci_driver sch_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sch_pci_tbl,
+ .probe = sch_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static struct scsi_host_template sch_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations sch_pata_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .cable_detect = ata_cable_unknown,
+ .set_piomode = sch_set_piomode,
+ .set_dmamode = sch_set_dmamode,
+};
+
+static struct ata_port_info sch_port_info = {
+ .flags = 0,
+ .pio_mask = ATA_PIO4, /* pio0-4 */
+ .mwdma_mask = ATA_MWDMA2, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .port_ops = &sch_pata_ops,
+};
+
+MODULE_AUTHOR("Alek Du <alek.du@intel.com>");
+MODULE_DESCRIPTION("SCSI low-level driver for Intel SCH PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sch_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+/**
+ * sch_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: ATA device
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int port = adev->devno ? D1TIM : D0TIM;
+ unsigned int data;
+
+ pci_read_config_dword(dev, port, &data);
+ /* see SCH datasheet page 351 */
+ /* set PIO mode */
+ data &= ~(PM | PPE);
+ data |= pio;
+ /* enable PPE for block device */
+ if (adev->class == ATA_DEV_ATA)
+ data |= PPE;
+ pci_write_config_dword(dev, port, data);
+}
+
+/**
+ * sch_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: ATA device
+ *
+ * Set MW/UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int dma_mode = adev->dma_mode;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int port = adev->devno ? D1TIM : D0TIM;
+ unsigned int data;
+
+ pci_read_config_dword(dev, port, &data);
+ /* see SCH datasheet page 351 */
+ if (dma_mode >= XFER_UDMA_0) {
+ /* enable Synchronous DMA mode */
+ data |= USD;
+ data &= ~UDM;
+ data |= (dma_mode - XFER_UDMA_0) << 16;
+ } else { /* must be MWDMA mode, since we masked SWDMA already */
+ data &= ~(USD | MDM);
+ data |= (dma_mode - XFER_MW_DMA_0) << 8;
+ }
+ pci_write_config_dword(dev, port, data);
+}
+
+/**
+ * sch_init_one - Register SCH ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in sch_pci_tbl matching with @pdev
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int __devinit sch_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int printed_version;
+ const struct ata_port_info *ppi[] = { &sch_port_info, NULL };
+ struct ata_host *host;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* enable device and prepare host */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+ rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+ if (rc)
+ return rc;
+ pci_set_master(pdev);
+ return ata_pci_sff_activate_host(host, ata_sff_interrupt, &sch_sht);
+}
+
+static int __init sch_init(void)
+{
+ return pci_register_driver(&sch_pci_driver);
+}
+
+static void __exit sch_exit(void)
+{
+ pci_unregister_driver(&sch_pci_driver);
+}
+
+module_init(sch_init);
+module_exit(sch_exit);
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 70d94fb28a5..69877bd8181 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -216,7 +216,7 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc)
struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
int rc;
- /* First apply the usual rules */
+ /* First apply the usual rules */
rc = ata_std_qc_defer(qc);
if (rc != 0)
return rc;
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 2fea6cbe775..708ed144ede 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -259,15 +259,15 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
pci_read_config_byte(pdev, 0x4C, &setup);
setup &= ~(3 << shift);
- setup |= FIT(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */
+ setup |= clamp_val(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */
pci_write_config_byte(pdev, 0x4C, setup);
}
/* Load the PIO mode bits */
pci_write_config_byte(pdev, 0x4F - ap->port_no,
- ((FIT(t.act8b, 1, 16) - 1) << 4) | (FIT(t.rec8b, 1, 16) - 1));
+ ((clamp_val(t.act8b, 1, 16) - 1) << 4) | (clamp_val(t.rec8b, 1, 16) - 1));
pci_write_config_byte(pdev, 0x48 + offset,
- ((FIT(t.active, 1, 16) - 1) << 4) | (FIT(t.recover, 1, 16) - 1));
+ ((clamp_val(t.active, 1, 16) - 1) << 4) | (clamp_val(t.recover, 1, 16) - 1));
/* Load the UDMA bits according to type */
switch(udma_type) {
@@ -275,16 +275,16 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
/* BUG() ? */
/* fall through */
case 33:
- ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 5) - 2)) : 0x03;
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03;
break;
case 66:
- ut = t.udma ? (0xe8 | (FIT(t.udma, 2, 9) - 2)) : 0x0f;
+ ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f;
break;
case 100:
- ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
break;
case 133:
- ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
break;
}
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 6e52a3573fb..474528f8fe3 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -75,8 +75,8 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
else
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
- active = (FIT(t.active, 3, 17) - 1) & 0x0F;
- recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
+ active = (clamp_val(t.active, 3, 17) - 1) & 0x0F;
+ recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F;
timing = (active << 4) | recovery;
winbond_writecfg(winbond->config, timing, reg);
@@ -87,7 +87,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
reg |= 0x08; /* FIFO off */
if (!ata_pio_need_iordy(adev))
reg |= 0x02; /* IORDY off */
- reg |= (FIT(t.setup, 0, 3) << 6);
+ reg |= (clamp_val(t.setup, 0, 3) << 6);
winbond_writecfg(winbond->config, timing + 1, reg);
}
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 853559e3231..3924e7209a4 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -34,7 +34,7 @@ enum {
SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_NCQ),
+ ATA_FLAG_PMP | ATA_FLAG_NCQ),
SATA_FSL_MAX_CMDS = SATA_FSL_QUEUE_DEPTH,
SATA_FSL_CMD_HDR_SIZE = 16, /* 4 DWORDS */
@@ -395,7 +395,7 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
cd = (struct command_desc *)pp->cmdentry + tag;
cd_paddr = pp->cmdentry_paddr + tag * SATA_FSL_CMD_DESC_SIZE;
- ata_tf_to_fis(&qc->tf, 0, 1, (u8 *) &cd->cfis);
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, (u8 *) &cd->cfis);
VPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x\n",
cd->cfis[0], cd->cfis[1], cd->cfis[2]);
@@ -438,6 +438,8 @@ static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc)
ioread32(CA + hcr_base),
ioread32(CE + hcr_base), ioread32(CC + hcr_base));
+ iowrite32(qc->dev->link->pmp, CQPMP + hcr_base);
+
/* Simply queue command to the controller/device */
iowrite32(1 << tag, CQ + hcr_base);
@@ -558,11 +560,36 @@ static void sata_fsl_thaw(struct ata_port *ap)
ioread32(hcr_base + HCONTROL), ioread32(hcr_base + HSTATUS));
}
+static void sata_fsl_pmp_attach(struct ata_port *ap)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp | HCONTROL_PMP_ATTACHED), hcr_base + HCONTROL);
+}
+
+static void sata_fsl_pmp_detach(struct ata_port *ap)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ temp = ioread32(hcr_base + HCONTROL);
+ temp &= ~HCONTROL_PMP_ATTACHED;
+ iowrite32(temp, hcr_base + HCONTROL);
+
+ /* enable interrupts on the controller/port */
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp | DEFAULT_PORT_IRQ_ENABLE_MASK), hcr_base + HCONTROL);
+
+}
+
static int sata_fsl_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
struct sata_fsl_port_priv *pp;
- int retval;
void *mem;
dma_addr_t mem_dma;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
@@ -688,12 +715,13 @@ static int sata_fsl_prereset(struct ata_link *link, unsigned long deadline)
}
static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+ unsigned long deadline)
{
struct ata_port *ap = link->ap;
struct sata_fsl_port_priv *pp = ap->private_data;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
+ int pmp = sata_srst_pmp(link);
u32 temp;
struct ata_taskfile tf;
u8 *cfis;
@@ -703,6 +731,9 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
DPRINTK("in xx_softreset\n");
+ if (pmp != SATA_PMP_CTRL_PORT)
+ goto issue_srst;
+
try_offline_again:
/*
* Force host controller to go off-line, aborting current operations
@@ -746,6 +777,7 @@ try_offline_again:
temp = ioread32(hcr_base + HCONTROL);
temp |= (HCONTROL_ONLINE_PHY_RST | HCONTROL_SNOOP_ENABLE);
+ temp |= HCONTROL_PMP_ATTACHED;
iowrite32(temp, hcr_base + HCONTROL);
temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, 0, 1, 500);
@@ -771,7 +803,8 @@ try_offline_again:
ata_port_printk(ap, KERN_WARNING,
"No Device OR PHYRDY change,Hstatus = 0x%x\n",
ioread32(hcr_base + HSTATUS));
- goto err;
+ *class = ATA_DEV_NONE;
+ goto out;
}
/*
@@ -783,7 +816,8 @@ try_offline_again:
if ((temp & 0xFF) != 0x18) {
ata_port_printk(ap, KERN_WARNING, "No Signature Update\n");
- goto err;
+ *class = ATA_DEV_NONE;
+ goto out;
} else {
ata_port_printk(ap, KERN_INFO,
"Signature Update detected @ %d msecs\n",
@@ -798,6 +832,7 @@ try_offline_again:
* reached here, we can send a command to the target device
*/
+issue_srst:
DPRINTK("Sending SRST/device reset\n");
ata_tf_init(link->device, &tf);
@@ -808,7 +843,7 @@ try_offline_again:
SRST_CMD | CMD_DESC_SNOOP_ENABLE, 0, 0, 5);
tf.ctl |= ATA_SRST; /* setup SRST bit in taskfile control reg */
- ata_tf_to_fis(&tf, 0, 0, cfis);
+ ata_tf_to_fis(&tf, pmp, 0, cfis);
DPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x, 0x%x\n",
cfis[0], cfis[1], cfis[2], cfis[3]);
@@ -854,8 +889,10 @@ try_offline_again:
sata_fsl_setup_cmd_hdr_entry(pp, 0, CMD_DESC_SNOOP_ENABLE, 0, 0, 5);
tf.ctl &= ~ATA_SRST; /* 2nd H2D Ctl. register FIS */
- ata_tf_to_fis(&tf, 0, 0, cfis);
+ ata_tf_to_fis(&tf, pmp, 0, cfis);
+ if (pmp != SATA_PMP_CTRL_PORT)
+ iowrite32(pmp, CQPMP + hcr_base);
iowrite32(1, CQ + hcr_base);
msleep(150); /* ?? */
@@ -886,12 +923,21 @@ try_offline_again:
VPRINTK("cereg = 0x%x\n", ioread32(hcr_base + CE));
}
+out:
return 0;
err:
return -EIO;
}
+static void sata_fsl_error_handler(struct ata_port *ap)
+{
+
+ DPRINTK("in xx_error_handler\n");
+ sata_pmp_error_handler(ap);
+
+}
+
static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc)
{
if (qc->flags & ATA_QCFLAG_FAILED)
@@ -905,18 +951,21 @@ static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc)
static void sata_fsl_error_intr(struct ata_port *ap)
{
- struct ata_link *link = &ap->link;
- struct ata_eh_info *ehi = &link->eh_info;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
- u32 hstatus, dereg, cereg = 0, SError = 0;
+ u32 hstatus, dereg=0, cereg = 0, SError = 0;
unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
- int freeze = 0;
+ int freeze = 0, abort=0;
+ struct ata_link *link = NULL;
+ struct ata_queued_cmd *qc = NULL;
+ struct ata_eh_info *ehi;
hstatus = ioread32(hcr_base + HSTATUS);
cereg = ioread32(hcr_base + CE);
+ /* first, analyze and record host port events */
+ link = &ap->link;
+ ehi = &link->eh_info;
ata_ehi_clear_desc(ehi);
/*
@@ -926,42 +975,28 @@ static void sata_fsl_error_intr(struct ata_port *ap)
sata_fsl_scr_read(ap, SCR_ERROR, &SError);
if (unlikely(SError & 0xFFFF0000)) {
sata_fsl_scr_write(ap, SCR_ERROR, SError);
- err_mask |= AC_ERR_ATA_BUS;
}
DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n",
hstatus, cereg, ioread32(hcr_base + DE), SError);
- /* handle single device errors */
- if (cereg) {
- /*
- * clear the command error, also clears queue to the device
- * in error, and we can (re)issue commands to this device.
- * When a device is in error all commands queued into the
- * host controller and at the device are considered aborted
- * and the queue for that device is stopped. Now, after
- * clearing the device error, we can issue commands to the
- * device to interrogate it to find the source of the error.
- */
- dereg = ioread32(hcr_base + DE);
- iowrite32(dereg, hcr_base + DE);
- iowrite32(cereg, hcr_base + CE);
+ /* handle fatal errors */
+ if (hstatus & FATAL_ERROR_DECODE) {
+ ehi->err_mask |= AC_ERR_ATA_BUS;
+ ehi->action |= ATA_EH_SOFTRESET;
- DPRINTK("single device error, CE=0x%x, DE=0x%x\n",
- ioread32(hcr_base + CE), ioread32(hcr_base + DE));
/*
- * We should consider this as non fatal error, and TF must
- * be updated as done below.
+ * Ignore serror in case of fatal errors as we always want
+ * to do a soft-reset of the FSL SATA controller. Analyzing
+ * serror may cause libata to schedule a hard-reset action,
+ * and hard-reset currently does not do controller
+ * offline/online, causing command timeouts and leads to an
+ * un-recoverable state, hence make libATA ignore
+ * autopsy in case of fatal errors.
*/
- err_mask |= AC_ERR_DEV;
- }
+ ehi->flags |= ATA_EHI_NO_AUTOPSY;
- /* handle fatal errors */
- if (hstatus & FATAL_ERROR_DECODE) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_RESET;
- /* how will fatal error interrupts be completed ?? */
freeze = 1;
}
@@ -971,30 +1006,83 @@ static void sata_fsl_error_intr(struct ata_port *ap)
/* Setup a soft-reset EH action */
ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, "%s", "PHY RDY changed");
freeze = 1;
}
- /* record error info */
- qc = ata_qc_from_tag(ap, link->active_tag);
+ /* handle single device errors */
+ if (cereg) {
+ /*
+ * clear the command error, also clears queue to the device
+ * in error, and we can (re)issue commands to this device.
+ * When a device is in error all commands queued into the
+ * host controller and at the device are considered aborted
+ * and the queue for that device is stopped. Now, after
+ * clearing the device error, we can issue commands to the
+ * device to interrogate it to find the source of the error.
+ */
+ abort = 1;
+
+ DPRINTK("single device error, CE=0x%x, DE=0x%x\n",
+ ioread32(hcr_base + CE), ioread32(hcr_base + DE));
- if (qc)
+ /* find out the offending link and qc */
+ if (ap->nr_pmp_links) {
+ dereg = ioread32(hcr_base + DE);
+ iowrite32(dereg, hcr_base + DE);
+ iowrite32(cereg, hcr_base + CE);
+
+ if (dereg < ap->nr_pmp_links) {
+ link = &ap->pmp_link[dereg];
+ ehi = &link->eh_info;
+ qc = ata_qc_from_tag(ap, link->active_tag);
+ /*
+ * We should consider this as non fatal error,
+ * and TF must be updated as done below.
+ */
+
+ err_mask |= AC_ERR_DEV;
+
+ } else {
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_HARDRESET;
+ freeze = 1;
+ }
+ } else {
+ dereg = ioread32(hcr_base + DE);
+ iowrite32(dereg, hcr_base + DE);
+ iowrite32(cereg, hcr_base + CE);
+
+ qc = ata_qc_from_tag(ap, link->active_tag);
+ /*
+ * We should consider this as non fatal error,
+ * and TF must be updated as done below.
+ */
+ err_mask |= AC_ERR_DEV;
+ }
+ }
+
+ /* record error info */
+ if (qc) {
qc->err_mask |= err_mask;
- else
+ } else
ehi->err_mask |= err_mask;
ehi->action |= action;
- ehi->serror |= SError;
/* freeze or abort */
if (freeze)
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ else if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
static void sata_fsl_host_intr(struct ata_port *ap)
{
- struct ata_link *link = &ap->link;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
u32 hstatus, qc_active = 0;
@@ -1017,10 +1105,19 @@ static void sata_fsl_host_intr(struct ata_port *ap)
return;
}
- if (link->sactive) { /* only true for NCQ commands */
+ /* Read command completed register */
+ qc_active = ioread32(hcr_base + CC);
+
+ VPRINTK("Status of all queues :\n");
+ VPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n",
+ qc_active,
+ ioread32(hcr_base + CA),
+ ioread32(hcr_base + CE),
+ ioread32(hcr_base + CQ),
+ ap->qc_active);
+
+ if (qc_active & ap->qc_active) {
int i;
- /* Read command completed register */
- qc_active = ioread32(hcr_base + CC);
/* clear CC bit, this will also complete the interrupt */
iowrite32(qc_active, hcr_base + CC);
@@ -1032,8 +1129,9 @@ static void sata_fsl_host_intr(struct ata_port *ap)
for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {
if (qc_active & (1 << i)) {
qc = ata_qc_from_tag(ap, i);
- if (qc)
+ if (qc) {
ata_qc_complete(qc);
+ }
DPRINTK
("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n",
i, ioread32(hcr_base + CC),
@@ -1042,19 +1140,21 @@ static void sata_fsl_host_intr(struct ata_port *ap)
}
return;
- } else if (ap->qc_active) {
+ } else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) {
iowrite32(1, hcr_base + CC);
- qc = ata_qc_from_tag(ap, link->active_tag);
+ qc = ata_qc_from_tag(ap, ATA_TAG_INTERNAL);
- DPRINTK("completing non-ncq cmd, tag=%d,CC=0x%x\n",
- link->active_tag, ioread32(hcr_base + CC));
+ DPRINTK("completing non-ncq cmd, CC=0x%x\n",
+ ioread32(hcr_base + CC));
- if (qc)
+ if (qc) {
ata_qc_complete(qc);
+ }
} else {
/* Spurious Interrupt!! */
DPRINTK("spurious interrupt!!, CC = 0x%x\n",
ioread32(hcr_base + CC));
+ iowrite32(qc_active, hcr_base + CC);
return;
}
}
@@ -1130,9 +1230,6 @@ static int sata_fsl_init_controller(struct ata_host *host)
iowrite32(0x00000FFFF, hcr_base + CE);
iowrite32(0x00000FFFF, hcr_base + DE);
- /* initially assuming no Port multiplier, set CQPMP to 0 */
- iowrite32(0x0, hcr_base + CQPMP);
-
/*
* host controller will be brought on-line, during xx_port_start()
* callback, that should also initiate the OOB, COMINIT sequence
@@ -1154,8 +1251,8 @@ static struct scsi_host_template sata_fsl_sht = {
.dma_boundary = ATA_DMA_BOUNDARY,
};
-static const struct ata_port_operations sata_fsl_ops = {
- .inherits = &sata_port_ops,
+static struct ata_port_operations sata_fsl_ops = {
+ .inherits = &sata_pmp_port_ops,
.qc_prep = sata_fsl_qc_prep,
.qc_issue = sata_fsl_qc_issue,
@@ -1168,10 +1265,15 @@ static const struct ata_port_operations sata_fsl_ops = {
.thaw = sata_fsl_thaw,
.prereset = sata_fsl_prereset,
.softreset = sata_fsl_softreset,
+ .pmp_softreset = sata_fsl_softreset,
+ .error_handler = sata_fsl_error_handler,
.post_internal_cmd = sata_fsl_post_internal_cmd,
.port_start = sata_fsl_port_start,
.port_stop = sata_fsl_port_stop,
+
+ .pmp_attach = sata_fsl_pmp_attach,
+ .pmp_detach = sata_fsl_pmp_detach,
};
static const struct ata_port_info sata_fsl_port_info[] = {
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index d27bb9a2568..3ead02fe379 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -10,13 +10,33 @@
* right. Documentation is available at initio's website but it only
* documents registers (not programming model).
*
- * - ATA disks work.
- * - Hotplug works.
- * - ATAPI read works but burning doesn't. This thing is really
- * peculiar about ATAPI and I couldn't figure out how ATAPI PIO and
- * ATAPI DMA WRITE should be programmed. If you've got a clue, be
- * my guest.
- * - Both STR and STD work.
+ * This driver has interesting history. The first version was written
+ * from the documentation and a 2.4 IDE driver posted on a Taiwan
+ * company, which didn't use any IDMA features and couldn't handle
+ * LBA48. The resulting driver couldn't handle LBA48 devices either
+ * making it pretty useless.
+ *
+ * After a while, initio picked the driver up, renamed it to
+ * sata_initio162x, updated it to use IDMA for ATA DMA commands and
+ * posted it on their website. It only used ATA_PROT_DMA for IDMA and
+ * attaching both devices and issuing IDMA and !IDMA commands
+ * simultaneously broke it due to PIRQ masking interaction but it did
+ * show how to use the IDMA (ADMA + some initio specific twists)
+ * engine.
+ *
+ * Then, I picked up their changes again and here's the usable driver
+ * which uses IDMA for everything. Everything works now including
+ * LBA48, CD/DVD burning, suspend/resume and hotplug. There are some
+ * issues tho. Result Tf is not resported properly, NCQ isn't
+ * supported yet and CD/DVD writing works with DMA assisted PIO
+ * protocol (which, for native SATA devices, shouldn't cause any
+ * noticeable difference).
+ *
+ * Anyways, so, here's finally a working driver for inic162x. Enjoy!
+ *
+ * initio: If you guys wanna improve the driver regarding result TF
+ * access and other stuff, please feel free to contact me. I'll be
+ * happy to assist.
*/
#include <linux/kernel.h>
@@ -28,13 +48,19 @@
#include <scsi/scsi_device.h>
#define DRV_NAME "sata_inic162x"
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.4"
enum {
- MMIO_BAR = 5,
+ MMIO_BAR_PCI = 5,
+ MMIO_BAR_CARDBUS = 1,
NR_PORTS = 2,
+ IDMA_CPB_TBL_SIZE = 4 * 32,
+
+ INIC_DMA_BOUNDARY = 0xffffff,
+
+ HOST_ACTRL = 0x08,
HOST_CTL = 0x7c,
HOST_STAT = 0x7e,
HOST_IRQ_STAT = 0xbc,
@@ -43,22 +69,37 @@ enum {
PORT_SIZE = 0x40,
/* registers for ATA TF operation */
- PORT_TF = 0x00,
- PORT_ALT_STAT = 0x08,
+ PORT_TF_DATA = 0x00,
+ PORT_TF_FEATURE = 0x01,
+ PORT_TF_NSECT = 0x02,
+ PORT_TF_LBAL = 0x03,
+ PORT_TF_LBAM = 0x04,
+ PORT_TF_LBAH = 0x05,
+ PORT_TF_DEVICE = 0x06,
+ PORT_TF_COMMAND = 0x07,
+ PORT_TF_ALT_STAT = 0x08,
PORT_IRQ_STAT = 0x09,
PORT_IRQ_MASK = 0x0a,
PORT_PRD_CTL = 0x0b,
PORT_PRD_ADDR = 0x0c,
PORT_PRD_XFERLEN = 0x10,
+ PORT_CPB_CPBLAR = 0x18,
+ PORT_CPB_PTQFIFO = 0x1c,
/* IDMA register */
PORT_IDMA_CTL = 0x14,
+ PORT_IDMA_STAT = 0x16,
+
+ PORT_RPQ_FIFO = 0x1e,
+ PORT_RPQ_CNT = 0x1f,
PORT_SCR = 0x20,
/* HOST_CTL bits */
HCTL_IRQOFF = (1 << 8), /* global IRQ off */
- HCTL_PWRDWN = (1 << 13), /* power down PHYs */
+ HCTL_FTHD0 = (1 << 10), /* fifo threshold 0 */
+ HCTL_FTHD1 = (1 << 11), /* fifo threshold 1*/
+ HCTL_PWRDWN = (1 << 12), /* power down PHYs */
HCTL_SOFTRST = (1 << 13), /* global reset (no phy reset) */
HCTL_RPGSEL = (1 << 15), /* register page select */
@@ -81,9 +122,7 @@ enum {
PIRQ_PENDING = (1 << 7), /* port IRQ pending (STAT only) */
PIRQ_ERR = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL,
-
- PIRQ_MASK_DMA_READ = PIRQ_REPLY | PIRQ_ATA,
- PIRQ_MASK_OTHER = PIRQ_REPLY | PIRQ_COMPLETE,
+ PIRQ_MASK_DEFAULT = PIRQ_REPLY | PIRQ_ATA,
PIRQ_MASK_FREEZE = 0xff,
/* PORT_PRD_CTL bits */
@@ -96,20 +135,104 @@ enum {
IDMA_CTL_RST_IDMA = (1 << 5), /* reset IDMA machinary */
IDMA_CTL_GO = (1 << 7), /* IDMA mode go */
IDMA_CTL_ATA_NIEN = (1 << 8), /* ATA IRQ disable */
+
+ /* PORT_IDMA_STAT bits */
+ IDMA_STAT_PERR = (1 << 0), /* PCI ERROR MODE */
+ IDMA_STAT_CPBERR = (1 << 1), /* ADMA CPB error */
+ IDMA_STAT_LGCY = (1 << 3), /* ADMA legacy */
+ IDMA_STAT_UIRQ = (1 << 4), /* ADMA unsolicited irq */
+ IDMA_STAT_STPD = (1 << 5), /* ADMA stopped */
+ IDMA_STAT_PSD = (1 << 6), /* ADMA pause */
+ IDMA_STAT_DONE = (1 << 7), /* ADMA done */
+
+ IDMA_STAT_ERR = IDMA_STAT_PERR | IDMA_STAT_CPBERR,
+
+ /* CPB Control Flags*/
+ CPB_CTL_VALID = (1 << 0), /* CPB valid */
+ CPB_CTL_QUEUED = (1 << 1), /* queued command */
+ CPB_CTL_DATA = (1 << 2), /* data, rsvd in datasheet */
+ CPB_CTL_IEN = (1 << 3), /* PCI interrupt enable */
+ CPB_CTL_DEVDIR = (1 << 4), /* device direction control */
+
+ /* CPB Response Flags */
+ CPB_RESP_DONE = (1 << 0), /* ATA command complete */
+ CPB_RESP_REL = (1 << 1), /* ATA release */
+ CPB_RESP_IGNORED = (1 << 2), /* CPB ignored */
+ CPB_RESP_ATA_ERR = (1 << 3), /* ATA command error */
+ CPB_RESP_SPURIOUS = (1 << 4), /* ATA spurious interrupt error */
+ CPB_RESP_UNDERFLOW = (1 << 5), /* APRD deficiency length error */
+ CPB_RESP_OVERFLOW = (1 << 6), /* APRD exccess length error */
+ CPB_RESP_CPB_ERR = (1 << 7), /* CPB error flag */
+
+ /* PRD Control Flags */
+ PRD_DRAIN = (1 << 1), /* ignore data excess */
+ PRD_CDB = (1 << 2), /* atapi packet command pointer */
+ PRD_DIRECT_INTR = (1 << 3), /* direct interrupt */
+ PRD_DMA = (1 << 4), /* data transfer method */
+ PRD_WRITE = (1 << 5), /* data dir, rsvd in datasheet */
+ PRD_IOM = (1 << 6), /* io/memory transfer */
+ PRD_END = (1 << 7), /* APRD chain end */
};
+/* Comman Parameter Block */
+struct inic_cpb {
+ u8 resp_flags; /* Response Flags */
+ u8 error; /* ATA Error */
+ u8 status; /* ATA Status */
+ u8 ctl_flags; /* Control Flags */
+ __le32 len; /* Total Transfer Length */
+ __le32 prd; /* First PRD pointer */
+ u8 rsvd[4];
+ /* 16 bytes */
+ u8 feature; /* ATA Feature */
+ u8 hob_feature; /* ATA Ex. Feature */
+ u8 device; /* ATA Device/Head */
+ u8 mirctl; /* Mirror Control */
+ u8 nsect; /* ATA Sector Count */
+ u8 hob_nsect; /* ATA Ex. Sector Count */
+ u8 lbal; /* ATA Sector Number */
+ u8 hob_lbal; /* ATA Ex. Sector Number */
+ u8 lbam; /* ATA Cylinder Low */
+ u8 hob_lbam; /* ATA Ex. Cylinder Low */
+ u8 lbah; /* ATA Cylinder High */
+ u8 hob_lbah; /* ATA Ex. Cylinder High */
+ u8 command; /* ATA Command */
+ u8 ctl; /* ATA Control */
+ u8 slave_error; /* Slave ATA Error */
+ u8 slave_status; /* Slave ATA Status */
+ /* 32 bytes */
+} __packed;
+
+/* Physical Region Descriptor */
+struct inic_prd {
+ __le32 mad; /* Physical Memory Address */
+ __le16 len; /* Transfer Length */
+ u8 rsvd;
+ u8 flags; /* Control Flags */
+} __packed;
+
+struct inic_pkt {
+ struct inic_cpb cpb;
+ struct inic_prd prd[LIBATA_MAX_PRD + 1]; /* + 1 for cdb */
+ u8 cdb[ATAPI_CDB_LEN];
+} __packed;
+
struct inic_host_priv {
- u16 cached_hctl;
+ void __iomem *mmio_base;
+ u16 cached_hctl;
};
struct inic_port_priv {
- u8 dfl_prdctl;
- u8 cached_prdctl;
- u8 cached_pirq_mask;
+ struct inic_pkt *pkt;
+ dma_addr_t pkt_dma;
+ u32 *cpb_tbl;
+ dma_addr_t cpb_tbl_dma;
};
static struct scsi_host_template inic_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
+ .sg_tablesize = LIBATA_MAX_PRD, /* maybe it can be larger? */
+ .dma_boundary = INIC_DMA_BOUNDARY,
};
static const int scr_map[] = {
@@ -120,54 +243,34 @@ static const int scr_map[] = {
static void __iomem *inic_port_base(struct ata_port *ap)
{
- return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
-}
-
-static void __inic_set_pirq_mask(struct ata_port *ap, u8 mask)
-{
- void __iomem *port_base = inic_port_base(ap);
- struct inic_port_priv *pp = ap->private_data;
+ struct inic_host_priv *hpriv = ap->host->private_data;
- writeb(mask, port_base + PORT_IRQ_MASK);
- pp->cached_pirq_mask = mask;
-}
-
-static void inic_set_pirq_mask(struct ata_port *ap, u8 mask)
-{
- struct inic_port_priv *pp = ap->private_data;
-
- if (pp->cached_pirq_mask != mask)
- __inic_set_pirq_mask(ap, mask);
+ return hpriv->mmio_base + ap->port_no * PORT_SIZE;
}
static void inic_reset_port(void __iomem *port_base)
{
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
- u16 ctl;
- ctl = readw(idma_ctl);
- ctl &= ~(IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN | IDMA_CTL_GO);
+ /* stop IDMA engine */
+ readw(idma_ctl); /* flush */
+ msleep(1);
/* mask IRQ and assert reset */
- writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(IDMA_CTL_RST_IDMA, idma_ctl);
readw(idma_ctl); /* flush */
-
- /* give it some time */
msleep(1);
/* release reset */
- writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(0, idma_ctl);
/* clear irq */
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- /* reenable ATA IRQ, turn off IDMA mode */
- writew(ctl, idma_ctl);
}
static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
+ void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
@@ -184,120 +287,126 @@ static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
- void __iomem *addr;
+ void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return -EINVAL;
- addr = scr_addr + scr_map[sc_reg] * 4;
writel(val, scr_addr + scr_map[sc_reg] * 4);
return 0;
}
-/*
- * In TF mode, inic162x is very similar to SFF device. TF registers
- * function the same. DMA engine behaves similary using the same PRD
- * format as BMDMA but different command register, interrupt and event
- * notification methods are used. The following inic_bmdma_*()
- * functions do the impedance matching.
- */
-static void inic_bmdma_setup(struct ata_queued_cmd *qc)
+static void inic_stop_idma(struct ata_port *ap)
{
- struct ata_port *ap = qc->ap;
- struct inic_port_priv *pp = ap->private_data;
void __iomem *port_base = inic_port_base(ap);
- int rw = qc->tf.flags & ATA_TFLAG_WRITE;
-
- /* make sure device sees PRD table writes */
- wmb();
-
- /* load transfer length */
- writel(qc->nbytes, port_base + PORT_PRD_XFERLEN);
-
- /* turn on DMA and specify data direction */
- pp->cached_prdctl = pp->dfl_prdctl | PRD_CTL_DMAEN;
- if (!rw)
- pp->cached_prdctl |= PRD_CTL_WR;
- writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
- /* issue r/w command */
- ap->ops->sff_exec_command(ap, &qc->tf);
+ readb(port_base + PORT_RPQ_FIFO);
+ readb(port_base + PORT_RPQ_CNT);
+ writew(0, port_base + PORT_IDMA_CTL);
}
-static void inic_bmdma_start(struct ata_queued_cmd *qc)
+static void inic_host_err_intr(struct ata_port *ap, u8 irq_stat, u16 idma_stat)
{
- struct ata_port *ap = qc->ap;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
+ struct inic_cpb *cpb = &pp->pkt->cpb;
+ bool freeze = false;
- /* start host DMA transaction */
- pp->cached_prdctl |= PRD_CTL_START;
- writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
-}
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat=0x%x idma_stat=0x%x",
+ irq_stat, idma_stat);
-static void inic_bmdma_stop(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
+ inic_stop_idma(ap);
- /* stop DMA engine */
- writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
-}
+ if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
+ ata_ehi_push_desc(ehi, "hotplug");
+ ata_ehi_hotplugged(ehi);
+ freeze = true;
+ }
-static u8 inic_bmdma_status(struct ata_port *ap)
-{
- /* event is already verified by the interrupt handler */
- return ATA_DMA_INTR;
+ if (idma_stat & IDMA_STAT_PERR) {
+ ata_ehi_push_desc(ehi, "PCI error");
+ freeze = true;
+ }
+
+ if (idma_stat & IDMA_STAT_CPBERR) {
+ ata_ehi_push_desc(ehi, "CPB error");
+
+ if (cpb->resp_flags & CPB_RESP_IGNORED) {
+ __ata_ehi_push_desc(ehi, " ignored");
+ ehi->err_mask |= AC_ERR_INVALID;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags & CPB_RESP_ATA_ERR)
+ ehi->err_mask |= AC_ERR_DEV;
+
+ if (cpb->resp_flags & CPB_RESP_SPURIOUS) {
+ __ata_ehi_push_desc(ehi, " spurious-intr");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags &
+ (CPB_RESP_UNDERFLOW | CPB_RESP_OVERFLOW)) {
+ __ata_ehi_push_desc(ehi, " data-over/underflow");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+ }
+
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
}
static void inic_host_intr(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
u8 irq_stat;
+ u16 idma_stat;
- /* fetch and clear irq */
+ /* read and clear IRQ status */
irq_stat = readb(port_base + PORT_IRQ_STAT);
writeb(irq_stat, port_base + PORT_IRQ_STAT);
+ idma_stat = readw(port_base + PORT_IDMA_STAT);
- if (likely(!(irq_stat & PIRQ_ERR))) {
- struct ata_queued_cmd *qc =
- ata_qc_from_tag(ap, ap->link.active_tag);
+ if (unlikely((irq_stat & PIRQ_ERR) || (idma_stat & IDMA_STAT_ERR)))
+ inic_host_err_intr(ap, irq_stat, idma_stat);
- if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
- return;
- }
+ if (unlikely(!qc))
+ goto spurious;
- if (likely(ata_sff_host_intr(ap, qc)))
- return;
+ if (likely(idma_stat & IDMA_STAT_DONE)) {
+ inic_stop_idma(ap);
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
- ata_port_printk(ap, KERN_WARNING, "unhandled "
- "interrupt, irq_stat=%x\n", irq_stat);
+ /* Depending on circumstances, device error
+ * isn't reported by IDMA, check it explicitly.
+ */
+ if (unlikely(readb(port_base + PORT_TF_COMMAND) &
+ (ATA_DF | ATA_ERR)))
+ qc->err_mask |= AC_ERR_DEV;
+
+ ata_qc_complete(qc);
return;
}
- /* error */
- ata_ehi_push_desc(ehi, "irq_stat=0x%x", irq_stat);
-
- if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
- ata_ehi_hotplugged(ehi);
- ata_port_freeze(ap);
- } else
- ata_port_abort(ap);
+ spurious:
+ ata_port_printk(ap, KERN_WARNING, "unhandled interrupt: "
+ "cmd=0x%x irq_stat=0x%x idma_stat=0x%x\n",
+ qc ? qc->tf.command : 0xff, irq_stat, idma_stat);
}
static irqreturn_t inic_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
- void __iomem *mmio_base = host->iomap[MMIO_BAR];
+ struct inic_host_priv *hpriv = host->private_data;
u16 host_irq_stat;
int i, handled = 0;;
- host_irq_stat = readw(mmio_base + HOST_IRQ_STAT);
+ host_irq_stat = readw(hpriv->mmio_base + HOST_IRQ_STAT);
if (unlikely(!(host_irq_stat & HIRQ_GLOBAL)))
goto out;
@@ -327,60 +436,173 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
+static int inic_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ /* For some reason ATAPI_PROT_DMA doesn't work for some
+ * commands including writes and other misc ops. Use PIO
+ * protocol instead, which BTW is driven by the DMA engine
+ * anyway, so it shouldn't make much difference for native
+ * SATA devices.
+ */
+ if (atapi_cmd_type(qc->cdb[0]) == READ)
+ return 0;
+ return 1;
+}
+
+static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg;
+ unsigned int si;
+ u8 flags = 0;
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ flags |= PRD_WRITE;
+
+ if (ata_is_dma(qc->tf.protocol))
+ flags |= PRD_DMA;
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ prd->mad = cpu_to_le32(sg_dma_address(sg));
+ prd->len = cpu_to_le16(sg_dma_len(sg));
+ prd->flags = flags;
+ prd++;
+ }
+
+ WARN_ON(!si);
+ prd[-1].flags |= PRD_END;
+}
+
+static void inic_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct inic_port_priv *pp = qc->ap->private_data;
+ struct inic_pkt *pkt = pp->pkt;
+ struct inic_cpb *cpb = &pkt->cpb;
+ struct inic_prd *prd = pkt->prd;
+ bool is_atapi = ata_is_atapi(qc->tf.protocol);
+ bool is_data = ata_is_data(qc->tf.protocol);
+ unsigned int cdb_len = 0;
+
+ VPRINTK("ENTER\n");
+
+ if (is_atapi)
+ cdb_len = qc->dev->cdb_len;
+
+ /* prepare packet, based on initio driver */
+ memset(pkt, 0, sizeof(struct inic_pkt));
+
+ cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN;
+ if (is_atapi || is_data)
+ cpb->ctl_flags |= CPB_CTL_DATA;
+
+ cpb->len = cpu_to_le32(qc->nbytes + cdb_len);
+ cpb->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd));
+
+ cpb->device = qc->tf.device;
+ cpb->feature = qc->tf.feature;
+ cpb->nsect = qc->tf.nsect;
+ cpb->lbal = qc->tf.lbal;
+ cpb->lbam = qc->tf.lbam;
+ cpb->lbah = qc->tf.lbah;
+
+ if (qc->tf.flags & ATA_TFLAG_LBA48) {
+ cpb->hob_feature = qc->tf.hob_feature;
+ cpb->hob_nsect = qc->tf.hob_nsect;
+ cpb->hob_lbal = qc->tf.hob_lbal;
+ cpb->hob_lbam = qc->tf.hob_lbam;
+ cpb->hob_lbah = qc->tf.hob_lbah;
+ }
+
+ cpb->command = qc->tf.command;
+ /* don't load ctl - dunno why. it's like that in the initio driver */
+
+ /* setup PRD for CDB */
+ if (is_atapi) {
+ memcpy(pkt->cdb, qc->cdb, ATAPI_CDB_LEN);
+ prd->mad = cpu_to_le32(pp->pkt_dma +
+ offsetof(struct inic_pkt, cdb));
+ prd->len = cpu_to_le16(cdb_len);
+ prd->flags = PRD_CDB | PRD_WRITE;
+ if (!is_data)
+ prd->flags |= PRD_END;
+ prd++;
+ }
+
+ /* setup sg table */
+ if (is_data)
+ inic_fill_sg(prd, qc);
+
+ pp->cpb_tbl[0] = pp->pkt_dma;
+}
+
static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ void __iomem *port_base = inic_port_base(ap);
- /* ATA IRQ doesn't wait for DMA transfer completion and vice
- * versa. Mask IRQ selectively to detect command completion.
- * Without it, ATA DMA read command can cause data corruption.
- *
- * Something similar might be needed for ATAPI writes. I
- * tried a lot of combinations but couldn't find the solution.
- */
- if (qc->tf.protocol == ATA_PROT_DMA &&
- !(qc->tf.flags & ATA_TFLAG_WRITE))
- inic_set_pirq_mask(ap, PIRQ_MASK_DMA_READ);
- else
- inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+ /* fire up the ADMA engine */
+ writew(HCTL_FTHD0, port_base + HOST_CTL);
+ writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
+ writeb(0, port_base + PORT_CPB_PTQFIFO);
+
+ return 0;
+}
+
+static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ tf->feature = readb(port_base + PORT_TF_FEATURE);
+ tf->nsect = readb(port_base + PORT_TF_NSECT);
+ tf->lbal = readb(port_base + PORT_TF_LBAL);
+ tf->lbam = readb(port_base + PORT_TF_LBAM);
+ tf->lbah = readb(port_base + PORT_TF_LBAH);
+ tf->device = readb(port_base + PORT_TF_DEVICE);
+ tf->command = readb(port_base + PORT_TF_COMMAND);
+}
- /* Issuing a command to yet uninitialized port locks up the
- * controller. Most of the time, this happens for the first
- * command after reset which are ATA and ATAPI IDENTIFYs.
- * Fast fail if stat is 0x7f or 0xff for those commands.
+static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *rtf = &qc->result_tf;
+ struct ata_taskfile tf;
+
+ /* FIXME: Except for status and error, result TF access
+ * doesn't work. I tried reading from BAR0/2, CPB and BAR5.
+ * None works regardless of which command interface is used.
+ * For now return true iff status indicates device error.
+ * This means that we're reporting bogus sector for RW
+ * failures. Eeekk....
*/
- if (unlikely(qc->tf.command == ATA_CMD_ID_ATA ||
- qc->tf.command == ATA_CMD_ID_ATAPI)) {
- u8 stat = ap->ops->sff_check_status(ap);
- if (stat == 0x7f || stat == 0xff)
- return AC_ERR_HSM;
- }
+ inic_tf_read(qc->ap, &tf);
- return ata_sff_qc_issue(qc);
+ if (!(tf.command & ATA_ERR))
+ return false;
+
+ rtf->command = tf.command;
+ rtf->feature = tf.feature;
+ return true;
}
static void inic_freeze(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE);
-
- ap->ops->sff_check_status(ap);
+ writeb(PIRQ_MASK_FREEZE, port_base + PORT_IRQ_MASK);
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- readb(port_base + PORT_IRQ_STAT); /* flush */
}
static void inic_thaw(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- ap->ops->sff_check_status(ap);
writeb(0xff, port_base + PORT_IRQ_STAT);
+ writeb(PIRQ_MASK_DEFAULT, port_base + PORT_IRQ_MASK);
+}
- __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+static int inic_check_ready(struct ata_link *link)
+{
+ void __iomem *port_base = inic_port_base(link->ap);
- readb(port_base + PORT_IRQ_STAT); /* flush */
+ return ata_check_ready(readb(port_base + PORT_TF_COMMAND));
}
/*
@@ -394,17 +616,15 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
void __iomem *port_base = inic_port_base(ap);
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
- u16 val;
int rc;
/* hammer it into sane state */
inic_reset_port(port_base);
- val = readw(idma_ctl);
- writew(val | IDMA_CTL_RST_ATA, idma_ctl);
+ writew(IDMA_CTL_RST_ATA, idma_ctl);
readw(idma_ctl); /* flush */
msleep(1);
- writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
+ writew(0, idma_ctl);
rc = sata_link_resume(link, timing, deadline);
if (rc) {
@@ -418,7 +638,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
struct ata_taskfile tf;
/* wait for link to become ready */
- rc = ata_sff_wait_after_reset(link, 1, deadline);
+ rc = ata_wait_after_reset(link, deadline, inic_check_ready);
/* link occupied, -ENODEV too is an error */
if (rc) {
ata_link_printk(link, KERN_WARNING, "device not ready "
@@ -426,7 +646,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
return rc;
}
- ata_sff_tf_read(ap, &tf);
+ inic_tf_read(ap, &tf);
*class = ata_dev_classify(&tf);
}
@@ -436,18 +656,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
static void inic_error_handler(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct inic_port_priv *pp = ap->private_data;
- unsigned long flags;
- /* reset PIO HSM and stop DMA engine */
inic_reset_port(port_base);
-
- spin_lock_irqsave(ap->lock, flags);
- ap->hsm_task_state = HSM_ST_IDLE;
- writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* PIO and DMA engines have been stopped, perform recovery */
ata_std_error_handler(ap);
}
@@ -458,26 +668,18 @@ static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
inic_reset_port(inic_port_base(qc->ap));
}
-static void inic_dev_config(struct ata_device *dev)
-{
- /* inic can only handle upto LBA28 max sectors */
- if (dev->max_sectors > ATA_MAX_SECTORS)
- dev->max_sectors = ATA_MAX_SECTORS;
-
- if (dev->n_sectors >= 1 << 28) {
- ata_dev_printk(dev, KERN_ERR,
- "ERROR: This driver doesn't support LBA48 yet and may cause\n"
- " data corruption on such devices. Disabling.\n");
- ata_dev_disable(dev);
- }
-}
-
static void init_port(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp = ap->private_data;
- /* Setup PRD address */
+ /* clear packet and CPB table */
+ memset(pp->pkt, 0, sizeof(struct inic_pkt));
+ memset(pp->cpb_tbl, 0, IDMA_CPB_TBL_SIZE);
+
+ /* setup PRD and CPB lookup table addresses */
writel(ap->prd_dma, port_base + PORT_PRD_ADDR);
+ writel(pp->cpb_tbl_dma, port_base + PORT_CPB_CPBLAR);
}
static int inic_port_resume(struct ata_port *ap)
@@ -488,28 +690,30 @@ static int inic_port_resume(struct ata_port *ap)
static int inic_port_start(struct ata_port *ap)
{
- void __iomem *port_base = inic_port_base(ap);
+ struct device *dev = ap->host->dev;
struct inic_port_priv *pp;
- u8 tmp;
int rc;
/* alloc and initialize private data */
- pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
ap->private_data = pp;
- /* default PRD_CTL value, DMAEN, WR and START off */
- tmp = readb(port_base + PORT_PRD_CTL);
- tmp &= ~(PRD_CTL_DMAEN | PRD_CTL_WR | PRD_CTL_START);
- pp->dfl_prdctl = tmp;
-
/* Alloc resources */
rc = ata_port_start(ap);
- if (rc) {
- kfree(pp);
+ if (rc)
return rc;
- }
+
+ pp->pkt = dmam_alloc_coherent(dev, sizeof(struct inic_pkt),
+ &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
+
+ pp->cpb_tbl = dmam_alloc_coherent(dev, IDMA_CPB_TBL_SIZE,
+ &pp->cpb_tbl_dma, GFP_KERNEL);
+ if (!pp->cpb_tbl)
+ return -ENOMEM;
init_port(ap);
@@ -517,21 +721,18 @@ static int inic_port_start(struct ata_port *ap)
}
static struct ata_port_operations inic_port_ops = {
- .inherits = &ata_sff_port_ops,
+ .inherits = &sata_port_ops,
- .bmdma_setup = inic_bmdma_setup,
- .bmdma_start = inic_bmdma_start,
- .bmdma_stop = inic_bmdma_stop,
- .bmdma_status = inic_bmdma_status,
+ .check_atapi_dma = inic_check_atapi_dma,
+ .qc_prep = inic_qc_prep,
.qc_issue = inic_qc_issue,
+ .qc_fill_rtf = inic_qc_fill_rtf,
.freeze = inic_freeze,
.thaw = inic_thaw,
- .softreset = ATA_OP_NULL, /* softreset is broken */
.hardreset = inic_hardreset,
.error_handler = inic_error_handler,
.post_internal_cmd = inic_post_internal_cmd,
- .dev_config = inic_dev_config,
.scr_read = inic_scr_read,
.scr_write = inic_scr_write,
@@ -541,12 +742,6 @@ static struct ata_port_operations inic_port_ops = {
};
static struct ata_port_info inic_port_info = {
- /* For some reason, ATAPI_PROT_PIO is broken on this
- * controller, and no, PIO_POLLING does't fix it. It somehow
- * manages to report the wrong ireason and ignoring ireason
- * results in machine lock up. Tell libata to always prefer
- * DMA.
- */
.flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -599,7 +794,6 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct inic_host_priv *hpriv = host->private_data;
- void __iomem *mmio_base = host->iomap[MMIO_BAR];
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -607,7 +801,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- rc = init_controller(mmio_base, hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc)
return rc;
}
@@ -625,6 +819,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_host *host;
struct inic_host_priv *hpriv;
void __iomem * const *iomap;
+ int mmio_bar;
int i, rc;
if (!printed_version++)
@@ -638,38 +833,31 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->private_data = hpriv;
- /* acquire resources and fill host */
+ /* Acquire resources and fill host. Note that PCI and cardbus
+ * use different BARs.
+ */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
+ if (pci_resource_flags(pdev, MMIO_BAR_PCI) & IORESOURCE_MEM)
+ mmio_bar = MMIO_BAR_PCI;
+ else
+ mmio_bar = MMIO_BAR_CARDBUS;
+
+ rc = pcim_iomap_regions(pdev, 1 << mmio_bar, DRV_NAME);
if (rc)
return rc;
host->iomap = iomap = pcim_iomap_table(pdev);
+ hpriv->mmio_base = iomap[mmio_bar];
+ hpriv->cached_hctl = readw(hpriv->mmio_base + HOST_CTL);
for (i = 0; i < NR_PORTS; i++) {
struct ata_port *ap = host->ports[i];
- struct ata_ioports *port = &ap->ioaddr;
- unsigned int offset = i * PORT_SIZE;
-
- port->cmd_addr = iomap[2 * i];
- port->altstatus_addr =
- port->ctl_addr = (void __iomem *)
- ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
- port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
-
- ata_sff_std_ports(port);
-
- ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
- ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
- (unsigned long long)pci_resource_start(pdev, 2 * i),
- (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
- ATA_PCI_CTL_OFS);
- }
- hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
+ ata_port_pbar_desc(ap, mmio_bar, -1, "mmio");
+ ata_port_pbar_desc(ap, mmio_bar, i * PORT_SIZE, "port");
+ }
/* Set dma_mask. This devices doesn't support 64bit addressing. */
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
@@ -698,7 +886,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
- rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"failed to initialize controller\n");
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 842b1a15b78..ad169ffbc4c 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -65,13 +65,14 @@
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/mbus.h>
+#include <linux/bitops.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <linux/libata.h>
#define DRV_NAME "sata_mv"
-#define DRV_VERSION "1.20"
+#define DRV_VERSION "1.24"
enum {
/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -91,9 +92,9 @@ enum {
MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
MV_SATAHC0_REG_BASE = 0x20000,
- MV_FLASH_CTL = 0x1046c,
- MV_GPIO_PORT_CTL = 0x104f0,
- MV_RESET_CFG = 0x180d8,
+ MV_FLASH_CTL_OFS = 0x1046c,
+ MV_GPIO_PORT_CTL_OFS = 0x104f0,
+ MV_RESET_CFG_OFS = 0x180d8,
MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
@@ -121,14 +122,17 @@ enum {
/* Host Flags */
MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
- /* SoC integrated controllers, no PCI interface */
- MV_FLAG_SOC = (1 << 28),
MV_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
ATA_FLAG_PIO_POLLING,
+
MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
+ MV_GENIIE_FLAGS = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
+ ATA_FLAG_NCQ | ATA_FLAG_AN,
+
CRQB_FLAG_READ = (1 << 0),
CRQB_TAG_SHIFT = 1,
CRQB_IOID_SHIFT = 6, /* CRQB Gen-II/IIE IO Id shift */
@@ -147,18 +151,21 @@ enum {
/* PCI interface registers */
PCI_COMMAND_OFS = 0xc00,
+ PCI_COMMAND_MRDTRIG = (1 << 7), /* PCI Master Read Trigger */
PCI_MAIN_CMD_STS_OFS = 0xd30,
STOP_PCI_MASTER = (1 << 2),
PCI_MASTER_EMPTY = (1 << 3),
GLOB_SFT_RST = (1 << 4),
- MV_PCI_MODE = 0xd00,
+ MV_PCI_MODE_OFS = 0xd00,
+ MV_PCI_MODE_MASK = 0x30,
+
MV_PCI_EXP_ROM_BAR_CTL = 0xd2c,
MV_PCI_DISC_TIMER = 0xd04,
MV_PCI_MSI_TRIGGER = 0xc38,
MV_PCI_SERR_MASK = 0xc28,
- MV_PCI_XBAR_TMOUT = 0x1d04,
+ MV_PCI_XBAR_TMOUT_OFS = 0x1d04,
MV_PCI_ERR_LOW_ADDRESS = 0x1d40,
MV_PCI_ERR_HIGH_ADDRESS = 0x1d44,
MV_PCI_ERR_ATTRIBUTE = 0x1d48,
@@ -193,13 +200,6 @@ enum {
HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */
HC_MAIN_RSVD_SOC = (0x3fffffb << 6), /* bits 31-9, 7-6 */
- HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
- PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
- PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
- HC_MAIN_RSVD),
- HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
- HC_MAIN_RSVD_5),
- HC_MAIN_MASKED_IRQS_SOC = (PORTS_0_3_COAL_DONE | HC_MAIN_RSVD_SOC),
/* SATAHC registers */
HC_CFG_OFS = 0,
@@ -217,24 +217,32 @@ enum {
SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
SATA_ACTIVE_OFS = 0x350,
SATA_FIS_IRQ_CAUSE_OFS = 0x364,
+ SATA_FIS_IRQ_AN = (1 << 9), /* async notification */
LTMODE_OFS = 0x30c,
LTMODE_BIT8 = (1 << 8), /* unknown, but necessary */
PHY_MODE3 = 0x310,
PHY_MODE4 = 0x314,
+ PHY_MODE4_CFG_MASK = 0x00000003, /* phy internal config field */
+ PHY_MODE4_CFG_VALUE = 0x00000001, /* phy internal config field */
+ PHY_MODE4_RSVD_ZEROS = 0x5de3fffa, /* Gen2e always write zeros */
+ PHY_MODE4_RSVD_ONES = 0x00000005, /* Gen2e always write ones */
+
PHY_MODE2 = 0x330,
SATA_IFCTL_OFS = 0x344,
+ SATA_TESTCTL_OFS = 0x348,
SATA_IFSTAT_OFS = 0x34c,
VENDOR_UNIQUE_FIS_OFS = 0x35c,
- FIS_CFG_OFS = 0x360,
- FIS_CFG_SINGLE_SYNC = (1 << 16), /* SYNC on DMA activation */
+ FISCFG_OFS = 0x360,
+ FISCFG_WAIT_DEV_ERR = (1 << 8), /* wait for host on DevErr */
+ FISCFG_SINGLE_SYNC = (1 << 16), /* SYNC on DMA activation */
MV5_PHY_MODE = 0x74,
- MV5_LT_MODE = 0x30,
- MV5_PHY_CTL = 0x0C,
- SATA_INTERFACE_CFG = 0x050,
+ MV5_LTMODE_OFS = 0x30,
+ MV5_PHY_CTL_OFS = 0x0C,
+ SATA_INTERFACE_CFG_OFS = 0x050,
MV_M2_PREAMP_MASK = 0x7e0,
@@ -332,10 +340,16 @@ enum {
EDMA_CMD_OFS = 0x28, /* EDMA command register */
EDMA_EN = (1 << 0), /* enable EDMA */
EDMA_DS = (1 << 1), /* disable EDMA; self-negated */
- ATA_RST = (1 << 2), /* reset trans/link/phy */
+ EDMA_RESET = (1 << 2), /* reset eng/trans/link/phy */
- EDMA_IORDY_TMOUT = 0x34,
- EDMA_ARB_CFG = 0x38,
+ EDMA_STATUS_OFS = 0x30, /* EDMA engine status */
+ EDMA_STATUS_CACHE_EMPTY = (1 << 6), /* GenIIe command cache empty */
+ EDMA_STATUS_IDLE = (1 << 7), /* GenIIe EDMA enabled/idle */
+
+ EDMA_IORDY_TMOUT_OFS = 0x34,
+ EDMA_ARB_CFG_OFS = 0x38,
+
+ EDMA_HALTCOND_OFS = 0x60, /* GenIIe halt conditions */
GEN_II_NCQ_MAX_SECTORS = 256, /* max sects/io on Gen2 w/NCQ */
@@ -345,21 +359,25 @@ enum {
MV_HP_ERRATA_50XXB2 = (1 << 2),
MV_HP_ERRATA_60X1B2 = (1 << 3),
MV_HP_ERRATA_60X1C0 = (1 << 4),
- MV_HP_ERRATA_XX42A0 = (1 << 5),
MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */
MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */
+ MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */
+ MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */
/* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
MV_PP_FLAG_NCQ_EN = (1 << 1), /* is EDMA set up for NCQ? */
+ MV_PP_FLAG_FBS_EN = (1 << 2), /* is EDMA set up for FBS? */
+ MV_PP_FLAG_DELAYED_EH = (1 << 3), /* delayed dev err handling */
};
#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
-#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
+#define IS_PCIE(hpriv) ((hpriv)->hp_flags & MV_HP_PCIE)
+#define IS_SOC(hpriv) ((hpriv)->hp_flags & MV_HP_FLAG_SOC)
#define WINDOW_CTRL(i) (0x20030 + ((i) << 4))
#define WINDOW_BASE(i) (0x20034 + ((i) << 4))
@@ -433,6 +451,7 @@ struct mv_port_priv {
unsigned int resp_idx;
u32 pp_flags;
+ unsigned int delayed_eh_pmp_map;
};
struct mv_port_signal {
@@ -442,6 +461,7 @@ struct mv_port_signal {
struct mv_host_priv {
u32 hp_flags;
+ u32 main_irq_mask;
struct mv_port_signal signal[8];
const struct mv_hw_ops *ops;
int n_ports;
@@ -479,6 +499,7 @@ static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
+static int mv_qc_defer(struct ata_queued_cmd *qc);
static void mv_qc_prep(struct ata_queued_cmd *qc);
static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
@@ -527,6 +548,9 @@ static int mv_pmp_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int mv_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
+static void mv_pmp_error_handler(struct ata_port *ap);
+static void mv_process_crpb_entries(struct ata_port *ap,
+ struct mv_port_priv *pp);
/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
* because we have to allow room for worst case splitting of
@@ -548,6 +572,7 @@ static struct scsi_host_template mv6_sht = {
static struct ata_port_operations mv5_ops = {
.inherits = &ata_sff_port_ops,
+ .qc_defer = mv_qc_defer,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
@@ -566,7 +591,6 @@ static struct ata_port_operations mv5_ops = {
static struct ata_port_operations mv6_ops = {
.inherits = &mv5_ops,
- .qc_defer = sata_pmp_qc_defer_cmd_switch,
.dev_config = mv6_dev_config,
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
@@ -574,12 +598,11 @@ static struct ata_port_operations mv6_ops = {
.pmp_hardreset = mv_pmp_hardreset,
.pmp_softreset = mv_softreset,
.softreset = mv_softreset,
- .error_handler = sata_pmp_error_handler,
+ .error_handler = mv_pmp_error_handler,
};
static struct ata_port_operations mv_iie_ops = {
.inherits = &mv6_ops,
- .qc_defer = ata_std_qc_defer, /* FIS-based switching */
.dev_config = ATA_OP_NULL,
.qc_prep = mv_qc_prep_iie,
};
@@ -620,25 +643,19 @@ static const struct ata_port_info mv_port_info[] = {
.port_ops = &mv6_ops,
},
{ /* chip_6042 */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ,
+ .flags = MV_GENIIE_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
{ /* chip_7042 */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ,
+ .flags = MV_GENIIE_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
{ /* chip_soc */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ | MV_FLAG_SOC,
+ .flags = MV_GENIIE_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
@@ -798,12 +815,7 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index,
port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
-
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl((pp->crqb_dma & 0xffffffff) | index,
- port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
- else
- writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+ writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
/*
* initialize response queue
@@ -813,17 +825,38 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
WARN_ON(pp->crpb_dma & 0xff);
writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
-
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl((pp->crpb_dma & 0xffffffff) | index,
- port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
- else
- writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
-
+ writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
}
+static void mv_set_main_irq_mask(struct ata_host *host,
+ u32 disable_bits, u32 enable_bits)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ u32 old_mask, new_mask;
+
+ old_mask = hpriv->main_irq_mask;
+ new_mask = (old_mask & ~disable_bits) | enable_bits;
+ if (new_mask != old_mask) {
+ hpriv->main_irq_mask = new_mask;
+ writelfl(new_mask, hpriv->main_irq_mask_addr);
+ }
+}
+
+static void mv_enable_port_irqs(struct ata_port *ap,
+ unsigned int port_bits)
+{
+ unsigned int shift, hardport, port = ap->port_no;
+ u32 disable_bits, enable_bits;
+
+ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
+
+ disable_bits = (DONE_IRQ | ERR_IRQ) << shift;
+ enable_bits = port_bits << shift;
+ mv_set_main_irq_mask(ap->host, disable_bits, enable_bits);
+}
+
/**
* mv_start_dma - Enable eDMA engine
* @base: port base address
@@ -866,15 +899,40 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
mv_edma_cfg(ap, want_ncq);
/* clear FIS IRQ Cause */
- writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+ if (IS_GEN_IIE(hpriv))
+ writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
mv_set_edma_ptrs(port_mmio, hpriv, pp);
+ mv_enable_port_irqs(ap, DONE_IRQ|ERR_IRQ);
writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS);
pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
}
}
+static void mv_wait_for_edma_empty_idle(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ const u32 empty_idle = (EDMA_STATUS_CACHE_EMPTY | EDMA_STATUS_IDLE);
+ const int per_loop = 5, timeout = (15 * 1000 / per_loop);
+ int i;
+
+ /*
+ * Wait for the EDMA engine to finish transactions in progress.
+ * No idea what a good "timeout" value might be, but measurements
+ * indicate that it often requires hundreds of microseconds
+ * with two drives in-use. So we use the 15msec value above
+ * as a rough guess at what even more drives might require.
+ */
+ for (i = 0; i < timeout; ++i) {
+ u32 edma_stat = readl(port_mmio + EDMA_STATUS_OFS);
+ if ((edma_stat & empty_idle) == empty_idle)
+ break;
+ udelay(per_loop);
+ }
+ /* ata_port_printk(ap, KERN_INFO, "%s: %u+ usecs\n", __func__, i); */
+}
+
/**
* mv_stop_edma_engine - Disable eDMA engine
* @port_mmio: io base address
@@ -907,6 +965,7 @@ static int mv_stop_edma(struct ata_port *ap)
if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))
return 0;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ mv_wait_for_edma_empty_idle(ap);
if (mv_stop_edma_engine(port_mmio)) {
ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
return -EIO;
@@ -1057,26 +1116,95 @@ static void mv6_dev_config(struct ata_device *adev)
}
}
-static void mv_config_fbs(void __iomem *port_mmio, int enable_fbs)
+static int mv_qc_defer(struct ata_queued_cmd *qc)
{
- u32 old_fcfg, new_fcfg, old_ltmode, new_ltmode;
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+ struct mv_port_priv *pp = ap->private_data;
+
/*
- * Various bit settings required for operation
- * in FIS-based switching (fbs) mode on GenIIe:
+ * Don't allow new commands if we're in a delayed EH state
+ * for NCQ and/or FIS-based switching.
*/
- old_fcfg = readl(port_mmio + FIS_CFG_OFS);
- old_ltmode = readl(port_mmio + LTMODE_OFS);
- if (enable_fbs) {
- new_fcfg = old_fcfg | FIS_CFG_SINGLE_SYNC;
- new_ltmode = old_ltmode | LTMODE_BIT8;
- } else { /* disable fbs */
- new_fcfg = old_fcfg & ~FIS_CFG_SINGLE_SYNC;
- new_ltmode = old_ltmode & ~LTMODE_BIT8;
- }
- if (new_fcfg != old_fcfg)
- writelfl(new_fcfg, port_mmio + FIS_CFG_OFS);
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
+ return ATA_DEFER_PORT;
+ /*
+ * If the port is completely idle, then allow the new qc.
+ */
+ if (ap->nr_active_links == 0)
+ return 0;
+
+ if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
+ /*
+ * The port is operating in host queuing mode (EDMA).
+ * It can accomodate a new qc if the qc protocol
+ * is compatible with the current host queue mode.
+ */
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN) {
+ /*
+ * The host queue (EDMA) is in NCQ mode.
+ * If the new qc is also an NCQ command,
+ * then allow the new qc.
+ */
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ return 0;
+ } else {
+ /*
+ * The host queue (EDMA) is in non-NCQ, DMA mode.
+ * If the new qc is also a non-NCQ, DMA command,
+ * then allow the new qc.
+ */
+ if (qc->tf.protocol == ATA_PROT_DMA)
+ return 0;
+ }
+ }
+ return ATA_DEFER_PORT;
+}
+
+static void mv_config_fbs(void __iomem *port_mmio, int want_ncq, int want_fbs)
+{
+ u32 new_fiscfg, old_fiscfg;
+ u32 new_ltmode, old_ltmode;
+ u32 new_haltcond, old_haltcond;
+
+ old_fiscfg = readl(port_mmio + FISCFG_OFS);
+ old_ltmode = readl(port_mmio + LTMODE_OFS);
+ old_haltcond = readl(port_mmio + EDMA_HALTCOND_OFS);
+
+ new_fiscfg = old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR);
+ new_ltmode = old_ltmode & ~LTMODE_BIT8;
+ new_haltcond = old_haltcond | EDMA_ERR_DEV;
+
+ if (want_fbs) {
+ new_fiscfg = old_fiscfg | FISCFG_SINGLE_SYNC;
+ new_ltmode = old_ltmode | LTMODE_BIT8;
+ if (want_ncq)
+ new_haltcond &= ~EDMA_ERR_DEV;
+ else
+ new_fiscfg |= FISCFG_WAIT_DEV_ERR;
+ }
+
+ if (new_fiscfg != old_fiscfg)
+ writelfl(new_fiscfg, port_mmio + FISCFG_OFS);
if (new_ltmode != old_ltmode)
writelfl(new_ltmode, port_mmio + LTMODE_OFS);
+ if (new_haltcond != old_haltcond)
+ writelfl(new_haltcond, port_mmio + EDMA_HALTCOND_OFS);
+}
+
+static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq)
+{
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ u32 old, new;
+
+ /* workaround for 88SX60x1 FEr SATA#25 (part 1) */
+ old = readl(hpriv->base + MV_GPIO_PORT_CTL_OFS);
+ if (want_ncq)
+ new = old | (1 << 22);
+ else
+ new = old & ~(1 << 22);
+ if (new != old)
+ writel(new, hpriv->base + MV_GPIO_PORT_CTL_OFS);
}
static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
@@ -1088,25 +1216,40 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
/* set up non-NCQ EDMA configuration */
cfg = EDMA_CFG_Q_DEPTH; /* always 0x1f for *all* chips */
+ pp->pp_flags &= ~MV_PP_FLAG_FBS_EN;
if (IS_GEN_I(hpriv))
cfg |= (1 << 8); /* enab config burst size mask */
- else if (IS_GEN_II(hpriv))
+ else if (IS_GEN_II(hpriv)) {
cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+ mv_60x1_errata_sata25(ap, want_ncq);
- else if (IS_GEN_IIE(hpriv)) {
- cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
- cfg |= (1 << 22); /* enab 4-entry host queue cache */
- cfg |= (1 << 18); /* enab early completion */
- cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */
+ } else if (IS_GEN_IIE(hpriv)) {
+ int want_fbs = sata_pmp_attached(ap);
+ /*
+ * Possible future enhancement:
+ *
+ * The chip can use FBS with non-NCQ, if we allow it,
+ * But first we need to have the error handling in place
+ * for this mode (datasheet section 7.3.15.4.2.3).
+ * So disallow non-NCQ FBS for now.
+ */
+ want_fbs &= want_ncq;
+
+ mv_config_fbs(port_mmio, want_ncq, want_fbs);
- if (want_ncq && sata_pmp_attached(ap)) {
+ if (want_fbs) {
+ pp->pp_flags |= MV_PP_FLAG_FBS_EN;
cfg |= EDMA_CFG_EDMA_FBS; /* FIS-based switching */
- mv_config_fbs(port_mmio, 1);
- } else {
- mv_config_fbs(port_mmio, 0);
}
+
+ cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
+ cfg |= (1 << 22); /* enab 4-entry host queue cache */
+ if (!IS_SOC(hpriv))
+ cfg |= (1 << 18); /* enab early completion */
+ if (hpriv->hp_flags & MV_HP_CUT_THROUGH)
+ cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */
}
if (want_ncq) {
@@ -1179,6 +1322,9 @@ static int mv_port_start(struct ata_port *ap)
goto out_port_free_dma_mem;
memset(pp->crpb, 0, MV_CRPB_Q_SZ);
+ /* 6041/6081 Rev. "C0" (and newer) are okay with async notify */
+ if (hpriv->hp_flags & MV_HP_ERRATA_60X1C0)
+ ap->flags |= ATA_FLAG_AN;
/*
* For GEN_I, there's no NCQ, so we only allocate a single sg_tbl.
* For later hardware, we need one unique sg_tbl per NCQ tag.
@@ -1213,6 +1359,7 @@ out_port_free_dma_mem:
static void mv_port_stop(struct ata_port *ap)
{
mv_stop_edma(ap);
+ mv_enable_port_irqs(ap, 0);
mv_port_free_dma_mem(ap);
}
@@ -1448,12 +1595,31 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
if ((qc->tf.protocol != ATA_PROT_DMA) &&
(qc->tf.protocol != ATA_PROT_NCQ)) {
+ static int limit_warnings = 10;
+ /*
+ * Errata SATA#16, SATA#24: warn if multiple DRQs expected.
+ *
+ * Someday, we might implement special polling workarounds
+ * for these, but it all seems rather unnecessary since we
+ * normally use only DMA for commands which transfer more
+ * than a single block of data.
+ *
+ * Much of the time, this could just work regardless.
+ * So for now, just log the incident, and allow the attempt.
+ */
+ if (limit_warnings > 0 && (qc->nbytes / qc->sect_size) > 1) {
+ --limit_warnings;
+ ata_link_printk(qc->dev->link, KERN_WARNING, DRV_NAME
+ ": attempting PIO w/multiple DRQ: "
+ "this may fail due to h/w errata\n");
+ }
/*
* We're about to send a non-EDMA capable command to the
* port. Turn off EDMA so there won't be problems accessing
* shadow block, etc registers.
*/
mv_stop_edma(ap);
+ mv_enable_port_irqs(ap, ERR_IRQ);
mv_pmp_select(ap, qc->dev->link->pmp);
return ata_sff_qc_issue(qc);
}
@@ -1483,25 +1649,198 @@ static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
return qc;
}
-static void mv_unexpected_intr(struct ata_port *ap)
+static void mv_pmp_error_handler(struct ata_port *ap)
{
+ unsigned int pmp, pmp_map;
struct mv_port_priv *pp = ap->private_data;
- struct ata_eh_info *ehi = &ap->link.eh_info;
- char *when = "";
+
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH) {
+ /*
+ * Perform NCQ error analysis on failed PMPs
+ * before we freeze the port entirely.
+ *
+ * The failed PMPs are marked earlier by mv_pmp_eh_prep().
+ */
+ pmp_map = pp->delayed_eh_pmp_map;
+ pp->pp_flags &= ~MV_PP_FLAG_DELAYED_EH;
+ for (pmp = 0; pmp_map != 0; pmp++) {
+ unsigned int this_pmp = (1 << pmp);
+ if (pmp_map & this_pmp) {
+ struct ata_link *link = &ap->pmp_link[pmp];
+ pmp_map &= ~this_pmp;
+ ata_eh_analyze_ncq_error(link);
+ }
+ }
+ ata_port_freeze(ap);
+ }
+ sata_pmp_error_handler(ap);
+}
+
+static unsigned int mv_get_err_pmp_map(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+
+ return readl(port_mmio + SATA_TESTCTL_OFS) >> 16;
+}
+
+static void mv_pmp_eh_prep(struct ata_port *ap, unsigned int pmp_map)
+{
+ struct ata_eh_info *ehi;
+ unsigned int pmp;
/*
- * We got a device interrupt from something that
- * was supposed to be using EDMA or polling.
+ * Initialize EH info for PMPs which saw device errors
*/
+ ehi = &ap->link.eh_info;
+ for (pmp = 0; pmp_map != 0; pmp++) {
+ unsigned int this_pmp = (1 << pmp);
+ if (pmp_map & this_pmp) {
+ struct ata_link *link = &ap->pmp_link[pmp];
+
+ pmp_map &= ~this_pmp;
+ ehi = &link->eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "dev err");
+ ehi->err_mask |= AC_ERR_DEV;
+ ehi->action |= ATA_EH_RESET;
+ ata_link_abort(link);
+ }
+ }
+}
+
+static int mv_req_q_empty(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ u32 in_ptr, out_ptr;
+
+ in_ptr = (readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+ out_ptr = (readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+ return (in_ptr == out_ptr); /* 1 == queue_is_empty */
+}
+
+static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ int failed_links;
+ unsigned int old_map, new_map;
+
+ /*
+ * Device error during FBS+NCQ operation:
+ *
+ * Set a port flag to prevent further I/O being enqueued.
+ * Leave the EDMA running to drain outstanding commands from this port.
+ * Perform the post-mortem/EH only when all responses are complete.
+ * Follow recovery sequence from 6042/7042 datasheet (7.3.15.4.2.2).
+ */
+ if (!(pp->pp_flags & MV_PP_FLAG_DELAYED_EH)) {
+ pp->pp_flags |= MV_PP_FLAG_DELAYED_EH;
+ pp->delayed_eh_pmp_map = 0;
+ }
+ old_map = pp->delayed_eh_pmp_map;
+ new_map = old_map | mv_get_err_pmp_map(ap);
+
+ if (old_map != new_map) {
+ pp->delayed_eh_pmp_map = new_map;
+ mv_pmp_eh_prep(ap, new_map & ~old_map);
+ }
+ failed_links = hweight16(new_map);
+
+ ata_port_printk(ap, KERN_INFO, "%s: pmp_map=%04x qc_map=%04x "
+ "failed_links=%d nr_active_links=%d\n",
+ __func__, pp->delayed_eh_pmp_map,
+ ap->qc_active, failed_links,
+ ap->nr_active_links);
+
+ if (ap->nr_active_links <= failed_links && mv_req_q_empty(ap)) {
+ mv_process_crpb_entries(ap, pp);
+ mv_stop_edma(ap);
+ mv_eh_freeze(ap);
+ ata_port_printk(ap, KERN_INFO, "%s: done\n", __func__);
+ return 1; /* handled */
+ }
+ ata_port_printk(ap, KERN_INFO, "%s: waiting\n", __func__);
+ return 1; /* handled */
+}
+
+static int mv_handle_fbs_non_ncq_dev_err(struct ata_port *ap)
+{
+ /*
+ * Possible future enhancement:
+ *
+ * FBS+non-NCQ operation is not yet implemented.
+ * See related notes in mv_edma_cfg().
+ *
+ * Device error during FBS+non-NCQ operation:
+ *
+ * We need to snapshot the shadow registers for each failed command.
+ * Follow recovery sequence from 6042/7042 datasheet (7.3.15.4.2.3).
+ */
+ return 0; /* not handled */
+}
+
+static int mv_handle_dev_err(struct ata_port *ap, u32 edma_err_cause)
+{
+ struct mv_port_priv *pp = ap->private_data;
+
+ if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))
+ return 0; /* EDMA was not active: not handled */
+ if (!(pp->pp_flags & MV_PP_FLAG_FBS_EN))
+ return 0; /* FBS was not active: not handled */
+
+ if (!(edma_err_cause & EDMA_ERR_DEV))
+ return 0; /* non DEV error: not handled */
+ edma_err_cause &= ~EDMA_ERR_IRQ_TRANSIENT;
+ if (edma_err_cause & ~(EDMA_ERR_DEV | EDMA_ERR_SELF_DIS))
+ return 0; /* other problems: not handled */
+
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN) {
+ /*
+ * EDMA should NOT have self-disabled for this case.
+ * If it did, then something is wrong elsewhere,
+ * and we cannot handle it here.
+ */
+ if (edma_err_cause & EDMA_ERR_SELF_DIS) {
+ ata_port_printk(ap, KERN_WARNING,
+ "%s: err_cause=0x%x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+ return 0; /* not handled */
+ }
+ return mv_handle_fbs_ncq_dev_err(ap);
+ } else {
+ /*
+ * EDMA should have self-disabled for this case.
+ * If it did not, then something is wrong elsewhere,
+ * and we cannot handle it here.
+ */
+ if (!(edma_err_cause & EDMA_ERR_SELF_DIS)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "%s: err_cause=0x%x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+ return 0; /* not handled */
+ }
+ return mv_handle_fbs_non_ncq_dev_err(ap);
+ }
+ return 0; /* not handled */
+}
+
+static void mv_unexpected_intr(struct ata_port *ap, int edma_was_enabled)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ char *when = "idle";
+
ata_ehi_clear_desc(ehi);
- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
- when = " while EDMA enabled";
+ if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+ when = "disabled";
+ } else if (edma_was_enabled) {
+ when = "EDMA enabled";
} else {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
- when = " while polling";
+ when = "polling";
}
- ata_ehi_push_desc(ehi, "unexpected device interrupt%s", when);
+ ata_ehi_push_desc(ehi, "unexpected device interrupt while %s", when);
ehi->err_mask |= AC_ERR_OTHER;
ehi->action |= ATA_EH_RESET;
ata_port_freeze(ap);
@@ -1519,32 +1858,66 @@ static void mv_unexpected_intr(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+static void mv_err_intr(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
u32 edma_err_cause, eh_freeze_mask, serr = 0;
+ u32 fis_cause = 0;
struct mv_port_priv *pp = ap->private_data;
struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int action = 0, err_mask = 0;
struct ata_eh_info *ehi = &ap->link.eh_info;
-
- ata_ehi_clear_desc(ehi);
+ struct ata_queued_cmd *qc;
+ int abort = 0;
/*
- * Read and clear the err_cause bits. This won't actually
- * clear for some errors (eg. SError), but we will be doing
- * a hard reset in those cases regardless, which *will* clear it.
+ * Read and clear the SError and err_cause bits.
+ * For GenIIe, if EDMA_ERR_TRANS_IRQ_7 is set, we also must read/clear
+ * the FIS_IRQ_CAUSE register before clearing edma_err_cause.
*/
+ sata_scr_read(&ap->link, SCR_ERROR, &serr);
+ sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
+
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+ if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7)) {
+ fis_cause = readl(port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+ writelfl(~fis_cause, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+ }
writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
- ata_ehi_push_desc(ehi, "edma_err_cause=%08x", edma_err_cause);
+ if (edma_err_cause & EDMA_ERR_DEV) {
+ /*
+ * Device errors during FIS-based switching operation
+ * require special handling.
+ */
+ if (mv_handle_dev_err(ap, edma_err_cause))
+ return;
+ }
+ qc = mv_get_active_qc(ap);
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "edma_err_cause=%08x pp_flags=%08x",
+ edma_err_cause, pp->pp_flags);
+
+ if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7)) {
+ ata_ehi_push_desc(ehi, "fis_cause=%08x", fis_cause);
+ if (fis_cause & SATA_FIS_IRQ_AN) {
+ u32 ec = edma_err_cause &
+ ~(EDMA_ERR_TRANS_IRQ_7 | EDMA_ERR_IRQ_TRANSIENT);
+ sata_async_notification(ap);
+ if (!ec)
+ return; /* Just an AN; no need for the nukes */
+ ata_ehi_push_desc(ehi, "SDB notify");
+ }
+ }
/*
* All generations share these EDMA error cause bits:
*/
- if (edma_err_cause & EDMA_ERR_DEV)
+ if (edma_err_cause & EDMA_ERR_DEV) {
err_mask |= AC_ERR_DEV;
+ action |= ATA_EH_RESET;
+ ata_ehi_push_desc(ehi, "dev error");
+ }
if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR)) {
@@ -1576,13 +1949,6 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
ata_ehi_push_desc(ehi, "EDMA self-disable");
}
if (edma_err_cause & EDMA_ERR_SERR) {
- /*
- * Ensure that we read our own SCR, not a pmp link SCR:
- */
- ap->ops->scr_read(ap, SCR_ERROR, &serr);
- /*
- * Don't clear SError here; leave it for libata-eh:
- */
ata_ehi_push_desc(ehi, "SError=%08x", serr);
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_RESET;
@@ -1602,10 +1968,29 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
else
ehi->err_mask |= err_mask;
- if (edma_err_cause & eh_freeze_mask)
+ if (err_mask == AC_ERR_DEV) {
+ /*
+ * Cannot do ata_port_freeze() here,
+ * because it would kill PIO access,
+ * which is needed for further diagnosis.
+ */
+ mv_eh_freeze(ap);
+ abort = 1;
+ } else if (edma_err_cause & eh_freeze_mask) {
+ /*
+ * Note to self: ata_port_freeze() calls ata_port_abort()
+ */
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ } else {
+ abort = 1;
+ }
+
+ if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
static void mv_process_crpb_response(struct ata_port *ap,
@@ -1632,8 +2017,9 @@ static void mv_process_crpb_response(struct ata_port *ap,
}
}
ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
- qc->err_mask |= ac_err_mask(ata_status);
- ata_qc_complete(qc);
+ if (!ac_err_mask(ata_status))
+ ata_qc_complete(qc);
+ /* else: leave it for mv_err_intr() */
} else {
ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n",
__func__, tag);
@@ -1677,6 +2063,44 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
}
+static void mv_port_intr(struct ata_port *ap, u32 port_cause)
+{
+ struct mv_port_priv *pp;
+ int edma_was_enabled;
+
+ if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+ mv_unexpected_intr(ap, 0);
+ return;
+ }
+ /*
+ * Grab a snapshot of the EDMA_EN flag setting,
+ * so that we have a consistent view for this port,
+ * even if something we call of our routines changes it.
+ */
+ pp = ap->private_data;
+ edma_was_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
+ /*
+ * Process completed CRPB response(s) before other events.
+ */
+ if (edma_was_enabled && (port_cause & DONE_IRQ)) {
+ mv_process_crpb_entries(ap, pp);
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
+ mv_handle_fbs_ncq_dev_err(ap);
+ }
+ /*
+ * Handle chip-reported errors, or continue on to handle PIO.
+ */
+ if (unlikely(port_cause & ERR_IRQ)) {
+ mv_err_intr(ap);
+ } else if (!edma_was_enabled) {
+ struct ata_queued_cmd *qc = mv_get_active_qc(ap);
+ if (qc)
+ ata_sff_host_intr(ap, qc);
+ else
+ mv_unexpected_intr(ap, edma_was_enabled);
+ }
+}
+
/**
* mv_host_intr - Handle all interrupts on the given host controller
* @host: host specific structure
@@ -1688,66 +2112,58 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
static int mv_host_intr(struct ata_host *host, u32 main_irq_cause)
{
struct mv_host_priv *hpriv = host->private_data;
- void __iomem *mmio = hpriv->base, *hc_mmio = NULL;
- u32 hc_irq_cause = 0;
+ void __iomem *mmio = hpriv->base, *hc_mmio;
unsigned int handled = 0, port;
for (port = 0; port < hpriv->n_ports; port++) {
struct ata_port *ap = host->ports[port];
- struct mv_port_priv *pp;
- unsigned int shift, hardport, port_cause;
- /*
- * When we move to the second hc, flag our cached
- * copies of hc_mmio (and hc_irq_cause) as invalid again.
- */
- if (port == MV_PORTS_PER_HC)
- hc_mmio = NULL;
- /*
- * Do nothing if port is not interrupting or is disabled:
- */
+ unsigned int p, shift, hardport, port_cause;
+
MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
- port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ);
- if (!port_cause || !ap || (ap->flags & ATA_FLAG_DISABLED))
- continue;
/*
- * Each hc within the host has its own hc_irq_cause register.
- * We defer reading it until we know we need it, right now:
- *
- * FIXME later: we don't really need to read this register
- * (some logic changes required below if we go that way),
- * because it doesn't tell us anything new. But we do need
- * to write to it, outside the top of this loop,
- * to reset the interrupt triggers for next time.
+ * Each hc within the host has its own hc_irq_cause register,
+ * where the interrupting ports bits get ack'd.
*/
- if (!hc_mmio) {
+ if (hardport == 0) { /* first port on this hc ? */
+ u32 hc_cause = (main_irq_cause >> shift) & HC0_IRQ_PEND;
+ u32 port_mask, ack_irqs;
+ /*
+ * Skip this entire hc if nothing pending for any ports
+ */
+ if (!hc_cause) {
+ port += MV_PORTS_PER_HC - 1;
+ continue;
+ }
+ /*
+ * We don't need/want to read the hc_irq_cause register,
+ * because doing so hurts performance, and
+ * main_irq_cause already gives us everything we need.
+ *
+ * But we do have to *write* to the hc_irq_cause to ack
+ * the ports that we are handling this time through.
+ *
+ * This requires that we create a bitmap for those
+ * ports which interrupted us, and use that bitmap
+ * to ack (only) those ports via hc_irq_cause.
+ */
+ ack_irqs = 0;
+ for (p = 0; p < MV_PORTS_PER_HC; ++p) {
+ if ((port + p) >= hpriv->n_ports)
+ break;
+ port_mask = (DONE_IRQ | ERR_IRQ) << (p * 2);
+ if (hc_cause & port_mask)
+ ack_irqs |= (DMA_IRQ | DEV_IRQ) << p;
+ }
hc_mmio = mv_hc_base_from_port(mmio, port);
- hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+ writelfl(~ack_irqs, hc_mmio + HC_IRQ_CAUSE_OFS);
handled = 1;
}
/*
- * Process completed CRPB response(s) before other events.
+ * Handle interrupts signalled for this port:
*/
- pp = ap->private_data;
- if (hc_irq_cause & (DMA_IRQ << hardport)) {
- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN)
- mv_process_crpb_entries(ap, pp);
- }
- /*
- * Handle chip-reported errors, or continue on to handle PIO.
- */
- if (unlikely(port_cause & ERR_IRQ)) {
- mv_err_intr(ap, mv_get_active_qc(ap));
- } else if (hc_irq_cause & (DEV_IRQ << hardport)) {
- if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
- struct ata_queued_cmd *qc = mv_get_active_qc(ap);
- if (qc) {
- ata_sff_host_intr(ap, qc);
- continue;
- }
- }
- mv_unexpected_intr(ap);
- }
+ port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ);
+ if (port_cause)
+ mv_port_intr(ap, port_cause);
}
return handled;
}
@@ -1812,20 +2228,20 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
struct ata_host *host = dev_instance;
struct mv_host_priv *hpriv = host->private_data;
unsigned int handled = 0;
- u32 main_irq_cause, main_irq_mask;
+ u32 main_irq_cause, pending_irqs;
spin_lock(&host->lock);
main_irq_cause = readl(hpriv->main_irq_cause_addr);
- main_irq_mask = readl(hpriv->main_irq_mask_addr);
+ pending_irqs = main_irq_cause & hpriv->main_irq_mask;
/*
* Deal with cases where we either have nothing pending, or have read
* a bogus register value which can indicate HW removal or PCI fault.
*/
- if ((main_irq_cause & main_irq_mask) && (main_irq_cause != 0xffffffffU)) {
- if (unlikely((main_irq_cause & PCI_ERR) && HAS_PCI(host)))
+ if (pending_irqs && main_irq_cause != 0xffffffffU) {
+ if (unlikely((pending_irqs & PCI_ERR) && !IS_SOC(hpriv)))
handled = mv_pci_error(host, hpriv->base);
else
- handled = mv_host_intr(host, main_irq_cause);
+ handled = mv_host_intr(host, pending_irqs);
}
spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
@@ -1894,7 +2310,7 @@ static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio)
static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
{
- writel(0x0fcfffff, mmio + MV_FLASH_CTL);
+ writel(0x0fcfffff, mmio + MV_FLASH_CTL_OFS);
}
static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
@@ -1913,7 +2329,7 @@ static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
{
u32 tmp;
- writel(0, mmio + MV_GPIO_PORT_CTL);
+ writel(0, mmio + MV_GPIO_PORT_CTL_OFS);
/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
@@ -1931,14 +2347,14 @@ static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
if (fix_apm_sq) {
- tmp = readl(phy_mmio + MV5_LT_MODE);
+ tmp = readl(phy_mmio + MV5_LTMODE_OFS);
tmp |= (1 << 19);
- writel(tmp, phy_mmio + MV5_LT_MODE);
+ writel(tmp, phy_mmio + MV5_LTMODE_OFS);
- tmp = readl(phy_mmio + MV5_PHY_CTL);
+ tmp = readl(phy_mmio + MV5_PHY_CTL_OFS);
tmp &= ~0x3;
tmp |= 0x1;
- writel(tmp, phy_mmio + MV5_PHY_CTL);
+ writel(tmp, phy_mmio + MV5_PHY_CTL_OFS);
}
tmp = readl(phy_mmio + MV5_PHY_MODE);
@@ -1956,11 +2372,6 @@ static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
{
void __iomem *port_mmio = mv_port_base(mmio, port);
- /*
- * The datasheet warns against setting ATA_RST when EDMA is active
- * (but doesn't say what the problem might be). So we first try
- * to disable the EDMA engine before doing the ATA_RST operation.
- */
mv_reset_channel(hpriv, mmio, port);
ZERO(0x028); /* command */
@@ -1975,7 +2386,7 @@ static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
ZERO(0x024); /* respq outp */
ZERO(0x020); /* respq inp */
ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT_OFS);
}
#undef ZERO
@@ -2021,14 +2432,13 @@ static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio)
struct mv_host_priv *hpriv = host->private_data;
u32 tmp;
- tmp = readl(mmio + MV_PCI_MODE);
+ tmp = readl(mmio + MV_PCI_MODE_OFS);
tmp &= 0xff00ffff;
- writel(tmp, mmio + MV_PCI_MODE);
+ writel(tmp, mmio + MV_PCI_MODE_OFS);
ZERO(MV_PCI_DISC_TIMER);
ZERO(MV_PCI_MSI_TRIGGER);
- writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
- ZERO(PCI_HC_MAIN_IRQ_MASK_OFS);
+ writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT_OFS);
ZERO(MV_PCI_SERR_MASK);
ZERO(hpriv->irq_cause_ofs);
ZERO(hpriv->irq_mask_ofs);
@@ -2045,10 +2455,10 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
mv5_reset_flash(hpriv, mmio);
- tmp = readl(mmio + MV_GPIO_PORT_CTL);
+ tmp = readl(mmio + MV_GPIO_PORT_CTL_OFS);
tmp &= 0x3;
tmp |= (1 << 5) | (1 << 6);
- writel(tmp, mmio + MV_GPIO_PORT_CTL);
+ writel(tmp, mmio + MV_GPIO_PORT_CTL_OFS);
}
/**
@@ -2121,7 +2531,7 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
void __iomem *port_mmio;
u32 tmp;
- tmp = readl(mmio + MV_RESET_CFG);
+ tmp = readl(mmio + MV_RESET_CFG_OFS);
if ((tmp & (1 << 0)) == 0) {
hpriv->signal[idx].amps = 0x7 << 8;
hpriv->signal[idx].pre = 0x1 << 5;
@@ -2137,7 +2547,7 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
{
- writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
+ writel(0x00000060, mmio + MV_GPIO_PORT_CTL_OFS);
}
static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
@@ -2150,7 +2560,7 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
int fix_phy_mode4 =
hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
- u32 m2, tmp;
+ u32 m2, m3;
if (fix_phy_mode2) {
m2 = readl(port_mmio + PHY_MODE2);
@@ -2167,28 +2577,36 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
udelay(200);
}
- /* who knows what this magic does */
- tmp = readl(port_mmio + PHY_MODE3);
- tmp &= ~0x7F800000;
- tmp |= 0x2A800000;
- writel(tmp, port_mmio + PHY_MODE3);
-
- if (fix_phy_mode4) {
- u32 m4;
-
- m4 = readl(port_mmio + PHY_MODE4);
-
- if (hp_flags & MV_HP_ERRATA_60X1B2)
- tmp = readl(port_mmio + PHY_MODE3);
+ /*
+ * Gen-II/IIe PHY_MODE3 errata RM#2:
+ * Achieves better receiver noise performance than the h/w default:
+ */
+ m3 = readl(port_mmio + PHY_MODE3);
+ m3 = (m3 & 0x1f) | (0x5555601 << 5);
- /* workaround for errata FEr SATA#10 (part 1) */
- m4 = (m4 & ~(1 << 1)) | (1 << 0);
+ /* Guideline 88F5182 (GL# SATA-S11) */
+ if (IS_SOC(hpriv))
+ m3 &= ~0x1c;
+ if (fix_phy_mode4) {
+ u32 m4 = readl(port_mmio + PHY_MODE4);
+ /*
+ * Enforce reserved-bit restrictions on GenIIe devices only.
+ * For earlier chipsets, force only the internal config field
+ * (workaround for errata FEr SATA#10 part 1).
+ */
+ if (IS_GEN_IIE(hpriv))
+ m4 = (m4 & ~PHY_MODE4_RSVD_ZEROS) | PHY_MODE4_RSVD_ONES;
+ else
+ m4 = (m4 & ~PHY_MODE4_CFG_MASK) | PHY_MODE4_CFG_VALUE;
writel(m4, port_mmio + PHY_MODE4);
-
- if (hp_flags & MV_HP_ERRATA_60X1B2)
- writel(tmp, port_mmio + PHY_MODE3);
}
+ /*
+ * Workaround for 60x1-B2 errata SATA#13:
+ * Any write to PHY_MODE4 (above) may corrupt PHY_MODE3,
+ * so we must always rewrite PHY_MODE3 after PHY_MODE4.
+ */
+ writel(m3, port_mmio + PHY_MODE3);
/* Revert values of pre-emphasis and signal amps to the saved ones */
m2 = readl(port_mmio + PHY_MODE2);
@@ -2235,11 +2653,6 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
{
void __iomem *port_mmio = mv_port_base(mmio, port);
- /*
- * The datasheet warns against setting ATA_RST when EDMA is active
- * (but doesn't say what the problem might be). So we first try
- * to disable the EDMA engine before doing the ATA_RST operation.
- */
mv_reset_channel(hpriv, mmio, port);
ZERO(0x028); /* command */
@@ -2254,7 +2667,7 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
ZERO(0x024); /* respq outp */
ZERO(0x020); /* respq inp */
ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT_OFS);
}
#undef ZERO
@@ -2297,38 +2710,39 @@ static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio)
return;
}
-static void mv_setup_ifctl(void __iomem *port_mmio, int want_gen2i)
+static void mv_setup_ifcfg(void __iomem *port_mmio, int want_gen2i)
{
- u32 ifctl = readl(port_mmio + SATA_INTERFACE_CFG);
+ u32 ifcfg = readl(port_mmio + SATA_INTERFACE_CFG_OFS);
- ifctl = (ifctl & 0xf7f) | 0x9b1000; /* from chip spec */
+ ifcfg = (ifcfg & 0xf7f) | 0x9b1000; /* from chip spec */
if (want_gen2i)
- ifctl |= (1 << 7); /* enable gen2i speed */
- writelfl(ifctl, port_mmio + SATA_INTERFACE_CFG);
+ ifcfg |= (1 << 7); /* enable gen2i speed */
+ writelfl(ifcfg, port_mmio + SATA_INTERFACE_CFG_OFS);
}
-/*
- * Caller must ensure that EDMA is not active,
- * by first doing mv_stop_edma() where needed.
- */
static void mv_reset_channel(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port_no)
{
void __iomem *port_mmio = mv_port_base(mmio, port_no);
+ /*
+ * The datasheet warns against setting EDMA_RESET when EDMA is active
+ * (but doesn't say what the problem might be). So we first try
+ * to disable the EDMA engine before doing the EDMA_RESET operation.
+ */
mv_stop_edma_engine(port_mmio);
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_RESET, port_mmio + EDMA_CMD_OFS);
if (!IS_GEN_I(hpriv)) {
- /* Enable 3.0gb/s link speed */
- mv_setup_ifctl(port_mmio, 1);
+ /* Enable 3.0gb/s link speed: this survives EDMA_RESET */
+ mv_setup_ifcfg(port_mmio, 1);
}
/*
- * Strobing ATA_RST here causes a hard reset of the SATA transport,
+ * Strobing EDMA_RESET here causes a hard reset of the SATA transport,
* link, and physical layers. It resets all SATA interface registers
* (except for SATA_INTERFACE_CFG), and issues a COMRESET to the dev.
*/
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_RESET, port_mmio + EDMA_CMD_OFS);
udelay(25); /* allow reset propagation */
writelfl(0, port_mmio + EDMA_CMD_OFS);
@@ -2387,12 +2801,13 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, timing, deadline + extra,
&online, NULL);
+ rc = online ? -EAGAIN : rc;
if (rc)
return rc;
sata_scr_read(link, SCR_STATUS, &sstatus);
if (!IS_GEN_I(hpriv) && ++attempts >= 5 && sstatus == 0x121) {
/* Force 1.5gb/s link speed and try again */
- mv_setup_ifctl(mv_ap_base(ap), 0);
+ mv_setup_ifcfg(mv_ap_base(ap), 0);
if (time_after(jiffies + HZ, deadline))
extra = HZ; /* only extend it once, max */
}
@@ -2403,32 +2818,18 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
static void mv_eh_freeze(struct ata_port *ap)
{
- struct mv_host_priv *hpriv = ap->host->private_data;
- unsigned int shift, hardport, port = ap->port_no;
- u32 main_irq_mask;
-
- /* FIXME: handle coalescing completion events properly */
-
mv_stop_edma(ap);
- MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
-
- /* disable assertion of portN err, done events */
- main_irq_mask = readl(hpriv->main_irq_mask_addr);
- main_irq_mask &= ~((DONE_IRQ | ERR_IRQ) << shift);
- writelfl(main_irq_mask, hpriv->main_irq_mask_addr);
+ mv_enable_port_irqs(ap, 0);
}
static void mv_eh_thaw(struct ata_port *ap)
{
struct mv_host_priv *hpriv = ap->host->private_data;
- unsigned int shift, hardport, port = ap->port_no;
+ unsigned int port = ap->port_no;
+ unsigned int hardport = mv_hardport_from_port(port);
void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port);
void __iomem *port_mmio = mv_ap_base(ap);
- u32 main_irq_mask, hc_irq_cause;
-
- /* FIXME: handle coalescing completion events properly */
-
- MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
+ u32 hc_irq_cause;
/* clear EDMA errors on this port */
writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -2438,10 +2839,7 @@ static void mv_eh_thaw(struct ata_port *ap)
hc_irq_cause &= ~((DEV_IRQ | DMA_IRQ) << hardport);
writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
- /* enable assertion of portN err, done events */
- main_irq_mask = readl(hpriv->main_irq_mask_addr);
- main_irq_mask |= ((DONE_IRQ | ERR_IRQ) << shift);
- writelfl(main_irq_mask, hpriv->main_irq_mask_addr);
+ mv_enable_port_irqs(ap, ERR_IRQ);
}
/**
@@ -2493,6 +2891,34 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
}
+static unsigned int mv_in_pcix_mode(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
+ u32 reg;
+
+ if (IS_SOC(hpriv) || !IS_PCIE(hpriv))
+ return 0; /* not PCI-X capable */
+ reg = readl(mmio + MV_PCI_MODE_OFS);
+ if ((reg & MV_PCI_MODE_MASK) == 0)
+ return 0; /* conventional PCI mode */
+ return 1; /* chip is in PCI-X mode */
+}
+
+static int mv_pci_cut_through_okay(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
+ u32 reg;
+
+ if (!mv_in_pcix_mode(host)) {
+ reg = readl(mmio + PCI_COMMAND_OFS);
+ if (reg & PCI_COMMAND_MRDTRIG)
+ return 0; /* not okay */
+ }
+ return 1; /* okay */
+}
+
static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
@@ -2560,7 +2986,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
break;
case chip_7042:
- hp_flags |= MV_HP_PCIE;
+ hp_flags |= MV_HP_PCIE | MV_HP_CUT_THROUGH;
if (pdev->vendor == PCI_VENDOR_ID_TTI &&
(pdev->device == 0x2300 || pdev->device == 0x2310))
{
@@ -2590,15 +3016,15 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
" and avoid the final two gigabytes on"
" all RocketRAID BIOS initialized drives.\n");
}
+ /* drop through */
case chip_6042:
hpriv->ops = &mv6xxx_ops;
hp_flags |= MV_HP_GEN_IIE;
+ if (board_idx == chip_6042 && mv_pci_cut_through_okay(host))
+ hp_flags |= MV_HP_CUT_THROUGH;
switch (pdev->revision) {
- case 0x0:
- hp_flags |= MV_HP_ERRATA_XX42A0;
- break;
- case 0x1:
+ case 0x2: /* Rev.B0: the first/only public release */
hp_flags |= MV_HP_ERRATA_60X1C0;
break;
default:
@@ -2610,7 +3036,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
break;
case chip_soc:
hpriv->ops = &mv_soc_ops;
- hp_flags |= MV_HP_ERRATA_60X1C0;
+ hp_flags |= MV_HP_FLAG_SOC | MV_HP_ERRATA_60X1C0;
break;
default:
@@ -2654,16 +3080,16 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
if (rc)
goto done;
- if (HAS_PCI(host)) {
- hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS;
- } else {
+ if (IS_SOC(hpriv)) {
hpriv->main_irq_cause_addr = mmio + SOC_HC_MAIN_IRQ_CAUSE_OFS;
hpriv->main_irq_mask_addr = mmio + SOC_HC_MAIN_IRQ_MASK_OFS;
+ } else {
+ hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS;
}
/* global interrupt mask: 0 == mask everything */
- writel(0, hpriv->main_irq_mask_addr);
+ mv_set_main_irq_mask(host, ~0, 0);
n_hc = mv_get_hc_count(host->ports[0]->flags);
@@ -2685,7 +3111,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
mv_port_init(&ap->ioaddr, port_mmio);
#ifdef CONFIG_PCI
- if (HAS_PCI(host)) {
+ if (!IS_SOC(hpriv)) {
unsigned int offset = port_mmio - mmio;
ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
@@ -2705,31 +3131,18 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
}
- if (HAS_PCI(host)) {
+ if (!IS_SOC(hpriv)) {
/* Clear any currently outstanding host interrupt conditions */
writelfl(0, mmio + hpriv->irq_cause_ofs);
/* and unmask interrupt generation for host regs */
writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
- if (IS_GEN_I(hpriv))
- writelfl(~HC_MAIN_MASKED_IRQS_5,
- hpriv->main_irq_mask_addr);
- else
- writelfl(~HC_MAIN_MASKED_IRQS,
- hpriv->main_irq_mask_addr);
-
- VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
- "PCI int cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_irq_cause_addr),
- readl(hpriv->main_irq_mask_addr),
- readl(mmio + hpriv->irq_cause_ofs),
- readl(mmio + hpriv->irq_mask_ofs));
- } else {
- writelfl(~HC_MAIN_MASKED_IRQS_SOC,
- hpriv->main_irq_mask_addr);
- VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_irq_cause_addr),
- readl(hpriv->main_irq_mask_addr));
+
+ /*
+ * enable only global host interrupts for now.
+ * The per-port interrupts get done later as ports are set up.
+ */
+ mv_set_main_irq_mask(host, 0, PCI_ERR);
}
done:
return rc;
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 5a10dc5048a..030665ba76b 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -53,7 +53,15 @@ enum {
PDC_MMIO_BAR = 3,
PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */
- /* register offsets */
+ /* host register offsets (from host->iomap[PDC_MMIO_BAR]) */
+ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
+ PDC_FLASH_CTL = 0x44, /* Flash control register */
+ PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
+ PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
+ PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
+ PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */
+
+ /* per-port ATA register offsets (from ap->ioaddr.cmd_addr) */
PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
PDC_SECTOR_COUNT = 0x08, /* Sector count reg (per port) */
PDC_SECTOR_NUMBER = 0x0C, /* Sector number reg (per port) */
@@ -63,14 +71,11 @@ enum {
PDC_COMMAND = 0x1C, /* Command/status reg (per port) */
PDC_ALTSTATUS = 0x38, /* Alternate-status/device-control reg (per port) */
PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
- PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
- PDC_FLASH_CTL = 0x44, /* Flash control register */
PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */
PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
- PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
- PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
- PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
- PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */
+
+ /* per-port SATA register offsets (from ap->ioaddr.scr_addr) */
+ PDC_PHYMODE4 = 0x14,
/* PDC_GLOBAL_CTL bit definitions */
PDC_PH_ERR = (1 << 8), /* PCI error while loading packet */
@@ -134,7 +139,7 @@ struct pdc_port_priv {
static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int pdc_common_port_start(struct ata_port *ap);
static int pdc_sata_port_start(struct ata_port *ap);
static void pdc_qc_prep(struct ata_queued_cmd *qc);
@@ -332,12 +337,12 @@ static int pdc_sata_port_start(struct ata_port *ap)
/* fix up PHYMODE4 align timing */
if (ap->flags & PDC_FLAG_GEN_II) {
- void __iomem *mmio = ap->ioaddr.scr_addr;
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
unsigned int tmp;
- tmp = readl(mmio + 0x014);
+ tmp = readl(sata_mmio + PDC_PHYMODE4);
tmp = (tmp & ~3) | 1; /* set bits 1:0 = 0:1 */
- writel(tmp, mmio + 0x014);
+ writel(tmp, sata_mmio + PDC_PHYMODE4);
}
return 0;
@@ -345,32 +350,32 @@ static int pdc_sata_port_start(struct ata_port *ap)
static void pdc_reset_port(struct ata_port *ap)
{
- void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+ void __iomem *ata_ctlstat_mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
unsigned int i;
u32 tmp;
for (i = 11; i > 0; i--) {
- tmp = readl(mmio);
+ tmp = readl(ata_ctlstat_mmio);
if (tmp & PDC_RESET)
break;
udelay(100);
tmp |= PDC_RESET;
- writel(tmp, mmio);
+ writel(tmp, ata_ctlstat_mmio);
}
tmp &= ~PDC_RESET;
- writel(tmp, mmio);
- readl(mmio); /* flush */
+ writel(tmp, ata_ctlstat_mmio);
+ readl(ata_ctlstat_mmio); /* flush */
}
static int pdc_pata_cable_detect(struct ata_port *ap)
{
u8 tmp;
- void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
- tmp = readb(mmio);
+ tmp = readb(ata_mmio + PDC_CTLSTAT + 3);
if (tmp & 0x01)
return ATA_CBL_PATA40;
return ATA_CBL_PATA80;
@@ -557,31 +562,25 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
pdc_fill_sg(qc);
- /* fall through */
-
+ /*FALLTHROUGH*/
case ATA_PROT_NODATA:
i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,
qc->dev->devno, pp->pkt);
-
if (qc->tf.flags & ATA_TFLAG_LBA48)
i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
else
i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
-
pdc_pkt_footer(&qc->tf, pp->pkt, i);
break;
-
case ATAPI_PROT_PIO:
pdc_fill_sg(qc);
break;
-
case ATAPI_PROT_DMA:
pdc_fill_sg(qc);
/*FALLTHROUGH*/
case ATAPI_PROT_NODATA:
pdc_atapi_pkt(qc);
break;
-
default:
break;
}
@@ -611,7 +610,7 @@ static unsigned int pdc_sata_ata_port_to_ata_no(const struct ata_port *ap)
unsigned int nr_ports = pdc_sata_nr_ports(ap);
unsigned int i;
- for(i = 0; i < nr_ports && host->ports[i] != ap; ++i)
+ for (i = 0; i < nr_ports && host->ports[i] != ap; ++i)
;
BUG_ON(i >= nr_ports);
return pdc_port_no_to_ata_no(i, pdc_is_sataii_tx4(ap->flags));
@@ -624,14 +623,14 @@ static unsigned int pdc_sata_hotplug_offset(const struct ata_port *ap)
static void pdc_freeze(struct ata_port *ap)
{
- void __iomem *mmio = ap->ioaddr.cmd_addr;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
u32 tmp;
- tmp = readl(mmio + PDC_CTLSTAT);
+ tmp = readl(ata_mmio + PDC_CTLSTAT);
tmp |= PDC_IRQ_DISABLE;
tmp &= ~PDC_DMA_ENABLE;
- writel(tmp, mmio + PDC_CTLSTAT);
- readl(mmio + PDC_CTLSTAT); /* flush */
+ writel(tmp, ata_mmio + PDC_CTLSTAT);
+ readl(ata_mmio + PDC_CTLSTAT); /* flush */
}
static void pdc_sata_freeze(struct ata_port *ap)
@@ -659,17 +658,17 @@ static void pdc_sata_freeze(struct ata_port *ap)
static void pdc_thaw(struct ata_port *ap)
{
- void __iomem *mmio = ap->ioaddr.cmd_addr;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
u32 tmp;
/* clear IRQ */
- readl(mmio + PDC_INT_SEQMASK);
+ readl(ata_mmio + PDC_COMMAND);
/* turn IRQ back on */
- tmp = readl(mmio + PDC_CTLSTAT);
+ tmp = readl(ata_mmio + PDC_CTLSTAT);
tmp &= ~PDC_IRQ_DISABLE;
- writel(tmp, mmio + PDC_CTLSTAT);
- readl(mmio + PDC_CTLSTAT); /* flush */
+ writel(tmp, ata_mmio + PDC_CTLSTAT);
+ readl(ata_mmio + PDC_CTLSTAT); /* flush */
}
static void pdc_sata_thaw(struct ata_port *ap)
@@ -743,11 +742,11 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
ata_port_abort(ap);
}
-static inline unsigned int pdc_host_intr(struct ata_port *ap,
- struct ata_queued_cmd *qc)
+static unsigned int pdc_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
{
unsigned int handled = 0;
- void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
u32 port_status, err_mask;
err_mask = PDC_ERR_MASK;
@@ -755,7 +754,7 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
err_mask &= ~PDC1_ERR_MASK;
else
err_mask &= ~PDC2_ERR_MASK;
- port_status = readl(port_mmio + PDC_GLOBAL_CTL);
+ port_status = readl(ata_mmio + PDC_GLOBAL_CTL);
if (unlikely(port_status & err_mask)) {
pdc_error_intr(ap, qc, port_status, err_mask);
return 1;
@@ -770,7 +769,6 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
ata_qc_complete(qc);
handled = 1;
break;
-
default:
ap->stats.idle_irq++;
break;
@@ -781,10 +779,9 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
static void pdc_irq_clear(struct ata_port *ap)
{
- struct ata_host *host = ap->host;
- void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
- readl(mmio + PDC_INT_SEQMASK);
+ readl(ata_mmio + PDC_COMMAND);
}
static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
@@ -794,7 +791,7 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
u32 mask = 0;
unsigned int i, tmp;
unsigned int handled = 0;
- void __iomem *mmio_base;
+ void __iomem *host_mmio;
unsigned int hotplug_offset, ata_no;
u32 hotplug_status;
int is_sataii_tx4;
@@ -806,7 +803,7 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
return IRQ_NONE;
}
- mmio_base = host->iomap[PDC_MMIO_BAR];
+ host_mmio = host->iomap[PDC_MMIO_BAR];
spin_lock(&host->lock);
@@ -815,26 +812,26 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
hotplug_offset = PDC2_SATA_PLUG_CSR;
else
hotplug_offset = PDC_SATA_PLUG_CSR;
- hotplug_status = readl(mmio_base + hotplug_offset);
+ hotplug_status = readl(host_mmio + hotplug_offset);
if (hotplug_status & 0xff)
- writel(hotplug_status | 0xff, mmio_base + hotplug_offset);
+ writel(hotplug_status | 0xff, host_mmio + hotplug_offset);
hotplug_status &= 0xff; /* clear uninteresting bits */
/* reading should also clear interrupts */
- mask = readl(mmio_base + PDC_INT_SEQMASK);
+ mask = readl(host_mmio + PDC_INT_SEQMASK);
if (mask == 0xffffffff && hotplug_status == 0) {
VPRINTK("QUICK EXIT 2\n");
goto done_irq;
}
- mask &= 0xffff; /* only 16 tags possible */
+ mask &= 0xffff; /* only 16 SEQIDs possible */
if (mask == 0 && hotplug_status == 0) {
VPRINTK("QUICK EXIT 3\n");
goto done_irq;
}
- writel(mask, mmio_base + PDC_INT_SEQMASK);
+ writel(mask, host_mmio + PDC_INT_SEQMASK);
is_sataii_tx4 = pdc_is_sataii_tx4(host->ports[0]->flags);
@@ -875,23 +872,24 @@ done_irq:
return IRQ_RETVAL(handled);
}
-static inline void pdc_packet_start(struct ata_queued_cmd *qc)
+static void pdc_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
unsigned int port_no = ap->port_no;
u8 seq = (u8) (port_no + 1);
VPRINTK("ENTER, ap %p\n", ap);
- writel(0x00000001, mmio + (seq * 4));
- readl(mmio + (seq * 4)); /* flush */
+ writel(0x00000001, host_mmio + (seq * 4));
+ readl(host_mmio + (seq * 4)); /* flush */
pp->pkt[2] = seq;
wmb(); /* flush PRD, pkt writes */
- writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
+ writel(pp->pkt_dma, ata_mmio + PDC_PKT_SUBMIT);
+ readl(ata_mmio + PDC_PKT_SUBMIT); /* flush */
}
static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc)
@@ -909,11 +907,9 @@ static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc)
case ATA_PROT_DMA:
pdc_packet_start(qc);
return 0;
-
default:
break;
}
-
return ata_sff_qc_issue(qc);
}
@@ -987,7 +983,7 @@ static void pdc_ata_setup_port(struct ata_port *ap,
static void pdc_host_init(struct ata_host *host)
{
- void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR];
int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II;
int hotplug_offset;
u32 tmp;
@@ -1004,38 +1000,38 @@ static void pdc_host_init(struct ata_host *host)
*/
/* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */
- tmp = readl(mmio + PDC_FLASH_CTL);
+ tmp = readl(host_mmio + PDC_FLASH_CTL);
tmp |= 0x02000; /* bit 13 (enable bmr burst) */
if (!is_gen2)
tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */
- writel(tmp, mmio + PDC_FLASH_CTL);
+ writel(tmp, host_mmio + PDC_FLASH_CTL);
/* clear plug/unplug flags for all ports */
- tmp = readl(mmio + hotplug_offset);
- writel(tmp | 0xff, mmio + hotplug_offset);
+ tmp = readl(host_mmio + hotplug_offset);
+ writel(tmp | 0xff, host_mmio + hotplug_offset);
/* unmask plug/unplug ints */
- tmp = readl(mmio + hotplug_offset);
- writel(tmp & ~0xff0000, mmio + hotplug_offset);
+ tmp = readl(host_mmio + hotplug_offset);
+ writel(tmp & ~0xff0000, host_mmio + hotplug_offset);
/* don't initialise TBG or SLEW on 2nd generation chips */
if (is_gen2)
return;
/* reduce TBG clock to 133 Mhz. */
- tmp = readl(mmio + PDC_TBG_MODE);
+ tmp = readl(host_mmio + PDC_TBG_MODE);
tmp &= ~0x30000; /* clear bit 17, 16*/
tmp |= 0x10000; /* set bit 17:16 = 0:1 */
- writel(tmp, mmio + PDC_TBG_MODE);
+ writel(tmp, host_mmio + PDC_TBG_MODE);
- readl(mmio + PDC_TBG_MODE); /* flush */
+ readl(host_mmio + PDC_TBG_MODE); /* flush */
msleep(10);
/* adjust slew rate control register. */
- tmp = readl(mmio + PDC_SLEW_CTL);
+ tmp = readl(host_mmio + PDC_SLEW_CTL);
tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */
tmp |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */
- writel(tmp, mmio + PDC_SLEW_CTL);
+ writel(tmp, host_mmio + PDC_SLEW_CTL);
}
static int pdc_ata_init_one(struct pci_dev *pdev,
@@ -1045,7 +1041,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];
const struct ata_port_info *ppi[PDC_MAX_PORTS];
struct ata_host *host;
- void __iomem *base;
+ void __iomem *host_mmio;
int n_ports, i, rc;
int is_sataii_tx4;
@@ -1062,7 +1058,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
pcim_pin_device(pdev);
if (rc)
return rc;
- base = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
+ host_mmio = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
/* determine port configuration and setup host */
n_ports = 2;
@@ -1072,7 +1068,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
ppi[i] = pi;
if (pi->flags & PDC_FLAG_SATA_PATA) {
- u8 tmp = readb(base + PDC_FLASH_CTL+1);
+ u8 tmp = readb(host_mmio + PDC_FLASH_CTL + 1);
if (!(tmp & 0x80))
ppi[n_ports++] = pi + 1;
}
@@ -1088,13 +1084,13 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
- unsigned int port_offset = 0x200 + ata_no * 0x80;
+ unsigned int ata_offset = 0x200 + ata_no * 0x80;
unsigned int scr_offset = 0x400 + ata_no * 0x100;
- pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);
+ pdc_ata_setup_port(ap, host_mmio + ata_offset, host_mmio + scr_offset);
ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, ata_offset, "ata");
}
/* initialize adapter */
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 27a11011007..84ffcc26a74 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -370,6 +370,7 @@ static const struct pci_device_id sil24_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },
{ PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },
{ PCI_VDEVICE(CMD, 0x0242), BID_SIL3132 },
+ { PCI_VDEVICE(CMD, 0x0244), BID_SIL3132 },
{ PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },
{ PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },
@@ -899,14 +900,25 @@ static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc)
static void sil24_pmp_attach(struct ata_port *ap)
{
+ u32 *gscr = ap->link.device->gscr;
+
sil24_config_pmp(ap, 1);
sil24_init_port(ap);
+
+ if (sata_pmp_gscr_vendor(gscr) == 0x11ab &&
+ sata_pmp_gscr_devid(gscr) == 0x4140) {
+ ata_port_printk(ap, KERN_INFO,
+ "disabling NCQ support due to sil24-mv4140 quirk\n");
+ ap->flags &= ~ATA_FLAG_NCQ;
+ }
}
static void sil24_pmp_detach(struct ata_port *ap)
{
sil24_init_port(ap);
sil24_config_pmp(ap, 0);
+
+ ap->flags |= ATA_FLAG_NCQ;
}
static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index f277cea904c..db529b84994 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -83,6 +83,7 @@ static struct ata_port_operations uli_ops = {
.inherits = &ata_bmdma_port_ops,
.scr_read = uli_scr_read,
.scr_write = uli_scr_write,
+ .hardreset = ATA_OP_NULL,
};
static const struct ata_port_info uli_port_info = {