Subject: Re: kern/30194: unrecoverable wd(4) error after suspend/resume
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Manuel Bouyer <bouyer@antioche.eu.org>
List: netbsd-bugs
Date: 05/16/2005 18:03:02
The following reply was made to PR kern/30194; it has been noted by GNATS.

From: Manuel Bouyer <bouyer@antioche.eu.org>
To: gnats-bugs@NetBSD.org
Cc: kern-bug-people@NetBSD.org, gnats-admin@NetBSD.org,
	netbsd-bugs@NetBSD.org
Subject: Re: kern/30194: unrecoverable wd(4) error after suspend/resume
Date: Mon, 16 May 2005 20:02:05 +0200

 --17pEHd4RhPHOinZp
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 > >Description:
 > i am unable to resume from suspend with APM in the kernel.  when resuming, the
 > system comes up but disk seems to be hung immediately (sometimes the disk
 > activity led is constantly on), processes hang in vnlock (sometimes in
 > getblk).  kernel prints error:
 > 
 >  atabus0: resuming...
 >  atabus1: resuming...
 >  wd0a: error writing fsbn 15042624 of 15042624-15042655 (wd0 bn 15042687; cn 14923 tn 4 sn 51), retrying
 >  wd0: (aborted command)
 
 Hi,
 can you try the attached patch ? I've not been able to reproduce your problem,
 but the atabus power hook needs to be smarter than it is actually.
 
 -- 
 Manuel Bouyer <bouyer@antioche.eu.org>
      NetBSD: 26 ans d'experience feront toujours la difference
 --
 
 --17pEHd4RhPHOinZp
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename=diff
 
 Index: ata.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/ata/ata.c,v
 retrieving revision 1.67
 diff -u -r1.67 ata.c
 --- ata.c	11 Apr 2005 04:24:54 -0000	1.67
 +++ ata.c	16 May 2005 17:42:45 -0000
 @@ -158,6 +158,7 @@
  
  	TAILQ_INIT(&chp->ch_queue->queue_xfer);
  	chp->ch_queue->queue_freeze = 0;
 +	chp->ch_queue->queue_flags = 0;
  	chp->ch_queue->active_xfer = NULL;
  
  	chp->atabus = config_found(&chp->ch_atac->atac_dev, chp, atabusprint);
 @@ -322,11 +323,7 @@
  	splx(s);
  
  	/* Configure the devices on the bus. */
 -	if (sc->sc_sleeping == 1) {
 -		printf("%s: resuming...\n", sc->sc_dev.dv_xname);
 -		sc->sc_sleeping = 0;
 -	} else
 -		atabusconfig(sc);
 +	atabusconfig(sc);
  
  	for (;;) {
  		s = splbio();
 @@ -430,7 +427,6 @@
  	config_pending_incr();
  	kthread_create(atabus_create_thread, sc);
  
 -	sc->sc_sleeping = 0;
  	sc->sc_powerhook = powerhook_establish(atabus_powerhook, sc);
  	if (sc->sc_powerhook == NULL)
  		printf("%s: WARNING: unable to establish power hook\n",
 @@ -699,6 +695,22 @@
  }
  
  /*
 + * freeze the queue and wait for the controller to be idle. Caller has to
 + * unfreeze/restart the queue
 + */
 +void
 +ata_queue_idle(struct ata_queue *queue)
 +{
 +	int s = splbio();
 +	queue->queue_freeze++;
 +	while (queue->active_xfer != NULL) {
 +		queue->queue_flags |= QF_IDLE_WAIT;
 +		tsleep(&queue->queue_flags, PRIBIO, "qidl", 0);
 +	}
 +	splx(s);
 +}
 +
 +/*
   * Add a command to the queue and start controller.
   *
   * MUST BE CALLED AT splbio()!
 @@ -772,6 +784,10 @@
  		return; /* channel aleady active */
  	}
  	if (__predict_false(chp->ch_queue->queue_freeze > 0)) {
 +		if (queue->queue_flags & QF_IDLE_WAIT) {
 +			queue->queue_flags &= ~QF_IDLE_WAIT;
 +			wakeup(&queue->queue_flags);
 +		}
  		return; /* queue froozen */
  	}
  	/*
 @@ -1422,17 +1438,17 @@
  	switch (why) {
  	case PWR_SOFTSUSPEND:
  	case PWR_SOFTSTANDBY:
 -		sc->sc_sleeping = 1;
 -		s = splbio();
 -		chp->ch_flags = ATACH_SHUTDOWN;
 -		splx(s);
 -		wakeup(&chp->ch_thread);
 -		while (chp->ch_thread != NULL)
 -			(void) tsleep((void *)&chp->ch_flags, PRIBIO,
 -			    "atadown", 0);
 +		/* freeze the queue and wait for the controller to be idle */
 +		ata_queue_idle(chp->ch_queue);
  		break;
  	case PWR_RESUME:
 -		atabus_create_thread(sc);
 +		printf("%s: resuming...\n", sc->sc_dev.dv_xname);
 +		s = splbio();
 +		KASSERT(chp->ch_queue->queue_freeze > 0);
 +		/* unfreeze the queue and reset drives (to wake them up) */
 +		chp->ch_queue->queue_freeze--;
 +		ata_reset_channel(chp, AT_WAIT);
 +		splx(s);
  		break;
  	case PWR_SUSPEND:
  	case PWR_STANDBY:
 Index: atavar.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/ata/atavar.h,v
 retrieving revision 1.67
 diff -u -r1.67 atavar.h
 --- atavar.h	27 Feb 2005 00:26:59 -0000	1.67
 +++ atavar.h	16 May 2005 17:42:45 -0000
 @@ -88,6 +88,8 @@
  	TAILQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */
  	int queue_freeze; /* freeze count for the queue */
  	struct ata_xfer *active_xfer; /* active command */
 +	int queue_flags;	/* flags for this queue */
 +#define QF_IDLE_WAIT   0x01    /* someone is wants the controller idle */
  };
  
  /* ATA bus instance state information. */
 @@ -97,7 +99,6 @@
  	int sc_flags;
  #define ATABUSCF_OPEN	0x01
  	void *sc_powerhook;
 -	int sc_sleeping;
  };
  
  /*
 @@ -441,6 +442,7 @@
  void	ata_probe_caps(struct ata_drive_datas *);
  
  void	ata_dmaerr(struct ata_drive_datas *, int);
 +void	ata_queue_idle(struct ata_queue *);
  #endif /* _KERNEL */
  
  #endif /* _DEV_ATA_ATAVAR_H_ */
 
 --17pEHd4RhPHOinZp--