Date: Tue, 4 Mar 2003 16:44:53 -0800 From: "Luoqi Chen" <lchen@briontech.com> To: "David Xu" <davidxu@FreeBSD.ORG>, <current@FreeBSD.ORG> Subject: RE: ATA MODE_SENSE_BIG timeout Message-ID: <AHEKICEOIHLOGINAFIINCENOCAAA.lchen@briontech.com> In-Reply-To: <003701c2e208$12fde4c0$f001a8c0@davidw2k>
next in thread | previous in thread | raw e-mail | index | archive | help
> For those want to fix ATA code, I have another problem > with CURRENT. I have a Tyan Tiger 230T which is based > on VIA Apollo 133T, south bridge is VIA 686B. > On second IDE, I have a Mitsubishi 52X cdrom as master, > and a Sony 16X CD R/W as slave, when startup, kernel > is always stuck at "MODE_SENSE_BIG timeout". > I fortunately catched the dmesg text since ATA code past the > probing stage. In most case, it will be stuck there forever. > BTW, both Linux (2.2.14, Redhat) and MS Windows can probe > these devices in few seconds without any problem. > I had more than a few machines behaved this way. I believe the problem is with the probe and attach sequence of our ata driver. After an ATA reset, according to spec, an ATAPI device is supposed to present the ATAPI signature and deassert the ready bit, until it receives its first packet command. However when the ata driver issues the first mode sense command, it polls first for the ready bit which never becomes set and the operation times out. The most obviously solution is sending the first command without checking for the ready bit. My solution is a little different, but works equally well, instead I issue an ATAPI reset (what now called a device reset?), because I don't want to write another or alter the current ata_command function and we need an atapi_reset function anyway. According spec, atapi devices SHOULD ONLY be reset via the atapi reset command (our ata driver doesn't follow this rule). The patch is for -stable. I hope it's not too difficult to port to -current. -lq Index: atapi-all.c =================================================================== RCS file: /home/ncvs/src/sys/dev/ata/atapi-all.c,v retrieving revision 1.46.2.18 diff -u -r1.46.2.18 atapi-all.c --- atapi-all.c 31 Oct 2002 23:10:33 -0000 1.46.2.18 +++ atapi-all.c 19 Dec 2002 19:59:20 -0000 @@ -48,6 +48,7 @@ #include <dev/ata/atapi-all.h> /* prototypes */ +static void atapi_reset(struct ata_device *); static void atapi_read(struct atapi_request *, int); static void atapi_write(struct atapi_request *, int); static void atapi_finish(struct atapi_request *); @@ -77,6 +78,7 @@ ata_umode(atadev->param), atadev->param->support_dma); ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL); + atapi_reset(atadev); if (atapi_dma && !(atadev->param->drq_type == ATAPI_DRQT_INTR)) { ata_dmainit(atadev->channel, atadev->unit, (ata_pmode(atadev->param) < 0) ? @@ -483,6 +485,8 @@ void atapi_reinit(struct ata_device *atadev) { + atapi_reset(atadev); + /* reinit device parameters */ if (atadev->mode >= ATA_DMA) ata_dmainit(atadev->channel, atadev->unit, @@ -536,6 +540,43 @@ } static void +atapi_reset(struct ata_device *atadev) +{ + struct ata_channel *ch = atadev->channel; + u_int8_t stat, lsb, msb; + int timeout; + + ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | atadev->unit); + DELAY(10); + ATA_OUTB(ch->r_altio, ATA_ALTSTAT, ATA_A_4BIT | ATA_A_IDS); + DELAY(10); + ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | atadev->unit); + DELAY(10); + ATA_OUTB(ch->r_io, ATA_CMD, ATA_C_ATAPI_RESET); + + for (timeout = 10000; timeout; timeout--) { + DELAY(100); + ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | atadev->unit); + DELAY(10); + lsb = ATA_INB(ch->r_io, ATA_CYL_LSB); + msb = ATA_INB(ch->r_io, ATA_CYL_MSB); + stat = ATA_INB(ch->r_io, ATA_STATUS); + if ((stat & ATA_S_BUSY) == 0) + break; + } + + if (bootverbose) + ata_prtdev(atadev, "stat %x, lsb %x, msb %x\n", stat, lsb, msb); + + if (timeout == 0) + ata_prtdev(atadev, "soft reset failed\n"); + + ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | atadev->unit); + DELAY(10); + ATA_OUTB(ch->r_altio, ATA_ALTSTAT, ATA_A_4BIT); +} + +static void atapi_read(struct atapi_request *request, int length) { int8_t **buffer = (int8_t **)&request->data; @@ -617,10 +658,13 @@ { struct ata_device *atadev = request->device; + ATA_FORCELOCK_CH(atadev->channel, ATA_CONTROL); atadev->channel->running = NULL; ata_prtdev(atadev, "%s command timeout - resetting\n", atapi_cmd2str(request->ccb[0])); + atapi_reset(atadev); + if (request->flags & ATPR_F_DMA_USED) { ata_dmadone(atadev->channel); if (request->retries == ATAPI_MAX_RETRIES) { @@ -631,17 +675,20 @@ request->retries = 0; } } + ATA_UNLOCK_CH(atadev->channel); /* if retries still permit, reinject this request */ if (request->retries++ < ATAPI_MAX_RETRIES) { + int s = splbio(); TAILQ_INSERT_HEAD(&atadev->channel->atapi_queue, request, chain); + ata_start(atadev->channel); + splx(s); } else { /* retries all used up, return error */ request->error = EIO; wakeup((caddr_t)request); } - ata_reinit(atadev->channel); } static char * To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?AHEKICEOIHLOGINAFIINCENOCAAA.lchen>