Subject: Re: kern/25659: drive not recognized because of delays
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Brian Buhrow <buhrow@lothlorien.nfbcal.org>
List: netbsd-bugs
Date: 04/21/2005 22:09:01
The following reply was made to PR kern/25659; it has been noted by GNATS.

From: buhrow@lothlorien.nfbcal.org (Brian Buhrow)
To: gnats-bugs@netbsd.org
Cc: buhrow@lothlorien.nfbcal.org
Subject: Re: kern/25659: drive not recognized because of delays
Date: Thu, 21 Apr 2005 15:08:21 -0700

 	Hello.  I'm finding that this problem plagues IDE drives attached to
 standard IDE controllers as well as the problem Steven outlines above. 
 Below is a patch to wdc.c which addresses the issues I'm seeing with a
 number of drives attached to Intel IDE controllers driven by the piixide(4)
 driver.
 	In general, I think wdc.c is a bit too trigger happy, and given the
 increasing speeds of processors, slowing it down a bit will lead to fewer
 failures to recognize attached drives.
 	The following patch is tested and works on production machines.  I
 hope this issue can be addressed before NetBSD-3 comes out.
 In the mean time, I hope someone finds this useful
 -Brian
 
 P.S.  This is patched against the netBSD-2-0 branch of the wdc.c file.
 
 
 Index: wdc.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/ic/wdc.c,v
 retrieving revision 1.172.2.7
 diff -u -r1.172.2.7 wdc.c
 --- wdc.c	17 Sep 2004 04:04:57 -0000	1.172.2.7
 +++ wdc.c	21 Apr 2005 20:56:30 -0000
 @@ -206,13 +206,13 @@
  	}
  
  	/* for ATA/OLD drives, wait for DRDY, 3s timeout */
 -	for (i = 0; i < mstohz(3000); i++) {
 +	for (i = 0; i < mstohz(9000); i++) {
  		if (chp->ch_drive[0].drive_flags & (DRIVE_ATA|DRIVE_OLD)) {
  			if (wdc != NULL && (wdc->cap & WDC_CAPABILITY_SELECT))
  				wdc->select(chp,0);
  			bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh],
  			    0, WDSD_IBM);
 -			delay(10);	/* 400ns delay */
 +			delay(40);	/* 400ns delay */
  			st0 = bus_space_read_1(chp->cmd_iot,
  			    chp->cmd_iohs[wd_status], 0);
  		}
 @@ -222,7 +222,7 @@
  				wdc->select(chp,1);
  			bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh],
  			    0, WDSD_IBM | 0x10);
 -			delay(10);	/* 400ns delay */
 +			delay(40);	/* 400ns delay */
  			st1 = bus_space_read_1(chp->cmd_iot,
  			    chp->cmd_iohs[wd_status], 0);
  		}
 @@ -246,7 +246,7 @@
  	    chp->ch_channel, st0, st1), DEBUG_PROBE);
  
  	/* Wait a bit, some devices are weird just after a reset. */
 -	delay(5000);
 +	delay(9000);
  
  	for (i = 0; i < 2; i++) {
  		/* XXX This should be done by other code. */
 @@ -503,7 +503,7 @@
  
  		bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0,
  		    WDSD_IBM);
 -		delay(10);	/* 400ns delay */
 +		delay(40);	/* 400ns delay */
  		st0 = bus_space_read_1(chp->cmd_iot,
  		    chp->cmd_iohs[wd_status], 0);
  		
 @@ -512,10 +512,11 @@
  
  		bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0,
  		    WDSD_IBM | 0x10);
 -		delay(10);	/* 400ns delay */
 +		delay(40);	/* 400ns delay */
  		st1 = bus_space_read_1(chp->cmd_iot,
  		    chp->cmd_iohs[wd_status], 0);
  
 +		delay(1000000);
  		WDCDEBUG_PRINT(("%s:%d: before reset, st0=0x%x, st1=0x%x\n",
  		    wdc != NULL ? wdc->sc_dev.dv_xname : "wdcprobe",
  		    chp->ch_channel, st0, st1), DEBUG_PROBE);
 @@ -700,17 +701,17 @@
  	if (wdc != NULL && (wdc->cap & WDC_CAPABILITY_SELECT))
  		wdc->select(chp,0);
  	bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0, WDSD_IBM);
 -	delay(10);	/* 400ns delay */
 +	delay(40);	/* 400ns delay */
  	/* assert SRST, wait for reset to complete */
  	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
  	    WDCTL_RST | WDCTL_IDS | WDCTL_4BIT); 
 -	DELAY(1000);
 +	DELAY(4000);
  	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
  	    WDCTL_IDS | WDCTL_4BIT);
 -	DELAY(2000);
 +	DELAY(8000);
  	(void) bus_space_read_1(chp->cmd_iot, chp->cmd_iohs[wd_error], 0);
  	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
 -	delay(10);	/* 400ns delay */
 +	delay(40);	/* 400ns delay */
  	/* ACK interrupt in case there is one pending left (Promise ATA100) */
  	if (wdc != NULL && (wdc->cap & WDC_CAPABILITY_IRQACK))
  		wdc->irqack(chp);
 @@ -738,7 +739,7 @@
  			wdc->select(chp,drive);
  		bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0,
  		    WDSD_IBM | (drive << 4));
 -		delay(10);	/* 400ns delay */
 +		delay(80);	/* 400ns delay */
  		/* Save registers contents */
  		sc = bus_space_read_1(chp->cmd_iot,
  		    chp->cmd_iohs[wd_seccnt], 0);
 @@ -1030,14 +1031,14 @@
  		s = splbio();
  	/* master */
  	bus_space_write_1(chp->cmd_iot, chp->cmd_iohs[wd_sdh], 0, WDSD_IBM);
 -	delay(10);	/* 400ns delay */
 +	delay(40);	/* 400ns delay */
  	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
  	    WDCTL_RST | WDCTL_IDS | WDCTL_4BIT);
  	delay(2000);
  	(void) bus_space_read_1(chp->cmd_iot, chp->cmd_iohs[wd_error], 0);
  	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
  	    WDCTL_4BIT | WDCTL_IDS);
 -	delay(10);	/* 400ns delay */
 +	delay(40);	/* 400ns delay */
  	if (poll != RESET_SLEEP) {
  		if (wdc->cap & WDC_CAPABILITY_IRQACK)
  			wdc->irqack(chp);
 @@ -1710,7 +1711,7 @@
  	 * Polled command. Wait for drive ready or drq. Done in intr().
  	 * Wait for at last 400ns for status bit to be valid.
  	 */
 -	delay(10);	/* 400ns delay */
 +	delay(40);	/* 400ns delay */
  	__wdccommand_intr(chp, xfer, 0);
  }
  
 @@ -1862,7 +1863,7 @@
  		/* enable interrupts */
  		bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
  		    WDCTL_4BIT);
 -		delay(10); /* some drives need a little delay here */
 +		delay(40); /* some drives need a little delay here */
  	}
  	wdc_free_xfer(chp, xfer);
  	if (wdc_c->flags & AT_WAIT)