[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

wdc.c fix for restarted disk ops



The dev/isa/wdc.c disk driver fails on restarted operations.  I ran across
this with an IBM Thinkpad that returns an error and must be reset and
restarted after resuming from sleep mode, but I think this will be a problem
for any restarted disk operation.

Another bug is that wedgies will always result in a hard disk error if the
retry count is three or less (three is the default).  I'm not sure what the
right fix is.  When I fixed this the first time, back in the NetBSD driver,
I used to unwedge on every error.  But someone else put in some code that
apparently is supposed to only unwedge half way thru the retry count.  My
current code unwedges on the second and later retries.

This patch also includes a fix for notebook computers that get an unexpected
interrupt on spindown or spinup.  Three different models from three
different manufacturers I have tried all have problems if this interrupt is
acknowledged.  This patch violates the spec but it works.  Don't apply this
unless you are having a problem.

*** dev/isa/wdc.c-	Mon Oct 27 16:31:35 1997
--- dev/isa/wdc.c	Fri Dec  5 14:32:00 1997
***************
*** 433,447 ****
  
  	/* When starting a transfer... */
  	if (xfer->c_skip == 0) {
! 		daddr_t blkno;
  
  		WDDEBUG_PRINT(("\n%s: wdc_ata_start %s %d@%d; map ",
  		    wdc->sc_dev.dv_xname,
  		    (xfer->c_flags & B_READ) ? "read" : "write",
  		    xfer->c_bcount, xfer->c_blkno));
! 
! 		blkno = xfer->c_blkno+xfer->c_p_offset;
! 		xfer->c_blkno = blkno / (d_link->sc_lp->d_secsize / DEV_BSIZE);
  	} else {
  		WDDEBUG_PRINT((" %d)0x%x", xfer->c_skip,
  		    bus_space_read_1(iot, ioh, wd_altsts)));
--- 433,446 ----
  
  	/* When starting a transfer... */
  	if (xfer->c_skip == 0) {
! 		struct buf *bp = xfer->c_bp;
  
  		WDDEBUG_PRINT(("\n%s: wdc_ata_start %s %d@%d; map ",
  		    wdc->sc_dev.dv_xname,
  		    (xfer->c_flags & B_READ) ? "read" : "write",
  		    xfer->c_bcount, xfer->c_blkno));
! 		xfer->c_bcount = bp->b_bcount;
! 		xfer->c_blkno = (bp->b_blkno + xfer->c_p_offset) / (d_link->sc_lp->d_secsize / DEV_BSIZE);
  	} else {
  		WDDEBUG_PRINT((" %d)0x%x", xfer->c_skip,
  		    bus_space_read_1(iot, ioh, wd_altsts)));
***************
*** 651,657 ****
  	/* Have we an error? */
  	if (wdc->sc_status & WDCS_ERR) {
  #ifdef WDDEBUG
! 		wderror(d_link, NULL, "wdc_ata_start");
  #endif
  		if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
  			wdc->sc_flags |= WDCF_ERROR;
--- 650,656 ----
  	/* Have we an error? */
  	if (wdc->sc_status & WDCS_ERR) {
  #ifdef WDDEBUG
! 		wderror(d_link, NULL, "wdc_ata_intr");
  #endif
  		if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
  			wdc->sc_flags |= WDCF_ERROR;
***************
*** 663,669 ****
  			goto bad;
  #endif
  
! 		if (wdc->sc_errors == (WDIORETRIES + 1) / 2) {
  			wderror(d_link, NULL, "wedgie");
  			wdcunwedge(wdc);
  			return 1;
--- 662,668 ----
  			goto bad;
  #endif
  
! 		if (wdc->sc_errors > 0) {
  			wderror(d_link, NULL, "wedgie");
  			wdcunwedge(wdc);
  			return 1;
***************
*** 1508,1513 ****
--- 1507,1513 ----
  	struct wdc_xfer *xfer;
  
  	if ((wdc->sc_flags & WDCF_IRQ_WAIT) == 0) {
+ #if NATAPIBUS > 0
  		bus_space_tag_t iot = wdc->sc_iot;
  		bus_space_handle_t ioh = wdc->sc_ioh;
  		u_char s;
***************
*** 1540,1545 ****
--- 1540,1546 ----
  				wdcbit_bucket(wdc, len);
  			}
  		}
+ #endif /* NATAPIBUS > 0 */
  		return 0;
  	}
  
*** dev/isa/wd.c-	Mon Oct 27 16:31:34 1997
--- dev/isa/wd.c	Fri Dec  5 13:43:04 1997
***************
*** 313,319 ****
  		xfer->databuf = bp->b_data;
  		xfer->c_bcount = bp->b_bcount;
  		xfer->c_flags |= bp->b_flags & (B_READ|B_WRITE);
! 		xfer->c_blkno = bp->b_blkno;
  
  		/* Instrumentation. */
  		disk_busy(&wd->sc_dk);
--- 313,319 ----
  		xfer->databuf = bp->b_data;
  		xfer->c_bcount = bp->b_bcount;
  		xfer->c_flags |= bp->b_flags & (B_READ|B_WRITE);
! 		xfer->c_blkno = (bp->b_blkno + xfer->c_p_offset) / (d_link->sc_lp->d_secsize / DEV_BSIZE);
  
  		/* Instrumentation. */
  		disk_busy(&wd->sc_dk);