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