aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ata
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2013-06-25 09:15:49 +0000
committerAlexander Motin <mav@FreeBSD.org>2013-06-25 09:15:49 +0000
commitf49c6198500675ad772f35e9b6421e0ee9873f9e (patch)
tree8458ff41f01f7b51ec0f627672e20bb117e64585 /sys/dev/ata
parent277a6250852181e47ea6ae1fa40c7024f0fb335c (diff)
downloadsrc-f49c6198500675ad772f35e9b6421e0ee9873f9e.tar.gz
src-f49c6198500675ad772f35e9b6421e0ee9873f9e.zip
Add test for SATA registers writability and skip using them if it failed.
There are some systems reported, where PCI BAR(5), used for SATA registers access, is present, but not functional. Attempt to use it brakes devices detection logic. Try to detect those cases on attach by setting and testing some bits in SControl register. If bits are unsettable, fallback to legacy ATA without hot-plug detection, speed control/reporting, etc. MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=252203
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/chipsets/ata-intel.c35
1 files changed, 30 insertions, 5 deletions
diff --git a/sys/dev/ata/chipsets/ata-intel.c b/sys/dev/ata/chipsets/ata-intel.c
index 765af7cc366d..6a11a2372701 100644
--- a/sys/dev/ata/chipsets/ata-intel.c
+++ b/sys/dev/ata/chipsets/ata-intel.c
@@ -72,6 +72,7 @@ static int ata_intel_sata_cscr_write(device_t dev, int port,
int reg, u_int32_t result);
static int ata_intel_sata_sidpr_write(device_t dev, int port,
int reg, u_int32_t result);
+static int ata_intel_sata_sidpr_test(device_t dev);
static int ata_intel_31244_ch_attach(device_t dev);
static int ata_intel_31244_ch_detach(device_t dev);
static int ata_intel_31244_status(device_t dev);
@@ -416,22 +417,20 @@ ata_intel_ch_attach(device_t dev)
}
if (ch->flags & ATA_SATA) {
if ((ctlr->chip->cfg1 & INTEL_ICH5)) {
- ch->flags |= ATA_PERIODIC_POLL;
- ch->hw.status = ata_intel_sata_status;
ch->hw.pm_read = ata_intel_sata_cscr_read;
ch->hw.pm_write = ata_intel_sata_cscr_write;
} else if (ctlr->r_res2) {
- ch->flags |= ATA_PERIODIC_POLL;
- ch->hw.status = ata_intel_sata_status;
if ((ctlr->chip->cfg1 & INTEL_ICH7)) {
ch->hw.pm_read = ata_intel_sata_ahci_read;
ch->hw.pm_write = ata_intel_sata_ahci_write;
- } else {
+ } else if (ata_intel_sata_sidpr_test(dev)) {
ch->hw.pm_read = ata_intel_sata_sidpr_read;
ch->hw.pm_write = ata_intel_sata_sidpr_write;
};
}
if (ch->hw.pm_write != NULL) {
+ ch->flags |= ATA_PERIODIC_POLL;
+ ch->hw.status = ata_intel_sata_status;
ata_sata_scr_write(ch, 0,
ATA_SERROR, 0xffffffff);
if ((ch->flags & ATA_NO_SLAVE) == 0) {
@@ -835,6 +834,32 @@ ata_intel_sata_sidpr_write(device_t dev, int port, int reg, u_int32_t value)
}
static int
+ata_intel_sata_sidpr_test(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ int port;
+ uint32_t val;
+
+ port = (ch->flags & ATA_NO_SLAVE) ? 0 : 1;
+ for (; port >= 0; port--) {
+ ata_intel_sata_sidpr_read(dev, port, ATA_SCONTROL, &val);
+ if ((val & ATA_SC_IPM_MASK) ==
+ (ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER))
+ return (1);
+ val |= ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER;
+ ata_intel_sata_sidpr_write(dev, port, ATA_SCONTROL, val);
+ ata_intel_sata_sidpr_read(dev, port, ATA_SCONTROL, &val);
+ if ((val & ATA_SC_IPM_MASK) ==
+ (ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER))
+ return (1);
+ }
+ if (bootverbose)
+ device_printf(dev,
+ "SControl registers are not functional: %08x\n", val);
+ return (0);
+}
+
+static int
ata_intel_31244_ch_attach(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));