Subject: Fwd: Re: port-i386/21531: ACPI enabled kernel enforces stressful shutdown of harddrive
To: None <tech-kern@netbsd.org>
From: Charles M. Hannum <abuse@spamalicious.com>
List: tech-kern
Date: 06/28/2004 21:21:03
--Boundary-00=_/uI4AfcFGJspr4K
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
--Boundary-00=_/uI4AfcFGJspr4K
Content-Type: message/rfc822;
name="forwarded message"
Content-Transfer-Encoding: 7bit
Content-Description: "Charles M. Hannum" <abuse@spamalicious.com>: Re: port-i386/21531: ACPI enabled kernel enforces stressful shutdown of harddrive
Content-Disposition: inline
From: "Charles M. Hannum" <abuse@spamalicious.com>
Organization: By Noon Software, Inc.
To: DHOYASHIKI Shinichi <clare@znet.or.jp>
Subject: Re: port-i386/21531: ACPI enabled kernel enforces stressful shutdown of harddrive
Date: Mon, 28 Jun 2004 20:53:29 +0000
User-Agent: KMail/1.6.1
Cc: gnats-bugs@netbsd.org
MIME-Version: 1.0
Content-Disposition: inline
Content-Type: Multipart/Mixed;
boundary="Boundary-00=_JVI4ACY35gTsgDQ"
Message-Id: <200406282053.29585.abuse@spamalicious.com>
--Boundary-00=_JVI4ACY35gTsgDQ
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Subject:
While looking at this, I noticed that we also try to issue a "flush cache"
command to PCMCIA and CompactFlash cards that are currently powered down --
which is sort of guaranteed to not work. The following patch addresses both
of these problems.
This could probably be done better (e.g. by doing it from a shutdownhook and
powerhook for the controller, and making PCMCIA and CardBus use these to do a
graceful shutdown).
--Boundary-00=_JVI4ACY35gTsgDQ
Content-Type: text/x-diff;
charset="us-ascii";
name="ata.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="ata.diff"
Index: ata/ata_wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/ata_wdc.c,v
retrieving revision 1.57
diff -u -r1.57 ata_wdc.c
--- ata/ata_wdc.c 22 Jun 2004 19:20:56 -0000 1.57
+++ ata/ata_wdc.c 28 Jun 2004 20:46:54 -0000
@@ -128,6 +128,7 @@
static int wdc_ata_addref(struct ata_drive_datas *);
static void wdc_ata_delref(struct ata_drive_datas *);
static void wdc_ata_kill_pending(struct ata_drive_datas *);
+static int wdc_ata_isenabled(struct ata_drive_datas *);
const struct ata_bustype wdc_ata_bustype = {
SCSIPI_BUSTYPE_ATA,
@@ -138,6 +139,7 @@
wdc_ata_addref,
wdc_ata_delref,
wdc_ata_kill_pending,
+ wdc_ata_isenabled,
};
/*
@@ -828,3 +830,11 @@
wdc_delref(chp);
}
+
+static int
+wdc_ata_isenabled(struct ata_drive_datas *drvp)
+{
+ struct wdc_channel *chp = drvp->chnl_softc;
+
+ return (wdc_isenabled(chp));
+}
Index: ata/atavar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/atavar.h,v
retrieving revision 1.43
diff -u -r1.43 atavar.h
--- ata/atavar.h 1 Jun 2004 19:32:30 -0000 1.43
+++ ata/atavar.h 28 Jun 2004 20:46:54 -0000
@@ -261,6 +261,7 @@
int (*ata_addref)(struct ata_drive_datas *);
void (*ata_delref)(struct ata_drive_datas *);
void (*ata_killpending)(struct ata_drive_datas *);
+ int (*ata_isenabled)(struct ata_drive_datas *);
};
/* bustype_type */ /* XXX XXX XXX */
Index: ata/wd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/wd.c,v
retrieving revision 1.280
diff -u -r1.280 wd.c
--- ata/wd.c 22 Jun 2004 19:20:56 -0000 1.280
+++ ata/wd.c 28 Jun 2004 20:46:55 -0000
@@ -188,6 +188,7 @@
void wdrestart(void *);
void wddone(void *);
int wd_get_params(struct wd_softc *, u_int8_t, struct ataparams *);
+int wd_standby(struct wd_softc *, int);
int wd_flushcache(struct wd_softc *, int);
void wd_shutdown(void *);
@@ -947,7 +948,6 @@
if (wd->sc_dk.dk_openmask == 0) {
wd_flushcache(wd, AT_WAIT);
- /* XXXX Must wait for I/O to complete! */
if (! (wd->sc_flags & WDF_KLABEL))
wd->sc_flags &= ~WDF_LOADED;
@@ -1595,6 +1595,8 @@
return 0;
}
+const char at_errbits[] = "\20\10ERROR\11TIMEOU\12DF";
+
int
wd_setcache(struct wd_softc *wd, int bits)
{
@@ -1629,12 +1631,45 @@
return EIO;
}
if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
- printf("%s: wd_setcache command error 0x%x\n",
- wd->sc_dev.dv_xname, wdc_c.flags);
+ char sbuf[sizeof(at_errbits) + 64];
+ bitmask_snprintf(wdc_c.flags, at_errbits, sbuf, sizeof(sbuf));
+ printf("%s: wd_setcache: status=%s\n", wd->sc_dev.dv_xname,
+ sbuf);
+ return EIO;
+ }
+ return 0;
+}
+
+int
+wd_standby(struct wd_softc *wd, int flags)
+{
+ struct wdc_command wdc_c;
+
+printf("%s: wd_standby entered\n", wd->sc_dev.dv_xname);
+ memset(&wdc_c, 0, sizeof(struct wdc_command));
+ wdc_c.r_command = WDCC_STANDBY_IMMED;
+ wdc_c.r_st_bmask = WDCS_DRDY;
+ wdc_c.r_st_pmask = WDCS_DRDY;
+ wdc_c.flags = flags;
+ wdc_c.timeout = 30000; /* 30s timeout */
+ if (wd->atabus->ata_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) {
+ printf("%s: standby immediate command didn't complete\n",
+ wd->sc_dev.dv_xname);
+ return EIO;
+ }
+printf("%s: wd_standby finished, status=%x\n", wd->sc_dev.dv_xname,
+ wdc_c.flags);
+ if (wdc_c.flags & AT_ERROR) {
+ if (wdc_c.r_error == WDCE_ABRT) /* command not supported */
+ return ENODEV;
+ }
+ if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+ char sbuf[sizeof(at_errbits) + 64];
+ bitmask_snprintf(wdc_c.flags, at_errbits, sbuf, sizeof(sbuf));
+ printf("%s: wd_standby: status=%s\n", wd->sc_dev.dv_xname,
+ sbuf);
return EIO;
}
- if (wdc_c.flags & ERR_NODEV)
- return ENODEV;
return 0;
}
@@ -1643,6 +1678,7 @@
{
struct wdc_command wdc_c;
+printf("%s: wd_flushcache entered\n", wd->sc_dev.dv_xname);
if (wd->drvp->ata_vers < 4) /* WDCC_FLUSHCACHE is here since ATA-4 */
return ENODEV;
memset(&wdc_c, 0, sizeof(struct wdc_command));
@@ -1660,23 +1696,17 @@
wd->sc_dev.dv_xname);
return EIO;
}
- if (wdc_c.flags & ERR_NODEV)
- return ENODEV;
- if (wdc_c.flags & AT_TIMEOU) {
- printf("%s: flush cache command timeout\n",
- wd->sc_dev.dv_xname);
- return EIO;
- }
+printf("%s: wd_flushcache finished, status=%x\n", wd->sc_dev.dv_xname,
+ wdc_c.flags);
if (wdc_c.flags & AT_ERROR) {
if (wdc_c.r_error == WDCE_ABRT) /* command not supported */
return ENODEV;
- printf("%s: flush cache command: error 0x%x\n",
- wd->sc_dev.dv_xname, wdc_c.r_error);
- return EIO;
}
- if (wdc_c.flags & AT_DF) {
- printf("%s: flush cache command: drive fault\n",
- wd->sc_dev.dv_xname);
+ if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+ char sbuf[sizeof(at_errbits) + 64];
+ bitmask_snprintf(wdc_c.flags, at_errbits, sbuf, sizeof(sbuf));
+ printf("%s: wd_flushcache: status=%s\n", wd->sc_dev.dv_xname,
+ sbuf);
return EIO;
}
return 0;
@@ -1686,7 +1716,11 @@
wd_shutdown(void *arg)
{
struct wd_softc *wd = arg;
+
+ if (!wd->atabus->ata_isenabled(wd->drvp))
+ return;
wd_flushcache(wd, AT_POLL);
+ wd_standby(wd, AT_POLL);
}
/*
Index: ic/wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdc.c,v
retrieving revision 1.180
diff -u -r1.180 wdc.c
--- ic/wdc.c 1 Jun 2004 19:32:30 -0000 1.180
+++ ic/wdc.c 28 Jun 2004 20:46:55 -0000
@@ -2060,6 +2060,19 @@
splx(s);
}
+int
+wdc_isenabled(struct wdc_channel *chp)
+{
+ struct wdc_softc *wdc = chp->ch_wdc;
+ struct scsipi_adapter *adapt = &wdc->sc_atapi_adapter._generic;
+ int s, rv;
+
+ s = splbio();
+ rv = (adapt->adapt_enable == NULL || adapt->adapt_refcnt != 0);
+ splx(s);
+ return (rv);
+}
+
void
wdc_print_modes(struct wdc_channel *chp)
{
Index: ic/wdcvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdcvar.h,v
retrieving revision 1.57
diff -u -r1.57 wdcvar.h
--- ic/wdcvar.h 25 May 2004 20:42:41 -0000 1.57
+++ ic/wdcvar.h 28 Jun 2004 20:46:55 -0000
@@ -219,6 +219,7 @@
int wdc_addref(struct wdc_channel *);
void wdc_delref(struct wdc_channel *);
void wdc_kill_pending(struct wdc_channel *);
+int wdc_isenabled(struct wdc_channel *);
void wdc_print_modes (struct wdc_channel *);
void wdc_probe_caps(struct ata_drive_datas*);
Index: usb/umass_isdata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/umass_isdata.c,v
retrieving revision 1.9
diff -u -r1.9 umass_isdata.c
--- usb/umass_isdata.c 30 Dec 2003 19:30:39 -0000 1.9
+++ usb/umass_isdata.c 28 Jun 2004 20:46:56 -0000
@@ -119,6 +119,7 @@
int uisdata_addref(struct ata_drive_datas *);
void uisdata_delref(struct ata_drive_datas *);
void uisdata_kill_pending(struct ata_drive_datas *);
+int uisdata_isenabled(struct ata_drive_datas *);
void uisdata_bio_cb(struct umass_softc *, void *, int, int);
void uisdata_exec_cb(struct umass_softc *, void *, int, int);
@@ -133,6 +134,7 @@
uisdata_addref,
uisdata_delref,
uisdata_kill_pending,
+ uisdata_isenabled,
};
struct ata_cmd {
@@ -478,6 +480,14 @@
/* Nothing to do */
}
+int
+uisdata_isenabled(struct ata_drive_datas *drv)
+{
+ DPRINTF(("%s\n", __func__));
+ /* Nothing to do */
+ return (1);
+}
+
void
uisdata_kill_pending(struct ata_drive_datas *drv)
{
--Boundary-00=_JVI4ACY35gTsgDQ--
--Boundary-00=_/uI4AfcFGJspr4K--