Subject: Re: Bus-Master DMA missing interrupt?
To: Takahiro Kambe <taca@sky.yamashina.kyoto.jp>
From: Manuel Bouyer <bouyer@antioche.lip6.fr>
List: current-users
Date: 03/23/1999 13:14:23
On Mar 20, Takahiro Kambe wrote
> FreeBSD 2.2.8 introduced WDOPT_SLEEPHACK device flag.  It's really a
> hack, but works fine.
> 
> /*
>  * Wait uninterruptibly until controller is not busy, then send it a command.
>  * The wait usually terminates immediately because we waited for the previous
>  * command to terminate.
>  */
> static int
> wdcommand(struct disk *du, u_int cylinder, u_int head, u_int sector,
> 	  u_int count, u_int command)
> {
> 	u_int	wdc;
> 
> 	wdc = du->dk_port;
> 	if (du->cfg_flags & WDOPT_SLEEPHACK) {
> 		/* OK, so the APM bios has put the disk into SLEEP mode,
> 		 * how can we tell ?  Uhm, we can't.  There is no 
> 		 * standardized way of finding out, and the only way to
> 		 * wake it up is to reset it.  Bummer.
> 		 *
> 		 * All the many and varied versions of the IDE/ATA standard
> 		 * explicitly tells us not to look at these registers if
> 		 * the disk is in SLEEP mode.  Well, too bad really, we
> 		 * have to find out if it's in sleep mode before we can 
> 		 * avoid reading the registers.
> 		 *
> 		 * I have reason to belive that most disks will return
> 		 * either 0xff or 0x00 in all but the status register 
> 		 * when in SLEEP mode, but I have yet to see one return 
> 		 * 0x00, so we don't check for that yet.
> 		 *
> 		 * The check for WDCS_BUSY is for the case where the
> 		 * bios spins up the disk for us, but doesn't initialize
> 		 * it correctly					/phk
> 		 */
> 		if(inb(wdc + wd_precomp) + inb(wdc + wd_cyl_lo) +
> 		    inb(wdc + wd_cyl_hi) + inb(wdc + wd_sdh) +
> 		    inb(wdc + wd_sector) + inb(wdc + wd_seccnt) == 6 * 0xff) {
> 			if (bootverbose)
> 				printf("wd(%d,%d): disk aSLEEP\n",
> 					du->dk_ctrlr, du->dk_unit);
> 			wdunwedge(du);
> 		} else if(inb(wdc + wd_status) == WDCS_BUSY) {
> 			if (bootverbose)
> 				printf("wd(%d,%d): disk is BUSY\n",
> 					du->dk_ctrlr, du->dk_unit);
> 			wdunwedge(du);
> 		}
> 	}
> 

This handles a disk in sleep mode. In this mode the disk is disconnected from
the bus. The 'missing interrupt' occurs for drives in standby mode: the
interface still anserw commands, but for a read/write operation it needs to
spin up the disk first, which may take more than the timeout value ("up to
30s", per the spec). Bumping the timeout value to 30s will introduce some new
problems too.

--
Manuel Bouyer, LIP6, Universite Paris VI.           Manuel.Bouyer@lip6.fr
--