⬢ DragonFlyBSD Kernel Audit
DF-4401 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/tws/tws_cam.c
+++ b/sys/dev/raid/tws/tws_cam.c
@@ -1200,11 +1200,14 @@
 
     struct tws_softc *sc = (struct tws_softc *)arg;
 
+    /* Serialize entry: check the state under the lock it transitions under
+     * (callers: ccb-timeout callout, attn-error interrupt, passthru ioctl). */
+    lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
     if ( tws_get_state(sc) == TWS_RESET ) {
+        lockmgr(&sc->gen_lock, LK_RELEASE);
         return;
     }
     device_printf(sc->tws_dev,  "Resetting controller\n");
-    lockmgr(&sc->gen_lock, LK_EXCLUSIVE);
     tws_send_event(sc, TWS_RESET_START);
     lockmgr(&sc->gen_lock, LK_RELEASE);
 
@@ -1243,22 +1246,23 @@
 {
 
     struct tws_softc *sc = (struct tws_softc *)arg;
-    static int timeout_val=0, try=2  ;
+    int *timeout_val = &sc->reinit_timeout_val; /* per-adapter, not static */
+    int *try = &sc->reinit_try;
 
     if ( !tws_ctlr_ready(sc) ) {
-        timeout_val += 5;
-        if ( timeout_val >= TWS_RESET_TIMEOUT ) {
-           timeout_val = 0;
-           if ( try )
+        *timeout_val += 5;
+        if ( *timeout_val >= TWS_RESET_TIMEOUT ) {
+           *timeout_val = 0;
+           if ( *try )
                tws_assert_soft_reset(sc);
-           try--;
+           (*try)--;
         }
 	callout_reset(&sc->reinit_handle, 5*hz, tws_reinit, sc);
         return;
     }
 
-    timeout_val=0;
-    try = 2;
+    *timeout_val = 0;
+    *try = 2;
     sc->obfl_q_overrun = false;
     if ( tws_init_connect(sc, tws_queue_depth) ) {
         TWS_TRACE_DEBUG(sc, "initConnect failed", 0, sc->is64bit);
--- a/sys/dev/raid/tws/tws.h
+++ b/sys/dev/raid/tws/tws.h
@@ -256,6 +256,8 @@
     struct tws_request *reqs;             /* pointer to requests */
     struct tws_sense *sense_bufs;         /* pointer to sense buffers */
     boolean obfl_q_overrun;               /* OBFL overrun flag  */
+    int     reinit_timeout_val;           /* per-adapter reinit retry cnt */
+    int     reinit_try;
     union ccb *scan_ccb;                  /* pointer to a ccb */
     struct tws_request *q_head[TWS_MAX_QS]; /* head pointers to q's */
     struct tws_request *q_tail[TWS_MAX_QS]; /* tail pointers to q's */