> 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 [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message

Reply via email to