aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorBastiaan Jacques <b.jacques@planet.nl>2006-04-17 08:17:59 -0400
committerJeff Garzik <jeff@garzik.org>2006-04-20 18:37:08 -0400
commitbf2af2a2027e52b653882fbca840620e896ae081 (patch)
treee42ce1ac34058c1990d929f38a6e805dd6edb602 /drivers/scsi
parent857c68f733eea07f11a061caea43a38fed61adb7 (diff)
[PATCH] ahci: add support for VIA VT8251
Adds AHCI support for the VIA VT8251. Includes a workaround for a hardware bug which requires a Command List Override before softreset. Signed-off-by: Bastiaan Jacques <b.jacques@planet.nl> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/ahci.c64
1 files changed, 49 insertions, 15 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 1b8429cb3c9..d23f00230a7 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -73,6 +73,7 @@ enum {
73 RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ 73 RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
74 74
75 board_ahci = 0, 75 board_ahci = 0,
76 board_ahci_vt8251 = 1,
76 77
77 /* global controller registers */ 78 /* global controller registers */
78 HOST_CAP = 0x00, /* host capabilities */ 79 HOST_CAP = 0x00, /* host capabilities */
@@ -153,6 +154,9 @@ enum {
153 154
154 /* hpriv->flags bits */ 155 /* hpriv->flags bits */
155 AHCI_FLAG_MSI = (1 << 0), 156 AHCI_FLAG_MSI = (1 << 0),
157
158 /* ap->flags bits */
159 AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24),
156}; 160};
157 161
158struct ahci_cmd_hdr { 162struct ahci_cmd_hdr {
@@ -255,6 +259,16 @@ static const struct ata_port_info ahci_port_info[] = {
255 .udma_mask = 0x7f, /* udma0-6 ; FIXME */ 259 .udma_mask = 0x7f, /* udma0-6 ; FIXME */
256 .port_ops = &ahci_ops, 260 .port_ops = &ahci_ops,
257 }, 261 },
262 /* board_ahci_vt8251 */
263 {
264 .sht = &ahci_sht,
265 .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
266 ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
267 AHCI_FLAG_RESET_NEEDS_CLO,
268 .pio_mask = 0x1f, /* pio0-4 */
269 .udma_mask = 0x7f, /* udma0-6 ; FIXME */
270 .port_ops = &ahci_ops,
271 },
258}; 272};
259 273
260static const struct pci_device_id ahci_pci_tbl[] = { 274static const struct pci_device_id ahci_pci_tbl[] = {
@@ -296,6 +310,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
296 board_ahci }, /* ATI SB600 non-raid */ 310 board_ahci }, /* ATI SB600 non-raid */
297 { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 311 { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
298 board_ahci }, /* ATI SB600 raid */ 312 board_ahci }, /* ATI SB600 raid */
313 { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
314 board_ahci_vt8251 }, /* VIA VT8251 */
299 { } /* terminate list */ 315 { } /* terminate list */
300}; 316};
301 317
@@ -516,9 +532,29 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
516 pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16); 532 pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
517} 533}
518 534
519static int ahci_softreset(struct ata_port *ap, unsigned int *class) 535static int ahci_clo(struct ata_port *ap)
520{ 536{
537 void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
521 struct ahci_host_priv *hpriv = ap->host_set->private_data; 538 struct ahci_host_priv *hpriv = ap->host_set->private_data;
539 u32 tmp;
540
541 if (!(hpriv->cap & HOST_CAP_CLO))
542 return -EOPNOTSUPP;
543
544 tmp = readl(port_mmio + PORT_CMD);
545 tmp |= PORT_CMD_CLO;
546 writel(tmp, port_mmio + PORT_CMD);
547
548 tmp = ata_wait_register(port_mmio + PORT_CMD,
549 PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
550 if (tmp & PORT_CMD_CLO)
551 return -EIO;
552
553 return 0;
554}
555
556static int ahci_softreset(struct ata_port *ap, unsigned int *class)
557{
522 struct ahci_port_priv *pp = ap->private_data; 558 struct ahci_port_priv *pp = ap->private_data;
523 void __iomem *mmio = ap->host_set->mmio_base; 559 void __iomem *mmio = ap->host_set->mmio_base;
524 void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 560 void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
@@ -547,21 +583,13 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
547 /* check BUSY/DRQ, perform Command List Override if necessary */ 583 /* check BUSY/DRQ, perform Command List Override if necessary */
548 ahci_tf_read(ap, &tf); 584 ahci_tf_read(ap, &tf);
549 if (tf.command & (ATA_BUSY | ATA_DRQ)) { 585 if (tf.command & (ATA_BUSY | ATA_DRQ)) {
550 if (!(hpriv->cap & HOST_CAP_CLO)) { 586 rc = ahci_clo(ap);
551 rc = -EIO;
552 reason = "port busy but no CLO";
553 goto fail_restart;
554 }
555
556 tmp = readl(port_mmio + PORT_CMD);
557 tmp |= PORT_CMD_CLO;
558 writel(tmp, port_mmio + PORT_CMD);
559 587
560 tmp = ata_wait_register(port_mmio + PORT_CMD, 588 if (rc == -EOPNOTSUPP) {
561 PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); 589 reason = "port busy but CLO unavailable";
562 if (tmp & PORT_CMD_CLO) { 590 goto fail_restart;
563 rc = -EIO; 591 } else if (rc) {
564 reason = "CLO failed"; 592 reason = "port busy but CLO failed";
565 goto fail_restart; 593 goto fail_restart;
566 } 594 }
567 } 595 }
@@ -672,6 +700,12 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class)
672 700
673static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes) 701static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
674{ 702{
703 if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
704 (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
705 /* ATA_BUSY hasn't cleared, so send a CLO */
706 ahci_clo(ap);
707 }
708
675 return ata_drive_probe_reset(ap, ata_std_probeinit, 709 return ata_drive_probe_reset(ap, ata_std_probeinit,
676 ahci_softreset, ahci_hardreset, 710 ahci_softreset, ahci_hardreset,
677 ahci_postreset, classes); 711 ahci_postreset, classes);