Subject: Re: Bus-Master DMA missing interrupt?
To: None <current-users@netbsd.org>
From: Takahiro Kambe <taca@sky.yamashina.kyoto.jp>
List: current-users
Date: 03/20/1999 12:02:28
In message <19990318130553.56773@antioche.lip6.fr>
	on Thu, 18 Mar 1999 13:05:53 +0100,
	Manuel Bouyer <bouyer@antioche.lip6.fr> wrote:
> I lowered the timeout from 10s to 1s, but it caused problems with some
> power-manageemnt stuffs. I reverted back to a 10s timeout yesterday.
> Could you try a newer kernel, or alternatively change
> ATA_DELAY_NORMAL from 1000 to 10000 in sys/dev/ata_wdc.c
This works finr for me.

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);
		}
	}

--
Takahiro Kambe <taca@sky.yamashina.kyoto.jp>