Date: Thu, 16 Oct 2003 23:17:47 +0900 From: Hiroyuki Aizu <eyes@navi.org> To: current@freebsd.org Subject: PATCH for ATAng Message-ID: <20031016231747.4f0640e3.eyes@navi.org>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Hi.
The original ata_reset() lost ATA-master drive and remove main file system
after suspend/resume. Of cource it occors panic!
I think that the ata_reset() in ata-lowlevel.c is bogus and I can not
understand the code. So I study ATA and rewrite ata_reset() completely.
New device detect algorism using ata command ATA_IDENTIFY_DEVICE and
ATA_IDENTIFY_PACKET_DEVICE for judge ATA and ATAPI devices.
This patch works fine with my TOSHIBA Libretto L5.
But not yet test ATAPI devices and ATA-slave channel.
Maybe there is need to adjust wait DELAY time.
Please test and replace ata_reset().
I hope this solve ATAng troubles.
--
Hiroyuki Aizu
[-- Attachment #2 --]
--- ata-lowlevel.c.orig Thu Oct 9 23:33:06 2003
+++ ata-lowlevel.c Thu Oct 16 22:28:06 2003
@@ -488,162 +488,222 @@
}
/* must be called with ATA channel locked */
-static void
-ata_reset(struct ata_channel *ch)
+#define ATA_TIMEOUT 10000
+#define ATA_IDENTIFY_DEVICE 0xec
+#define ATA_IDENTIFY_PACKET_DEVICE 0xa1
+
+#define ATA_MASTER_MASK (ATA_ATA_MASTER | ATA_ATAPI_MASTER)
+#define ATA_SLAVE_MASK (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)
+
+static int
+ata_wait_ready(struct ata_channel *ch)
{
- u_int8_t err, lsb, msb, ostat0, ostat1;
- u_int8_t stat0 = 0, stat1 = 0;
- int mask = 0, timeout;
+ int i, stat;
- /* do we have any signs of ATA/ATAPI HW being present ? */
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
- DELAY(10);
- ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
- if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
- stat0 = ATA_S_BUSY;
- mask |= 0x01;
- }
-
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
- DELAY(10);
- ostat1 = ATA_IDX_INB(ch, ATA_STATUS);
-
- /* in some setups we dont want to test for a slave */
- if (!(ch->flags & ATA_NO_SLAVE)) {
- if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) {
- stat1 = ATA_S_BUSY;
- mask |= 0x02;
- }
+ for (i = 0; i< ATA_TIMEOUT; i++) {
+ DELAY(10);
+ stat = ATA_IDX_INB(ch, ATA_STATUS);
+ if (!(stat & ATA_S_BUSY) && !(stat & ATA_S_DRQ))
+ break;
}
+ DELAY(10);
- /* if nothing showed up no need to get any further */
- /* SOS is that too strong?, we just might loose devices here XXX */
- ch->devices = 0;
- if (!mask)
- return;
+ if (i == ATA_TIMEOUT)
+ return -1;
- if (bootverbose)
- ata_printf(ch, -1, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n",
- mask, ostat0, ostat1);
+ return 0;
+}
+
+static int
+ata_soft_reset(struct ata_channel *ch)
+{
+ int i, stat;
/* reset channel */
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
- DELAY(10);
ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET);
DELAY(10000);
ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS);
- DELAY(10000);
+ DELAY(20000);
+
+ for (i = 0; i< ATA_TIMEOUT; i++) {
+ DELAY(100);
+ /* stat = ATA_IDX_INB(ch, ATA_STATUS); */
+ stat = ATA_IDX_INB(ch, ATA_ALTSTAT);
+ if (!(stat & ATA_S_BUSY))
+ break;
+ }
+ if (i == ATA_TIMEOUT)
+ return -1;
+
+ DELAY(10);
+
+ return 0;
+}
+
+static int
+ata_device_select(struct ata_channel *ch, u_int8_t unit)
+{
+ if (ata_wait_ready(ch))
+ return -1;
+
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | unit);
+ DELAY(10);
+
+ if (ata_wait_ready(ch))
+ return -1;
+
+ return 0;
+}
+
+static int
+ata_check_device_existence(struct ata_channel *ch)
+{
+ u_int8_t lsb, msb;
+
+ ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0x55);
+ ATA_IDX_OUTB(ch, ATA_CYL_MSB, 0xaa);
+
+ lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
+ msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
+
+ if (lsb != 0x55 || msb != 0xaa) {
+ /* not found */
+ ata_printf(ch, -1, "check dev existence:lsb=%02x msb=%02x\n", lsb, msb);
+ return 0;
+ }
+
+ /* found */
+ return 1;
+}
+
+static int
+identify_device(struct ata_channel *ch, int device, u_int8_t type)
+{
+ int i, j;
+ u_int8_t stat;
+
+ ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS);
+
+ ATA_IDX_OUTB(ch, ATA_FEATURE, 0);
+ ATA_IDX_OUTB(ch, ATA_COUNT, 0);
+ ATA_IDX_OUTB(ch, ATA_SECTOR, 0);
+ ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0);
+ ATA_IDX_OUTB(ch, ATA_CYL_MSB, 0);
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | device);
+ ATA_IDX_OUTB(ch, ATA_CMD, type);
+ DELAY(10);
- /* wait for BUSY to go inactive */
- for (timeout = 0; timeout < 310; timeout++) {
- if (stat0 & ATA_S_BUSY) {
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
- DELAY(10);
- err = ATA_IDX_INB(ch, ATA_ERROR);
- lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
- msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
- stat0 = ATA_IDX_INB(ch, ATA_STATUS);
- if (bootverbose)
- ata_printf(ch, ATA_MASTER,
- "stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
- stat0, err, lsb, msb);
- if (!(stat0 & ATA_S_BUSY)) {
- if ((err & 0x7f) == ATA_E_ILI) {
- if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
- ch->devices |= ATA_ATAPI_MASTER;
- }
- else if (stat0 & ATA_S_READY) {
- ch->devices |= ATA_ATA_MASTER;
- }
- }
- else if ((stat0 & 0x4f) && err == lsb && err == msb) {
- stat0 |= ATA_S_BUSY;
- }
- }
- }
- if (stat1 & ATA_S_BUSY) {
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
- DELAY(10);
- err = ATA_IDX_INB(ch, ATA_ERROR);
- lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
- msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
- stat1 = ATA_IDX_INB(ch, ATA_STATUS);
- if (bootverbose)
- ata_printf(ch, ATA_SLAVE,
- " stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
- stat1, err, lsb, msb);
- if (!(stat1 & ATA_S_BUSY)) {
- if ((err & 0x7f) == ATA_E_ILI) {
- if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
- ch->devices |= ATA_ATAPI_SLAVE;
- }
- else if (stat1 & ATA_S_READY) {
- ch->devices |= ATA_ATA_SLAVE;
- }
- }
- else if ((stat1 & 0x4f) && err == lsb && err == msb) {
- stat1 |= ATA_S_BUSY;
- }
- }
- }
- if (mask == 0x01) /* wait for master only */
- if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 20))
- break;
- if (mask == 0x02) /* wait for slave only */
- if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 20))
- break;
- if (mask == 0x03) /* wait for both master & slave */
- if ((!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 20)) &&
- (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 20)))
- break;
- DELAY(100000);
- }
-
- if (stat0 & ATA_S_BUSY)
- mask &= ~0x01;
- if (stat1 & ATA_S_BUSY)
- mask &= ~0x02;
+ ATA_IDX_INB(ch, ATA_ALTSTAT);
+
+ for (j = 0; j < ATA_TIMEOUT; j++) {
+ stat = ATA_IDX_INB(ch, ATA_ALTSTAT);
+ if (!(stat & ATA_S_BUSY))
+ break;
+ }
+ if (j == ATA_TIMEOUT) {
+ if (bootverbose)
+ ata_printf(ch, -1, "identify timeout %02x\n", stat);
+ return -1;
+ }
+
+ if (stat & ATA_S_ERROR) {
+ ATA_IDX_INB(ch, ATA_STATUS);
+ if (bootverbose)
+ ata_printf(ch, -1, "identify error %02x\n", stat);
+ return -1;
+ }
+
+ if (!(stat & ATA_S_DRQ)) {
+ ATA_IDX_INB(ch, ATA_STATUS);
+ if (bootverbose)
+ ata_printf(ch, -1, "identify drq %02x\n", stat);
+ return -1;
+ }
+
+ for (i = 0; i < 256; i++) {
+ ATA_IDX_INW(ch, ATA_DATA);
+ }
+
+ ATA_IDX_INB(ch, ATA_STATUS);
+ return 0;
+}
+
+static void
+ata_reset(struct ata_channel *ch)
+{
+ int mask = 0;
+ int devices = 0;
+ int ret;
+
+ ch->devices = 0;
+
+ /* reset */
+ if (ata_soft_reset(ch)) {
+ if (bootverbose)
+ ata_printf(ch, -1, "error or timeout while reset\n");
+ return;
+ }
+
+ /* check MASTER */
+ if (ata_device_select(ch, ATA_MASTER))
+ return;
+ ret = ata_check_device_existence(ch);
+ if (ret > 0) {
+ mask |= 0x01;
+ }
+
+ /* check SLAVE */
+ if (ata_device_select(ch, ATA_SLAVE))
+ return;
+ ret = ata_check_device_existence(ch);
+ if (ret > 0) {
+ mask |= 0x02;
+ }
+
+ /* ATA MASTER */
+ if (mask & 0x01) {
+ if (!ata_device_select(ch, ATA_MASTER))
+ if (!identify_device(ch, ATA_MASTER, ATA_IDENTIFY_DEVICE))
+ devices |= ATA_ATA_MASTER;
+ }
+
+ /* ATA SLAVE */
+ if (mask & 0x02) {
+ if (!ata_device_select(ch, ATA_SLAVE))
+ if (!identify_device(ch, ATA_SLAVE, ATA_IDENTIFY_DEVICE))
+ devices |= ATA_ATA_SLAVE;
+ }
if (bootverbose)
- ata_printf(ch, -1,
- "reset tp2 mask=%02x stat0=%02x stat1=%02x devices=0x%b\n",
- mask, stat0, stat1, ch->devices,
- "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
-#if 0
- if (!mask)
- return;
-
- if (mask & 0x01 && ostat0 != 0x00 &&
- !(ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER))) {
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
- DELAY(10);
- ATA_IDX_OUTB(ch, ATA_ERROR, 0x58);
- ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5);
- err = ATA_IDX_INB(ch, ATA_ERROR);
- lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
- if (bootverbose)
- ata_printf(ch, ATA_MASTER, "ATA err=0x%02x lsb=0x%02x\n", err, lsb);
- if (err != 0x58 && lsb == 0xa5)
- ch->devices |= ATA_ATA_MASTER;
- }
- if (mask & 0x02 && ostat1 != 0x00 &&
- !(ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE))) {
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
- DELAY(10);
- ATA_IDX_OUTB(ch, ATA_ERROR, 0x58);
- ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5);
- err = ATA_IDX_INB(ch, ATA_ERROR);
- lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
- if (bootverbose)
- ata_printf(ch, ATA_SLAVE, "ATA err=0x%02x lsb=0x%02x\n", err, lsb);
- if (err != 0x58 && lsb == 0xa5)
- ch->devices |= ATA_ATA_SLAVE;
+ ata_printf(ch, -1, "reset check ATA: devices=%02x\n", devices);
+
+ /* ATAPI MASTER */
+ if (mask & 0x01) {
+ if (!ata_device_select(ch, ATA_MASTER))
+ if (!identify_device(ch, ATA_MASTER, ATA_IDENTIFY_PACKET_DEVICE))
+ devices |= ATA_ATAPI_MASTER;
+ }
+
+ /* ATAPI SLAVE */
+ if (mask & 0x02) {
+ if (!ata_device_select(ch, ATA_SLAVE))
+ if (!identify_device(ch, ATA_SLAVE, ATA_IDENTIFY_PACKET_DEVICE))
+ devices |= ATA_ATAPI_SLAVE;
}
if (bootverbose)
- ata_printf(ch, -1, "reset tp3 devices=0x%b\n", ch->devices,
- "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
-#endif
+ ata_printf(ch, -1, "reset check ATAPI: devices=%02x\n", devices);
+
+ if (!((devices & ATA_ATA_MASTER) && (devices & ATA_ATAPI_MASTER)))
+ ch->devices |= (devices & ATA_MASTER_MASK);
+
+ if (!((devices & ATA_ATA_SLAVE) && (devices & ATA_ATAPI_SLAVE)))
+ ch->devices |= (devices & ATA_SLAVE_MASK);
+
+ if (bootverbose)
+ ata_printf(ch, -1, "reset check final: devices=%02x\n", ch->devices);
+
+ return;
}
static int
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20031016231747.4f0640e3.eyes>
