kernel - Run AHCI and SILI disk drivers MPSAFE
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 25 Aug 2010 18:40:58 +0000 (11:40 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 25 Aug 2010 18:40:58 +0000 (11:40 -0700)
* These drivers now pass a port-disk-port lock in the cam sim registration,
  which should result in CAM callbacks being MPSAFE.

* Add a separate signalling interlock for the port threads.

* The devices were otherwise already MPSAFE, with per-port locking.

12 files changed:
sys/dev/disk/ahci/ahci.c
sys/dev/disk/ahci/ahci.h
sys/dev/disk/ahci/ahci_attach.c
sys/dev/disk/ahci/ahci_cam.c
sys/dev/disk/ahci/ahci_dragonfly.c
sys/dev/disk/ahci/ahci_pm.c
sys/dev/disk/sili/sili.c
sys/dev/disk/sili/sili.h
sys/dev/disk/sili/sili_attach.c
sys/dev/disk/sili/sili_cam.c
sys/dev/disk/sili/sili_dragonfly.c
sys/dev/disk/sili/sili_pm.c

index a290e06..fd8be79 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
index e1f7c0c..34c3518 100644 (file)
@@ -383,6 +383,8 @@ struct ahci_port {
        int                     ap_signal;      /* os per-port thread sig */
        thread_t                ap_thread;      /* os per-port thread */
        struct lock             ap_lock;        /* os per-port lock */
+       struct lock             ap_sim_lock;    /* cam sim lock */
+       struct lock             ap_sig_lock;    /* signal thread */
 #define AP_SIGF_INIT           0x0001
 #define AP_SIGF_TIMEOUT                0x0002
 #define AP_SIGF_PORTINT                0x0004
index b999595..fc15bd7 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -413,7 +415,8 @@ noccc:
         * ready to go.
         */
        if (error == 0) {
-               error = bus_setup_intr(dev, sc->sc_irq, 0, ahci_intr, sc,
+               error = bus_setup_intr(dev, sc->sc_irq, INTR_MPSAFE,
+                                      ahci_intr, sc,
                                       &sc->sc_irq_handle, NULL);
        }
 
index e7bcc07..cc86c0f 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
@@ -105,14 +107,16 @@ ahci_cam_attach(struct ahci_port *ap)
                return (ENOMEM);
        }
        sim = cam_sim_alloc(ahci_xpt_action, ahci_xpt_poll, "ahci",
-                          (void *)ap, unit, &sim_mplock, 1, 1, devq);
+                          (void *)ap, unit, &ap->ap_sim_lock, 1, 1, devq);
        cam_simq_release(devq);
        if (sim == NULL) {
                return (ENOMEM);
        }
        ap->ap_sim = sim;
        ahci_os_unlock_port(ap);
+       lockmgr(&ap->ap_sim_lock, LK_EXCLUSIVE);
        error = xpt_bus_register(ap->ap_sim, ap->ap_num);
+       lockmgr(&ap->ap_sim_lock, LK_RELEASE);
        ahci_os_lock_port(ap);
        if (error != CAM_SUCCESS) {
                ahci_cam_detach(ap);
@@ -190,7 +194,7 @@ ahci_cam_detach(struct ahci_port *ap)
 
        if ((ap->ap_flags & AP_F_CAM_ATTACHED) == 0)
                return;
-       get_mplock();
+       lockmgr(&ap->ap_sim_lock, LK_EXCLUSIVE);
        if (ap->ap_sim) {
                xpt_freeze_simq(ap->ap_sim, 1);
        }
@@ -203,7 +207,7 @@ ahci_cam_detach(struct ahci_port *ap)
                cam_sim_free(ap->ap_sim);
                ap->ap_sim = NULL;
        }
-       rel_mplock();
+       lockmgr(&ap->ap_sim_lock, LK_RELEASE);
        ap->ap_flags &= ~AP_F_CAM_ATTACHED;
 }
 
index 407827c..fc8b6fc 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
@@ -245,6 +247,8 @@ ahci_os_start_port(struct ahci_port *ap)
 
        atomic_set_int(&ap->ap_signal, AP_SIGF_INIT | AP_SIGF_THREAD_SYNC);
        lockinit(&ap->ap_lock, "ahcipo", 0, 0);
+       lockinit(&ap->ap_sim_lock, "ahcicam", 0, LK_CANRECURSE);
+       lockinit(&ap->ap_sig_lock, "ahport", 0, 0);
        sysctl_ctx_init(&ap->sysctl_ctx);
        ksnprintf(name, sizeof(name), "%d", ap->ap_num);
        ap->sysctl_tree = SYSCTL_ADD_NODE(&ap->sysctl_ctx,
@@ -304,8 +308,10 @@ ahci_os_stop_port(struct ahci_port *ap)
 void
 ahci_os_signal_port_thread(struct ahci_port *ap, int mask)
 {
+       lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE);
        atomic_set_int(&ap->ap_signal, mask);
        wakeup(&ap->ap_thread);
+       lockmgr(&ap->ap_sig_lock, LK_RELEASE);
 }
 
 /*
@@ -349,6 +355,8 @@ ahci_port_thread(void *arg)
        struct ahci_port *ap = arg;
        int mask;
 
+       rel_mplock();
+
        /*
         * The helper thread is responsible for the initial port init,
         * so all the ports can be inited in parallel.
@@ -373,9 +381,12 @@ ahci_port_thread(void *arg)
        while ((mask & AP_SIGF_STOP) == 0) {
                atomic_clear_int(&ap->ap_signal, mask);
                ahci_port_thread_core(ap, mask);
-               tsleep_interlock(&ap->ap_thread, 0);
-               if (ap->ap_signal == 0)
-                       tsleep(&ap->ap_thread, PINTERLOCKED, "ahport", 0);
+               lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE);
+               if (ap->ap_signal == 0) {
+                       lksleep(&ap->ap_thread, &ap->ap_sig_lock, 0,
+                               "ahport", 0);
+               }
+               lockmgr(&ap->ap_sig_lock, LK_RELEASE);
                mask = ap->ap_signal;
        }
        ap->ap_thread = NULL;
index 31a62a3..742338c 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
index efe0114..a3c2c65 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
index a6d4fcc..8f89419 100644 (file)
@@ -757,6 +757,8 @@ struct sili_port {
        int                     ap_signal;      /* os per-port thread sig */
        thread_t                ap_thread;      /* os per-port thread */
        struct lock             ap_lock;        /* os per-port lock */
