Subject: Re: strange behaviour of apmd
To: Thorsten Frueauf <frueauf@ira.uka.de>
From: Chris G. Demetriou <cgd@CS.cmu.edu>
List: current-users
Date: 01/14/1997 14:23:21
> And even more strange, sometimes (not always!) the /etc/apm/resume script is
> trashed! It has the same size as before, but does only conatin 0 chars!

So, there have been several failure modes reported with the 'wd'
driver in combination with suspend/resume on laptops.

The patch below fixed all of them for me.  If it fixes the problem for
you, please let me know.  The patch is what I sent to the i386 port
maintainers >2 months ago.  There have been few (one 8-) changes to
the wd driver since then, but that change is unrelated and this patch
should apply relatively cleanly.


At the time i sent it to the i386 port maintainers, i specifically
said:

>thoughts?  If this patch is inappropriate, i'd appreciate knowing why,
>and being given enough information so that I might be able to fix it.
>Without this patch, my laptop was unusable after suspends...

I've yet to get _any_ reply.  (Other mail that i sent at the same
time, e.g. the NKPDE "fixes," was responded to soon after, so it's not
clear that "you should have sent a PR" is a reasonable response...)


cgd
===================================================================
Index: wd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/isa/wd.c,v
retrieving revision 1.154
diff -c -r1.154 wd.c
*** wd.c	1996/11/07 05:23:07	1.154
--- wd.c	1996/11/09 00:29:27
***************
*** 96,102 ****
  #define	GEOMETRY_WAIT	3		/* done uploading geometry */
  #define	MULTIMODE	4		/* set multiple mode */
  #define	MULTIMODE_WAIT	5		/* done setting multiple mode */
! #define	OPEN		6		/* done with open */
  	int sc_mode;			/* transfer mode */
  #define	WDM_PIOSINGLE	0		/* single-sector PIO */
  #define	WDM_PIOMULTI	1		/* multi-sector PIO */
--- 96,102 ----
  #define	GEOMETRY_WAIT	3		/* done uploading geometry */
  #define	MULTIMODE	4		/* set multiple mode */
  #define	MULTIMODE_WAIT	5		/* done setting multiple mode */
! #define	READY		6		/* ready for use */
  	int sc_mode;			/* transfer mode */
  #define	WDM_PIOSINGLE	0		/* single-sector PIO */
  #define	WDM_PIOMULTI	1		/* multi-sector PIO */
***************
*** 547,553 ****
  	bp = wd->sc_q.b_actf;
      
  	if (wdc->sc_errors >= WDIORETRIES) {
! 		wderror(wd, bp, "hard error");
  		bp->b_error = EIO;
  		bp->b_flags |= B_ERROR;
  		wdfinish(wd, bp);
--- 547,553 ----
  	bp = wd->sc_q.b_actf;
      
  	if (wdc->sc_errors >= WDIORETRIES) {
! 		wderror(wd, bp, "wdcstart hard error");
  		bp->b_error = EIO;
  		bp->b_flags |= B_ERROR;
  		wdfinish(wd, bp);
***************
*** 555,561 ****
  	}
  
  	/* Do control operations specially. */
! 	if (wd->sc_state < OPEN) {
  		/*
  		 * Actually, we want to be careful not to mess with the control
  		 * state if the device is currently busy, but we can assume
--- 555,561 ----
  	}
  
  	/* Do control operations specially. */
! 	if (wd->sc_state < READY) {
  		/*
  		 * Actually, we want to be careful not to mess with the control
  		 * state if the device is currently busy, but we can assume
***************
*** 783,789 ****
  	}
      
  	/* Is it not a transfer, but a control operation? */
! 	if (wd->sc_state < OPEN) {
  		if (wdcontrol(wd) == 0) {
  			/* The drive is busy.  Wait. */
  			return 1;
--- 783,789 ----
  	}
      
  	/* Is it not a transfer, but a control operation? */
! 	if (wd->sc_state < READY) {
  		if (wdcontrol(wd) == 0) {
  			/* The drive is busy.  Wait. */
  			return 1;
***************
*** 811,821 ****
  		if (bp->b_flags & B_FORMAT)
  			goto bad;
  #endif
- 	
- 		if (++wdc->sc_errors < WDIORETRIES)
- 			goto restart;
- 		wderror(wd, bp, "hard error");
  
  #ifdef B_FORMAT
  	bad:
  #endif
--- 811,828 ----
  		if (bp->b_flags & B_FORMAT)
  			goto bad;
  #endif
  
+ 		if (++wdc->sc_errors < WDIORETRIES) {
+ 			if (wdc->sc_errors == (WDIORETRIES + 1) / 2) {
+ #if 0
+ 				wderror(wd, NULL, "wedgie");
+ #endif
+ 				wdcunwedge(wdc);
+ 				return 1;
+ 			}
+ 			goto restart;
+ 		}
+ 		wderror(wd, bp, "wdcintr hard error");
  #ifdef B_FORMAT
  	bad:
  #endif
***************
*** 1129,1135 ****
  	case MULTIMODE:
  	multimode:
  		if (wd->sc_mode != WDM_PIOMULTI)
! 			goto open;
  		outb(wdc->sc_iobase+wd_seccnt, wd->sc_multiple);
  		if (wdcommandshort(wdc, wd->sc_drive, WDCC_SETMULTI) != 0) {
  			wderror(wd, NULL, "wdcontrol: setmulti failed (1)");
--- 1136,1142 ----
  	case MULTIMODE:
  	multimode:
  		if (wd->sc_mode != WDM_PIOMULTI)
! 			goto ready;
  		outb(wdc->sc_iobase+wd_seccnt, wd->sc_multiple);
  		if (wdcommandshort(wdc, wd->sc_drive, WDCC_SETMULTI) != 0) {
  			wderror(wd, NULL, "wdcontrol: setmulti failed (1)");
***************
*** 1144,1153 ****
  			goto bad;
  		}
  		/* fall through */
! 	case OPEN:
! 	open:
  		wdc->sc_errors = 0;
! 		wd->sc_state = OPEN;
  		/*
  		 * The rest of the initialization can be done by normal means.
  		 */
--- 1151,1160 ----
  			goto bad;
  		}
  		/* fall through */
! 	case READY:
! 	ready:
  		wdc->sc_errors = 0;
! 		wd->sc_state = READY;
  		/*
  		 * The rest of the initialization can be done by normal means.
  		 */
***************
*** 1500,1506 ****
  	part = WDPART(dev);
  
  	/* Make sure it was initialized. */
! 	if (wd->sc_state < OPEN)
  		return ENXIO;
  
  	wdc = (void *)wd->sc_dev.dv_parent;
--- 1507,1513 ----
  	part = WDPART(dev);
  
  	/* Make sure it was initialized. */
! 	if (wd->sc_state < READY)
  		return ENXIO;
  
  	wdc = (void *)wd->sc_dev.dv_parent;