diff options
| -rw-r--r-- | drivers/scsi/ahci.c | 64 |
1 files changed, 49 insertions, 15 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 1b8429cb3c96..d23f00230a76 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 | ||
| 158 | struct ahci_cmd_hdr { | 162 | struct 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 | ||
| 260 | static const struct pci_device_id ahci_pci_tbl[] = { | 274 | static 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 | ||
| 519 | static int ahci_softreset(struct ata_port *ap, unsigned int *class) | 535 | static 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 | |||
| 556 | static 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 | ||
| 673 | static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes) | 701 | static 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); |
