Subject: Re: port-i386/21531 (ACPI enabled kernel enforces stressful
To: None <tech-kern@netbsd.org>
From: Takayoshi Kochi <kochi@netbsd.org>
List: tech-kern
Date: 08/16/2003 02:59:25
----Next_Part(Sat_Aug_16_02:59:25_2003_725)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi,

It seems that no one is actively looking at this PR...

I updated the proposed patch in PR/21531 to -current and tested
on my laptop (ThinkPad X31), which worked fine.

Can someone familiar with ATA (Manuel or Jason?) look at the
patch and commit if it's ok?

---
Takayoshi Kochi

----Next_Part(Sat_Aug_16_02:59:25_2003_725)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="wd.c.patch3"

--- wd.c.orig	2003-08-10 01:29:29.000000000 +0900
+++ wd.c	2003-08-16 02:24:41.000000000 +0900
@@ -190,6 +190,7 @@
 void  __wdstart(struct wd_softc*, struct buf *);
 void  wdrestart(void *);
 int   wd_get_params(struct wd_softc *, u_int8_t, struct ataparams *);
+int   wd_pm_command(struct wd_softc *, u_int8_t, int);
 void  wd_flushcache(struct wd_softc *, int);
 void  wd_shutdown(void *);
 
@@ -1725,11 +1726,72 @@
 	 */
 }
 
+int
+wd_pm_command(struct wd_softc *wd, u_int8_t cmd, int flags)
+{
+	struct wdc_command wdc_c;
+	struct ataparams params;
+	char const *verb;
+
+	if (wd_get_params(wd, AT_WAIT, &params) != 0)
+		return EIO;
+	if (params.atap_cmd_set1 == 0x0000 ||
+	    params.atap_cmd_set1 == 0xffff ||
+	    (params.atap_cmd_set1 & WDC_CMD1_PM) == 0)
+		return EOPNOTSUPP;
+	switch (cmd) {
+	case WDCC_IDLE_IMMED :
+		verb = "idle";
+		break;
+	case WDCC_STANDBY_IMMED :
+		verb = "standby";
+		break;
+	case WDCC_SLEEP :
+		verb = "sleep";
+		break;
+	default :
+		verb = "unknown";
+#ifdef DIAGNOSTIC
+		panic("wd_pm_command: unknown command\n");
+#endif
+	}
+	memset(&wdc_c, 0, sizeof(struct wdc_command));
+	wdc_c.r_command = cmd;
+	wdc_c.r_st_bmask = WDCS_DRDY;
+	wdc_c.r_st_pmask = WDCS_DRDY;
+	wdc_c.flags = flags;
+	wdc_c.timeout = 30000; /* 30s timeout -- XXX too long? */
+	if (wd->atabus->ata_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) {
+		printf("%s: %s command didn't complete\n",
+		    wd->sc_dev.dv_xname, verb);
+		return EIO;
+	}
+	if (wdc_c.flags & AT_TIMEOU) {
+		printf("%s: %s command timeout\n",
+		    wd->sc_dev.dv_xname, verb);
+		return EIO;
+	}
+	if (wdc_c.flags & AT_DF) {
+		printf("%s: %s command: drive fault\n",
+		    wd->sc_dev.dv_xname, verb);
+		return EIO;
+	}
+	/*
+	 * Error register shouldn't report anything else than COMMAND ABORTED,
+	 * which means the device doesn't support given command.
+	 */
+	if (wdc_c.flags & AT_ERROR)
+		return EOPNOTSUPP;
+	return (0);
+}
+
 void
 wd_shutdown(void *arg)
 {
 	struct wd_softc *wd = arg;
-	wd_flushcache(wd, AT_POLL);
+
+	if (wd_pm_command(wd, WDCC_STANDBY_IMMED, AT_POLL) != 0)
+		wd_flushcache(wd, AT_POLL);
 }
 
 /*

----Next_Part(Sat_Aug_16_02:59:25_2003_725)----