Subject: Re: kern/22869: Slave IDE drive not detected
To: Charles M. Hannum <abuse@spamalicious.com>
From: Manuel Bouyer <bouyer@antioche.eu.org>
List: tech-kern
Date: 09/23/2003 00:47:17
On Mon, Sep 22, 2003 at 11:33:24PM +0200, Manuel Bouyer wrote:
> On Mon, Sep 22, 2003 at 09:08:50PM +0000, Charles M. Hannum wrote:
> > 
> > Well, I tried the following change, and it helped a bit.  It prevents
> > trying to further probe the ghost on the laptop's primary bus.  It
> > also avoids waiting for BSY to clear on the bogus drive 1 with my CF
> > cards.  However, the real IDENTIFY command never manages to complete
> > on the CF cards now.  I'll look into this some more later.
> > 
> > 
> >[...]
> >  		[...]
> > @@ -362,13 +345,28 @@
> >  		 */
> >  		if (cl == 0x14 && ch == 0xeb) {
> >  			chp->ch_drive[drive].drive_flags |= DRIVE_ATAPI;
> > -		} else {
> > +			continue;
> > +		}
> > +		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_command,
> > +		    WDCC_IDENTIFY);
> 
> You need to wait for DRDY|DSC before issuing the command here

I added this to my tree (with my atabus changes), just after the return from
__wdcprobe() (in the current tree, this would be in wdcattach()),
which helps a lot. As with atabus kernel thread we do this in parallel for
all busses, we're down to 3s to detect the ghosts, independant from the
number of busses.
We still may need special handling for ATAPI devices, but on my test box,
the bus with one atapi device doesn't show any wait because the device
doesn't send its registers content when device 1 is selected.
I'll have to check if other ATAPI devices I have behaves the same way.

	/* for ATA/OLD drives, wait for DRDY, 3s timeout */
	for (i = 0; i < mstohz(3000); i++) {
		if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
			chp->wdc->select(chp,0);
		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
		    WDSD_IBM);
		delay(10);
		st0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
		
		if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
			chp->wdc->select(chp,1);
		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
		    WDSD_IBM | 0x10);
		delay(10);
		st1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
	
		if (((chp->ch_drive[0].drive_flags & (DRIVE_ATA|DRIVE_OLD))
			== 0 ||
		    (st0 & WDCS_DRDY)) &&
		    ((chp->ch_drive[1].drive_flags & (DRIVE_ATA|DRIVE_OLD))
			== 0 ||
		    (st1 & WDCS_DRDY)))
			break;
		tsleep(&atabus_sc, PRIBIO, "atadrdy", 1);
	}
	if ((st0 & WDCS_DRDY) == 0)
		chp->ch_drive[0].drive_flags &= ~(DRIVE_ATA|DRIVE_OLD);
	if ((st1 & WDCS_DRDY) == 0)
		chp->ch_drive[1].drive_flags &= ~(DRIVE_ATA|DRIVE_OLD);

	WDCDEBUG_PRINT(("%s:%d: wait DRDY st0 0x%x st1 0x%x\n",
	    chp->wdc->sc_dev.dv_xname,
	    chp->channel, st0, st1), DEBUG_PROBE);

-- 
Manuel Bouyer <bouyer@antioche.eu.org>
     NetBSD: 24 ans d'experience feront toujours la difference
--