+       struct lock             ap_sim_lock;    /* cam sim lock */
+       struct lock             ap_sig_lock;    /* signal thread */
 #define AP_SIGF_INIT           0x0001
 #define AP_SIGF_TIMEOUT                0x0002
 #define AP_SIGF_PORTINT                0x0004
index 31f87bb..bd065ae 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -256,7 +258,8 @@ sili_pci_attach(device_t dev)
         * ready to go.
         */
        if (error == 0) {
-               error = bus_setup_intr(dev, sc->sc_irq, 0, sili_intr, sc,
+               error = bus_setup_intr(dev, sc->sc_irq, INTR_MPSAFE,
+                                      sili_intr, sc,
                                       &sc->sc_irq_handle, NULL);
        }
 
index 1b9d619..d7a43fb 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
@@ -105,14 +107,16 @@ sili_cam_attach(struct sili_port *ap)
                return (ENOMEM);
        }
        sim = cam_sim_alloc(sili_xpt_action, sili_xpt_poll, "sili",
-                          (void *)ap, unit, &sim_mplock, 1, 1, devq);
+                          (void *)ap, unit, &ap->ap_sim_lock, 1, 1, devq);
        cam_simq_release(devq);
        if (sim == NULL) {
                return (ENOMEM);
        }
        ap->ap_sim = sim;
        sili_os_unlock_port(ap);
+       lockmgr(&ap->ap_sim_lock, LK_EXCLUSIVE);
        error = xpt_bus_register(ap->ap_sim, ap->ap_num);
+       lockmgr(&ap->ap_sim_lock, LK_RELEASE);
        sili_os_lock_port(ap);
        if (error != CAM_SUCCESS) {
                sili_cam_detach(ap);
@@ -190,7 +194,7 @@ sili_cam_detach(struct sili_port *ap)
 
        if ((ap->ap_flags & AP_F_CAM_ATTACHED) == 0)
                return;
-       get_mplock();
+       lockmgr(&ap->ap_sim_lock, LK_EXCLUSIVE);
        if (ap->ap_sim) {
                xpt_freeze_simq(ap->ap_sim, 1);
        }
@@ -203,7 +207,7 @@ sili_cam_detach(struct sili_port *ap)
                cam_sim_free(ap->ap_sim);
                ap->ap_sim = NULL;
        }
-       rel_mplock();
+       lockmgr(&ap->ap_sim_lock, LK_RELEASE);
        ap->ap_flags &= ~AP_F_CAM_ATTACHED;
 }
 
index 3de0914..e2641b6 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
@@ -194,6 +196,8 @@ sili_os_start_port(struct sili_port *ap)
 {
        atomic_set_int(&ap->ap_signal, AP_SIGF_INIT);
        lockinit(&ap->ap_lock, "silipo", 0, 0);
+       lockinit(&ap->ap_sim_lock, "silicam", 0, LK_CANRECURSE);
+       lockinit(&ap->ap_sig_lock, "siport", 0, 0);
        kthread_create(sili_port_thread, ap, &ap->ap_thread,
                       "%s", PORTNAME(ap));
 }
@@ -226,8 +230,10 @@ sili_os_stop_port(struct sili_port *ap)
 void
 sili_os_signal_port_thread(struct sili_port *ap, int mask)
 {
+       lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE);
        atomic_set_int(&ap->ap_signal, mask);
        wakeup(&ap->ap_thread);
+       lockmgr(&ap->ap_sig_lock, LK_RELEASE);
 }
 
 /*
@@ -271,6 +277,8 @@ sili_port_thread(void *arg)
        struct sili_port *ap = arg;
        int mask;
 
+       rel_mplock();
+
        /*
         * The helper thread is responsible for the initial port init,
         * so all the ports can be inited in parallel.
@@ -293,9 +301,12 @@ sili_port_thread(void *arg)
        while ((mask & AP_SIGF_STOP) == 0) {
                atomic_clear_int(&ap->ap_signal, mask);
                sili_port_thread_core(ap, mask);
-               tsleep_interlock(&ap->ap_thread, 0);
-               if (ap->ap_signal == 0)
-                       tsleep(&ap->ap_thread, PINTERLOCKED, "ahport", 0);
+               lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE);
+               if (ap->ap_signal == 0) {
+                       lksleep(&ap->ap_thread, &ap->ap_sig_lock, 0,
+                               "siport", 0);
+               }
+               lockmgr(&ap->ap_sig_lock, LK_RELEASE);
                mask = ap->ap_signal;
        }
        ap->ap_thread = NULL;
index 53ec22b..2b09d5b 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project