diff options
author | Alexander Motin <mav@FreeBSD.org> | 2011-06-09 16:30:13 +0000 |
---|---|---|
committer | Alexander Motin <mav@FreeBSD.org> | 2011-06-09 16:30:13 +0000 |
commit | 0eac2d6be34c5e02b6a0b5157ba3d6c69003cd65 (patch) | |
tree | da4d7629b138a6f5faec3770540eae5953377660 /sys/dev/ata | |
parent | 3f6c8f3765d721ab95dd104ded83f4363c538695 (diff) | |
download | src-0eac2d6be34c5e02b6a0b5157ba3d6c69003cd65.tar.gz src-0eac2d6be34c5e02b6a0b5157ba3d6c69003cd65.zip |
Intel NM10 chipset's SATA controller has same PCI ID and revision as ICH7's,
but has only 2 SATA ports instead of 4. The worst part is that SStatus and
SError registers for missing ports are not implemented and return wrong
values (0xffffffff), that caused infinite reset loop.
Just ignore that SError value while I found no better way to identify them.
Notes
Notes:
svn path=/head/; revision=222897
Diffstat (limited to 'sys/dev/ata')
-rw-r--r-- | sys/dev/ata/ata-sata.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/sys/dev/ata/ata-sata.c b/sys/dev/ata/ata-sata.c index e95fc8fcf208..1ddf238f2e6c 100644 --- a/sys/dev/ata/ata-sata.c +++ b/sys/dev/ata/ata-sata.c @@ -54,6 +54,11 @@ ata_sata_phy_check_events(device_t dev, int port) u_int32_t error, status; ata_sata_scr_read(ch, port, ATA_SERROR, &error); + + /* Check that SError value is sane. */ + if (error == 0xffffffff) + return; + /* Clear set error bits/interrupt. */ if (error) ata_sata_scr_write(ch, port, ATA_SERROR, error); @@ -163,18 +168,18 @@ ata_sata_phy_reset(device_t dev, int port, int quick) if (bootverbose) { if (port < 0) { - device_printf(dev, "hardware reset ...\n"); + device_printf(dev, "hard reset ...\n"); } else { - device_printf(dev, "p%d: hardware reset ...\n", port); + device_printf(dev, "p%d: hard reset ...\n", port); } } for (retry = 0; retry < 10; retry++) { for (loop = 0; loop < 10; loop++) { if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET)) - return (0); + goto fail; ata_udelay(100); if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) - return (0); + goto fail; if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_RESET) break; } @@ -183,15 +188,26 @@ ata_sata_phy_reset(device_t dev, int port, int quick) if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_IDLE | ((ch->pm_level > 0) ? 0 : ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER))) - return (0); + goto fail; ata_udelay(100); if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) - return (0); + goto fail; if ((val & ATA_SC_DET_MASK) == 0) return ata_sata_connect(ch, port, 0); } } - return 0; +fail: + /* Clear SATA error register. */ + ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff); + + if (bootverbose) { + if (port < 0) { + device_printf(dev, "hard reset failed\n"); + } else { + device_printf(dev, "p%d: hard reset failed\n", port); + } + } + return (0); } int |