diff options
author | Greg Felix <gregfelixlkml@gmail.com> | 2005-07-28 15:54:15 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-07-28 15:54:15 -0400 |
commit | 7b6dbd6872ca1d0c03dc0e0a7108d79c8dafa793 (patch) | |
tree | 54160c4c0aa0970d3daa8b9a8f40c7a31f9527fe /drivers/scsi | |
parent | 6b6a93c6876ea1c530d5d3f68e3678093a27fab0 (diff) |
libata: Check PCI sub-class code before disabling AHCI
This patch adds functionality to check the PCI sub-class code of an
AHCI capable device before disabling AHCI. It fixes a bug where an
ICH7 sata controller is being setup by the BIOS as sub-class 1 (ide)
and the AHCI control registers weren't being initialized, thus causing
an IO error in piix_disable_ahci().
Signed-off-by: Gregory Felix <greg.felix@gmail.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ata_piix.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 3be546439252..a2cfade2c1c6 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c | |||
@@ -38,6 +38,7 @@ enum { | |||
38 | PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ | 38 | PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ |
39 | ICH5_PMR = 0x90, /* port mapping register */ | 39 | ICH5_PMR = 0x90, /* port mapping register */ |
40 | ICH5_PCS = 0x92, /* port control and status */ | 40 | ICH5_PCS = 0x92, /* port control and status */ |
41 | PIIX_SCC = 0x0A, /* sub-class code register */ | ||
41 | 42 | ||
42 | PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */ | 43 | PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */ |
43 | PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ | 44 | PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ |
@@ -62,6 +63,8 @@ enum { | |||
62 | ich6_sata_rm = 4, | 63 | ich6_sata_rm = 4, |
63 | ich7_sata = 5, | 64 | ich7_sata = 5, |
64 | esb2_sata = 6, | 65 | esb2_sata = 6, |
66 | |||
67 | PIIX_AHCI_DEVICE = 6, | ||
65 | }; | 68 | }; |
66 | 69 | ||
67 | static int piix_init_one (struct pci_dev *pdev, | 70 | static int piix_init_one (struct pci_dev *pdev, |
@@ -574,11 +577,11 @@ static int piix_disable_ahci(struct pci_dev *pdev) | |||
574 | addr = pci_resource_start(pdev, AHCI_PCI_BAR); | 577 | addr = pci_resource_start(pdev, AHCI_PCI_BAR); |
575 | if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR)) | 578 | if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR)) |
576 | return 0; | 579 | return 0; |
577 | 580 | ||
578 | mmio = ioremap(addr, 64); | 581 | mmio = ioremap(addr, 64); |
579 | if (!mmio) | 582 | if (!mmio) |
580 | return -ENOMEM; | 583 | return -ENOMEM; |
581 | 584 | ||
582 | tmp = readl(mmio + AHCI_GLOBAL_CTL); | 585 | tmp = readl(mmio + AHCI_GLOBAL_CTL); |
583 | if (tmp & AHCI_ENABLE) { | 586 | if (tmp & AHCI_ENABLE) { |
584 | tmp &= ~AHCI_ENABLE; | 587 | tmp &= ~AHCI_ENABLE; |
@@ -588,7 +591,7 @@ static int piix_disable_ahci(struct pci_dev *pdev) | |||
588 | if (tmp & AHCI_ENABLE) | 591 | if (tmp & AHCI_ENABLE) |
589 | rc = -EIO; | 592 | rc = -EIO; |
590 | } | 593 | } |
591 | 594 | ||
592 | iounmap(mmio); | 595 | iounmap(mmio); |
593 | return rc; | 596 | return rc; |
594 | } | 597 | } |
@@ -626,9 +629,13 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
626 | port_info[1] = NULL; | 629 | port_info[1] = NULL; |
627 | 630 | ||
628 | if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { | 631 | if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { |
629 | int rc = piix_disable_ahci(pdev); | 632 | u8 tmp; |
630 | if (rc) | 633 | pci_read_config_byte(pdev, PIIX_SCC, &tmp); |
631 | return rc; | 634 | if (tmp == PIIX_AHCI_DEVICE) { |
635 | int rc = piix_disable_ahci(pdev); | ||
636 | if (rc) | ||
637 | return rc; | ||
638 | } | ||
632 | } | 639 | } |
633 | 640 | ||
634 | if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { | 641 | if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { |