tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
ld(4) shutdown/flush patch to avoid tsleep at system shutdown time
Hi folks,
With a recent -current on a machine with a twe(4) I get the following on
a reboot:
panic: cpu_switcho: switching above IPL_SCHED
Stopped in pid 6.1 (reboot) at netbsd:breakpoint+0x4: popl %ebp
db{0}> bt
breakpoint(c0a5f40c,cc819af4,c0a89100,cc819acc,c0484c7c,c0a89148,cc7f3c80,cc819afc,c0543aea,c0a89100)
at netbsd:breakpoint+0x4
panic(c010038a,cc7f3c80,0,0,c0484e50,cc7f3c80,cb367be0,0,c0481901,cc7f3c80)
at netbsd:panic+0x1bd
cpu_switchto(cc7f3c80,1770,b4063c,c1eb2600,0,c1ed8400,cc819bac,c05978fb,1770,0)
at netbsd:cpu_switchto+0x17
sleepq_block(1770,0,c0a38198,1770,0,5,8,c1f99000,0,c0a84b20) at
netbsd:sleepq_block+0x92
ld_twe_flush(c1f99000,c0a84b20,cc819bdc,c04a28c6,c1f99000,c1f99000,cc819bdc,c0491051,c1f99000,0)
at netbsd:ld_twe_flush+0xcb
ld_shutdown(c1f99000,0,cc819bfc,c047543e,c1f99000,0,cc819c0c,c04df28d,0,cc819d00)
at netbsd:ld_shutdown+0x21
device_pmf_driver_shutdown(c1f99000,0,cc819c0c,c04df28d,0,cc819d00,cc819c0c,c0484112,0,0)
at netbsd:device_pmf_driver_shutdown+0x21
pmf_system_shutdown(0,0,cc819c2c,c0558afb,8,cc7f3c80,0,0,cc819d00,0) at
netbsd:pmf_system_shutdown+0x9e
doshutdownhooks(8,cc7f3c80,0,0,cc819d00,0,cc819cdc,c04903c4,0,0) at
netbsd:doshutdownhooks+0x42
cpu_reboot(0,0,0,0,0,0,cc819c9c,c0543343,23,cc819cc0) at
netbsd:cpu_reboot+0x1b
sys_reboot(cc7f3c80,cc819d00,cc819d28,cc819d40,c05432f7,cb37bf50,1,0,0,bfbfede8)
at netbsd:sys_reboot+0x74
syscall(cc819d48,b3,ab,1f,1f,1,d,bfbfede8,2,256) at netbsd:syscall+0xab
The following patch adds a poll flag to the ld(4) sc_flush() function,
and ld_twe_flush() checks this and either polls or doesn't. By
inspection, twa(4) needs the same handling. I'm not sure about icp(4)
and iop(4).
This is vaguely based on what ata(4)/wdc(4) do - thanks to Joerg
Sonnenberger for the pointer to that code.
Any problems with this?
Cheers,
Simon.
--
Index: ld.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ld.c,v
retrieving revision 1.58
diff -d -p -u -r1.58 ld.c
--- ld.c 28 Apr 2008 20:23:46 -0000 1.58
+++ ld.c 10 May 2008 15:28:44 -0000
@@ -253,7 +253,7 @@ ldenddetach(struct ld_softc *sc)
#if 0
/* Flush the device's cache. */
if (sc->sc_flush != NULL)
- if ((*sc->sc_flush)(sc) != 0)
+ if ((*sc->sc_flush)(sc, 0) != 0)
aprint_error_dev(&sc->sc_dv, "unable to flush cache\n");
#endif
}
@@ -264,7 +264,7 @@ ld_shutdown(device_t dev, int flags)
{
struct ld_softc *sc = device_private(dev);
- if (sc->sc_flush != NULL && (*sc->sc_flush)(sc) != 0) {
+ if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, LDFL_POLL) != 0) {
printf("%s: unable to flush cache\n", device_xname(dev));
return false;
}
@@ -344,7 +344,7 @@ ldclose(dev_t dev, int flags, int fmt, s
sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
if (sc->sc_dk.dk_openmask == 0) {
- if (sc->sc_flush != NULL && (*sc->sc_flush)(sc) != 0)
+ if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, 0) != 0)
aprint_error_dev(&sc->sc_dv, "unable to flush cache\n");
if ((sc->sc_flags & LDF_KLABEL) == 0)
sc->sc_flags &= ~LDF_VLABEL;
@@ -486,7 +486,7 @@ ldioctl(dev_t dev, u_long cmd, void *add
if ((flag & FWRITE) == 0)
error = EBADF;
else if (sc->sc_flush)
- error = (*sc->sc_flush)(sc);
+ error = (*sc->sc_flush)(sc, 0);
else
error = 0; /* XXX Error out instead? */
break;
Index: ldvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ldvar.h,v
retrieving revision 1.13
diff -d -p -u -r1.13 ldvar.h
--- ldvar.h 28 Apr 2008 20:23:46 -0000 1.13
+++ ldvar.h 10 May 2008 15:28:44 -0000
@@ -57,10 +57,11 @@ struct ld_softc {
int sc_maxqueuecnt; /* maximum h/w queue depth */
int (*sc_dump)(struct ld_softc *, void *, int, int);
- int (*sc_flush)(struct ld_softc *);
+ int (*sc_flush)(struct ld_softc *, int);
int (*sc_start)(struct ld_softc *, struct buf *);
};
+/* sc_flags */
#define LDF_ENABLED 0x001 /* device enabled */
#define LDF_WLABEL 0x008 /* label is writable */
#define LDF_LABELLING 0x010 /* writing label */
@@ -69,6 +70,9 @@ struct ld_softc {
#define LDF_KLABEL 0x080 /* keep label on close */
#define LDF_VLABEL 0x100 /* label is valid */
+/* sc_flush() flags */
+#define LDFL_POLL 0x001 /* poll for completion */
+
int ldadjqparam(struct ld_softc *, int);
void ldattach(struct ld_softc *);
int ldbegindetach(struct ld_softc *, int);
Index: i2o/ld_iop.c
===================================================================
RCS file: /cvsroot/src/sys/dev/i2o/ld_iop.c,v
retrieving revision 1.28
diff -d -p -u -r1.28 ld_iop.c
--- i2o/ld_iop.c 28 Apr 2008 20:23:48 -0000 1.28
+++ i2o/ld_iop.c 10 May 2008 15:28:48 -0000
@@ -78,7 +78,7 @@ static void ld_iop_adjqparam(struct devi
static void ld_iop_attach(struct device *, struct device *, void *);
static int ld_iop_detach(struct device *, int);
static int ld_iop_dump(struct ld_softc *, void *, int, int);
-static int ld_iop_flush(struct ld_softc *);
+static int ld_iop_flush(struct ld_softc *, int);
static void ld_iop_intr(struct device *, struct iop_msg *, void *);
static void ld_iop_intr_event(struct device *, struct iop_msg *, void *);
static int ld_iop_match(struct device *, struct cfdata *, void *);
@@ -446,7 +446,7 @@ ld_iop_dump(struct ld_softc *ld, void *d
}
static int
-ld_iop_flush(struct ld_softc *ld)
+ld_iop_flush(struct ld_softc *ld, int flags)
{
struct iop_msg *im;
struct iop_softc *iop;
@@ -464,7 +464,7 @@ ld_iop_flush(struct ld_softc *ld)
mf.msgtctx = im->im_tctx;
mf.flags = 1 << 16; /* time multiplier */
- /* Aincent disks will return an error here. */
+ /* Ancient disks will return an error here. */
rv = iop_msg_post(iop, im, &mf, LD_IOP_TIMEOUT * 2);
iop_msg_free(iop, im);
return (rv);
Index: ic/ld_icp.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/ld_icp.c,v
retrieving revision 1.20
diff -d -p -u -r1.20 ld_icp.c
--- ic/ld_icp.c 28 Apr 2008 20:23:50 -0000 1.20
+++ ic/ld_icp.c 10 May 2008 15:28:48 -0000
@@ -70,7 +70,7 @@ int ld_icp_detach(struct device *, int);
int ld_icp_dobio(struct ld_icp_softc *, void *, int, int, int,
struct buf *);
int ld_icp_dump(struct ld_softc *, void *, int, int);
-int ld_icp_flush(struct ld_softc *);
+int ld_icp_flush(struct ld_softc *, int);
void ld_icp_intr(struct icp_ccb *);
int ld_icp_match(struct device *, struct cfdata *, void *);
int ld_icp_start(struct ld_softc *, struct buf *);
@@ -265,7 +265,7 @@ ld_icp_dump(struct ld_softc *ld, void *d
}
int
-ld_icp_flush(struct ld_softc *ld)
+ld_icp_flush(struct ld_softc *ld, int flags)
{
struct ld_icp_softc *sc;
struct icp_softc *icp;
Index: pci/ld_twa.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/ld_twa.c,v
retrieving revision 1.11
diff -d -p -u -r1.11 ld_twa.c
--- pci/ld_twa.c 7 May 2008 17:47:20 -0000 1.11
+++ pci/ld_twa.c 10 May 2008 15:28:49 -0000
@@ -81,7 +81,7 @@ static int ld_twa_detach(struct device *
static int ld_twa_dobio(struct ld_twa_softc *, void *, size_t, daddr_t,
struct buf *);
static int ld_twa_dump(struct ld_softc *, void *, int, int);
-static int ld_twa_flush(struct ld_softc *);
+static int ld_twa_flush(struct ld_softc *, int);
static void ld_twa_handler(struct twa_request *);
static int ld_twa_match(struct device *, struct cfdata *, void *);
static int ld_twa_start(struct ld_softc *, struct buf *);
@@ -243,7 +243,7 @@ ld_twa_dump(struct ld_softc *ld, void *d
static int
-ld_twa_flush(struct ld_softc *ld)
+ld_twa_flush(struct ld_softc *ld, int flags)
{
int s, rv = 0;
struct twa_request *tr;
Index: pci/ld_twe.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/ld_twe.c,v
retrieving revision 1.30
diff -d -p -u -r1.30 ld_twe.c
--- pci/ld_twe.c 28 Apr 2008 20:23:55 -0000 1.30
+++ pci/ld_twe.c 10 May 2008 15:28:49 -0000
@@ -71,7 +71,7 @@ static int ld_twe_detach(struct device *
static int ld_twe_dobio(struct ld_twe_softc *, void *, int, int, int,
struct buf *);
static int ld_twe_dump(struct ld_softc *, void *, int, int);
-static int ld_twe_flush(struct ld_softc *);
+static int ld_twe_flush(struct ld_softc *, int);
static void ld_twe_handler(struct twe_ccb *, int);
static int ld_twe_match(struct device *, struct cfdata *, void *);
static int ld_twe_start(struct ld_softc *, struct buf *);
@@ -274,7 +274,7 @@ ld_twe_dump(struct ld_softc *ld, void *d
}
static int
-ld_twe_flush(struct ld_softc *ld)
+ld_twe_flush(struct ld_softc *ld, int flags)
{
struct ld_twe_softc *sc = (void *) ld;
struct twe_softc *twe = (void *) device_parent(&ld->sc_dv);
@@ -287,9 +287,6 @@ ld_twe_flush(struct ld_softc *ld)
ccb->ccb_data = NULL;
ccb->ccb_datasize = 0;
- ccb->ccb_tx.tx_handler = twe_ccb_wait_handler;
- ccb->ccb_tx.tx_context = NULL;
- ccb->ccb_tx.tx_dv = &ld->sc_dv;
tc = ccb->ccb_cmd;
tc->tc_size = 2;
@@ -297,14 +294,31 @@ ld_twe_flush(struct ld_softc *ld)
tc->tc_unit = sc->sc_hwunit;
tc->tc_count = 0;
- rv = 0;
- twe_ccb_enqueue(twe, ccb);
- s = splbio();
- while ((ccb->ccb_flags & TWE_CCB_COMPLETE) == 0)
- if ((rv = tsleep(ccb, PRIBIO, "tweflush", 60 * hz)) != 0)
- break;
- twe_ccb_free(twe, ccb);
- splx(s);
+ if (flags & LDFL_POLL) {
+ /*
+ * Polled commands must not sit on the software queue. Wait
+ * up to 2 seconds for the command to complete.
+ */
+ s = splbio();
+ rv = twe_ccb_poll(twe, ccb, 2000);
+ twe_ccb_unmap(twe, ccb);
+ twe_ccb_free(twe, ccb);
+ splx(s);
+ } else {
+ ccb->ccb_tx.tx_handler = twe_ccb_wait_handler;
+ ccb->ccb_tx.tx_context = NULL;
+ ccb->ccb_tx.tx_dv = &ld->sc_dv;
+ twe_ccb_enqueue(twe, ccb);
+
+ rv = 0;
+ s = splbio();
+ while ((ccb->ccb_flags & TWE_CCB_COMPLETE) == 0)
+ if ((rv = tsleep(ccb, PRIBIO, "tweflush",
+ 60 * hz)) != 0)
+ break;
+ twe_ccb_free(twe, ccb);
+ splx(s);
+ }
return (rv);
}
Home |
Main Index |
Thread Index |
Old Index