diff options
author | Alexander Motin <mav@FreeBSD.org> | 2010-09-02 11:18:43 +0000 |
---|---|---|
committer | Alexander Motin <mav@FreeBSD.org> | 2010-09-02 11:18:43 +0000 |
commit | a250a687f75ef4acd6d863e68ea292c071b2ed28 (patch) | |
tree | fa7b44864889fb34eeeb135d1f76d109f7029794 /sys/dev | |
parent | a1482dccab8920a402aa22dbebcd524c1a6f6d89 (diff) | |
download | src-a250a687f75ef4acd6d863e68ea292c071b2ed28.tar.gz src-a250a687f75ef4acd6d863e68ea292c071b2ed28.zip |
SATA1.x SiliconImage controllers on power-on reset TFD Status register into
value 0xff. On hot-plug this value confuses ata_generic_reset() device
presence detection logic. As soon as we already know drive presence from
SATA hard reset, hint ata_generic_reset() to wait for device signature
until success or full timeout.
Notes
Notes:
svn path=/head/; revision=212145
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ata/ata-all.h | 1 | ||||
-rw-r--r-- | sys/dev/ata/ata-lowlevel.c | 30 | ||||
-rw-r--r-- | sys/dev/ata/chipsets/ata-siliconimage.c | 1 |
3 files changed, 15 insertions, 17 deletions
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 87226cc11f27..6132eab41017 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -565,6 +565,7 @@ struct ata_channel { #define ATA_NO_ATAPI_DMA 0x40 #define ATA_SATA 0x80 #define ATA_DMA_BEFORE_CMD 0x100 +#define ATA_KNOWN_PRESENCE 0x200 int pm_level; /* power management level */ int devices; /* what is present */ diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c index 6c196d60a442..91748233e5ce 100644 --- a/sys/dev/ata/ata-lowlevel.c +++ b/sys/dev/ata/ata-lowlevel.c @@ -474,7 +474,8 @@ ata_generic_reset(device_t dev) ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER)); DELAY(10); ostat0 = ATA_IDX_INB(ch, ATA_STATUS); - if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) { + if (((ostat0 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) && + ostat0 != 0xa5) { stat0 = ATA_S_BUSY; mask |= 0x01; } @@ -484,7 +485,8 @@ ata_generic_reset(device_t dev) ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_SLAVE)); DELAY(10); ostat1 = ATA_IDX_INB(ch, ATA_STATUS); - if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { + if (((ostat1 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) && + ostat1 != 0xa5) { stat1 = ATA_S_BUSY; mask |= 0x02; } @@ -570,22 +572,16 @@ ata_generic_reset(device_t dev) } } - if (mask == 0x00) /* nothing to wait for */ - break; - if (mask == 0x01) /* wait for master only */ - if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 10)) - break; - if (mask == 0x02) /* wait for slave only */ - if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 10)) - break; - if (mask == 0x03) { /* wait for both master & slave */ - if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) - break; - if ((stat0 == 0xff) && (timeout > 20)) - mask &= ~0x01; - if ((stat1 == 0xff) && (timeout > 20)) - mask &= ~0x02; + if ((ch->flags & ATA_KNOWN_PRESENCE) == 0 && + timeout > ((mask == 0x03) ? 20 : 10)) { + if ((mask & 0x01) && stat0 == 0xff) + mask &= ~0x01; + if ((mask & 0x02) && stat1 == 0xff) + mask &= ~0x02; } + if (((mask & 0x01) == 0 || !(stat0 & ATA_S_BUSY)) && + ((mask & 0x02) == 0 || !(stat1 & ATA_S_BUSY))) + break; ata_udelay(100000); } diff --git a/sys/dev/ata/chipsets/ata-siliconimage.c b/sys/dev/ata/chipsets/ata-siliconimage.c index 31d1878a1105..ff22f070d2e5 100644 --- a/sys/dev/ata/chipsets/ata-siliconimage.c +++ b/sys/dev/ata/chipsets/ata-siliconimage.c @@ -316,6 +316,7 @@ ata_sii_ch_attach(device_t dev) ch->r_io[ATA_SCONTROL].offset = 0x100 + (unit01 << 7) + (unit10 << 8); ch->flags |= ATA_NO_SLAVE; ch->flags |= ATA_SATA; + ch->flags |= ATA_KNOWN_PRESENCE; /* enable PHY state change interrupt */ ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16)); |