Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 Jan 1998 04:43:48 +1100
From:      Bruce Evans <bde@zeta.org.au>
To:        bde@zeta.org.au, mike@smith.net.au
Cc:        cvs-committers@FreeBSD.ORG, msmith@FreeBSD.ORG
Subject:   Re: cvs commit: src/sys/i386/isa atapi.c
Message-ID:  <199801281743.EAA15033@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>The Zip is, as I said, slow off the bus.  At least on the P6 I was 
>using, it goes like this (PC98 junk elided):
>
>        /* Wait for controller not busy. */
>        outb (port + AR_DRIVE, unit ? ARD_DRIVE1 : ARD_DRIVE0);
>        if (atapi_wait (port, 0) < 0) {

I complain about some other points while I'm here:
- There is no wait before the first outb.  It is invalid to access the
  "Command block" registers while BSY is set.
- The comment doesn't apply to the code that immediately follows it.
  The PC98 ifdef moves it further from the code that it applies to.

>## Zip is still on the bus here; atapi_wait() returns happily thinking 
>## there is a device present and ready.  A possibly better fix would be 
>## to have the 10us delay earlier in the loop in atapi_wait().

Does atapi_wait() really return early here?  You didn't change anything
here.

>        /* Issue ATAPI IDENTIFY command. */
>        outb (port + AR_DRIVE, unit ? ARD_DRIVE1 : ARD_DRIVE0);
>        outb (port + AR_COMMAND, ATAPIC_IDENTIFY);

- OK if Zip follows spec, since we waited.  Since we reselect the drive
  here, not waiting earlier is probably harmless.  Selecting it earlier
  may be to hide a bug somehere.
- The PC98 code waits for DRQ to be deasserted between the above 2 outb's
  this may be to hide the bug related to stale DRQs in atapi_wait() (if
  BSY and DRQ are both stale (and wrong), then atapi_wait() returns
  early).

>        /* Check that device is present. */
>        if (inb (port + AR_STATUS) == 0xff) {

- Bogus.  The device had better be there since we have written a lot to
  its registers.  atapi_wait() has just succeeded, so its status was
  not 0xff when it was read before the command was issued (ARS_BSY was
  clear).  The value just read is invalid since we didn't wait 400 nsec.

>## Zip is going off the bus at this point, but not gone.
>## Read returns 0xa1.

I see, you think 0xa1 is an echo of the value just read.  It happens to
be valid but not reasonable as a status value, since it is ARS_BSY |
ARS_DF | ARS_CHECK, and a drive fault or error probably won't occur this
fast.  The drive is probably within spec if it gets off the bus within
400 nsec.  A non-buggy driver couldn't tell the difference, because the
ARS_BSY bit is invalid until 400 nsec after the command is issued.

The bogus inb() probably helps because it delays for >= 400 nsec.  What
does the next inb() return?

>        /* Wait for data ready. */
>        if (atapi_wait (port, ARS_DRQ) != 0) {
>
>## Zip eventually goes off the bus, and thus DRQ reads high.

I don't think this has anything to do with the bus.  The Zip has been
assembling the reply somewhere.  After finishing of up to 700 nsec before,
it sets DRQ, which atapi_wait() reads a little later, up to 700 nsec
before the Zip clears BSY to indicate that it has finished, not to mention
that DRQ is valid.

>At this point the probe thinks it has a device that's responded to the 
>IDENTIFY.  The Zip is off having a beer, and the result is a garbage 
>probe.  The easiest fix at the time was to simply catch the obviously 
>nonsense case where the status register reads 0xff *after* waiting for 
>DRQ.

Did it actually read as 0xff?  This is possible, since BSY is not checked
for.

>> Perhaps the problem is earlier.  According to an old draft version of
>> the ATA spec, the timing for issueing a polled-mode input command is:

>0.0	Select the target
>0.5	Wait XXX<units) for drive to respond to selection, or poll 
>	(some register) to indicate drive is selected.

I think it's actually the polling of DRQ without checking BSY (step 9
or 10), which is most likely to cause problems if the drive is smart
enough to set DRQ 700 nsec in advance of becoming ready, to give drivers
advance notice.  Advance warning is especially useful for interrupt-driven
i/o - if the interrupt occurs with DRQ 700 nsec before BSY, then latency
is reduced by 700 nsec and BSY will probably be set when the interrupt
handler is reached.  OTOH, the lpt driver loses because some printers
give too much advance warning so that BSY isn't clear when the interrupt
handler is reached.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199801281743.EAA15033>