This converts softraid from scheduling IO in interrupt context to a
workq.  It also kills most spl dances since we needed to protect the
queues with a mutex anyway.

I am testing this with RAID 0, 1, 5 & 6 + crypto but I really could use
some eyes on this and lots and lots of testing.

The failure paths for RAID 1, 4, 5 & 6 are especially suspect at this
point.

Index: softraid.c
===================================================================
RCS file: /cvs/src/sys/dev/softraid.c,v
retrieving revision 1.210
diff -u -p -r1.210 softraid.c
--- softraid.c  3 Jul 2010 03:04:55 -0000       1.210
+++ softraid.c  29 Jul 2010 20:37:32 -0000
@@ -571,16 +571,12 @@ void
 sr_meta_save_callback(void *arg1, void *arg2)
 {
        struct sr_discipline    *sd = arg1;
-       int                     s;
-
-       s = splbio();
 
        if (sr_meta_save(arg1, SR_META_DIRTY))
                printf("%s: save metadata failed\n",
                    DEVNAME(sd->sd_sc));
 
        sd->sd_must_flush = 0;
-       splx(s);
 }
 
 int
@@ -1637,12 +1633,14 @@ sr_ccb_alloc(struct sr_discipline *sd)
 
        sd->sd_ccb = malloc(sizeof(struct sr_ccb) *
            sd->sd_max_wu * sd->sd_max_ccb_per_wu, M_DEVBUF, M_WAITOK | M_ZERO);
+       mtx_enter(&sd->sd_mtx); /* need this for sr_ccb_put */
        TAILQ_INIT(&sd->sd_ccb_freeq);
        for (i = 0; i < sd->sd_max_wu * sd->sd_max_ccb_per_wu; i++) {
                ccb = &sd->sd_ccb[i];
                ccb->ccb_dis = sd;
                sr_ccb_put(ccb);
        }
+       mtx_leave(&sd->sd_mtx);
 
        DNPRINTF(SR_D_CCB, "%s: sr_ccb_alloc ccb: %d\n",
            DEVNAME(sd->sd_sc), sd->sd_max_wu * sd->sd_max_ccb_per_wu);
@@ -1660,8 +1658,10 @@ sr_ccb_free(struct sr_discipline *sd)
 
        DNPRINTF(SR_D_CCB, "%s: sr_ccb_free %p\n", DEVNAME(sd->sd_sc), sd);
 
+       mtx_enter(&sd->sd_mtx);
        while ((ccb = TAILQ_FIRST(&sd->sd_ccb_freeq)) != NULL)
                TAILQ_REMOVE(&sd->sd_ccb_freeq, ccb, ccb_link);
+       mtx_leave(&sd->sd_mtx);
 
        if (sd->sd_ccb)
                free(sd->sd_ccb, M_DEVBUF);
@@ -1671,9 +1671,8 @@ struct sr_ccb *
 sr_ccb_get(struct sr_discipline *sd)
 {
        struct sr_ccb           *ccb;
-       int                     s;
 
-       s = splbio();
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
 
        ccb = TAILQ_FIRST(&sd->sd_ccb_freeq);
        if (ccb) {
@@ -1681,8 +1680,6 @@ sr_ccb_get(struct sr_discipline *sd)
                ccb->ccb_state = SR_CCB_INPROGRESS;
        }
 
-       splx(s);
-
        DNPRINTF(SR_D_CCB, "%s: sr_ccb_get: %p\n", DEVNAME(sd->sd_sc),
            ccb);
 
@@ -1693,21 +1690,18 @@ void
 sr_ccb_put(struct sr_ccb *ccb)
 {
        struct sr_discipline    *sd = ccb->ccb_dis;
-       int                     s;
+
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
 
        DNPRINTF(SR_D_CCB, "%s: sr_ccb_put: %p\n", DEVNAME(sd->sd_sc),
            ccb);
 
-       s = splbio();
-
        ccb->ccb_wu = NULL;
        ccb->ccb_state = SR_CCB_FREE;
        ccb->ccb_target = -1;
        ccb->ccb_opaque = NULL;
 
        TAILQ_INSERT_TAIL(&sd->sd_ccb_freeq, ccb, ccb_link);
-
-       splx(s);
 }
 
 int
@@ -1726,13 +1720,15 @@ sr_wu_alloc(struct sr_discipline *sd)
                return (1);
 
        no_wu = sd->sd_max_wu;
-       sd->sd_wu_pending = no_wu;
 
        sd->sd_wu = malloc(sizeof(struct sr_workunit) * no_wu,
            M_DEVBUF, M_WAITOK | M_ZERO);
+       mtx_enter(&sd->sd_mtx);
+       sd->sd_wu_pending = no_wu;
        TAILQ_INIT(&sd->sd_wu_freeq);
        TAILQ_INIT(&sd->sd_wu_pendq);
        TAILQ_INIT(&sd->sd_wu_defq);
+       mtx_leave(&sd->sd_mtx);
        for (i = 0; i < no_wu; i++) {
                wu = &sd->sd_wu[i];
                wu->swu_dis = sd;
@@ -1752,12 +1748,14 @@ sr_wu_free(struct sr_discipline *sd)
 
        DNPRINTF(SR_D_WU, "%s: sr_wu_free %p\n", DEVNAME(sd->sd_sc), sd);
 
+       mtx_enter(&sd->sd_mtx);
        while ((wu = TAILQ_FIRST(&sd->sd_wu_freeq)) != NULL)
                TAILQ_REMOVE(&sd->sd_wu_freeq, wu, swu_link);
        while ((wu = TAILQ_FIRST(&sd->sd_wu_pendq)) != NULL)
                TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link);
        while ((wu = TAILQ_FIRST(&sd->sd_wu_defq)) != NULL)
                TAILQ_REMOVE(&sd->sd_wu_defq, wu, swu_link);
+       mtx_leave(&sd->sd_mtx);
 
        if (sd->sd_wu)
                free(sd->sd_wu, M_DEVBUF);
@@ -1769,12 +1767,8 @@ sr_wu_put(struct sr_workunit *wu)
        struct sr_discipline    *sd = wu->swu_dis;
        struct sr_ccb           *ccb;
 
-       int                     s;
-
        DNPRINTF(SR_D_WU, "%s: sr_wu_put: %p\n", DEVNAME(sd->sd_sc), wu);
 
-       s = splbio();
-
        wu->swu_xs = NULL;
        wu->swu_state = SR_WU_FREE;
        wu->swu_ios_complete = 0;
@@ -1787,6 +1781,7 @@ sr_wu_put(struct sr_workunit *wu)
        wu->swu_fake = 0;
        wu->swu_flags = 0;
 
+       mtx_enter(&sd->sd_mtx);
        while ((ccb = TAILQ_FIRST(&wu->swu_ccb)) != NULL) {
                TAILQ_REMOVE(&wu->swu_ccb, ccb, ccb_link);
                sr_ccb_put(ccb);
@@ -1804,17 +1799,15 @@ sr_wu_put(struct sr_workunit *wu)
        if (sd->sd_wu_sleep)
                wakeup(&sd->sd_wu_sleep);
 
-       splx(s);
+       mtx_leave(&sd->sd_mtx);
 }
 
 struct sr_workunit *
 sr_wu_get(struct sr_discipline *sd, int canwait)
 {
        struct sr_workunit      *wu;
-       int                     s;
-
-       s = splbio();
 
+       mtx_enter(&sd->sd_mtx);
        for (;;) {
                wu = TAILQ_FIRST(&sd->sd_wu_freeq);
                if (wu) {
@@ -1824,13 +1817,13 @@ sr_wu_get(struct sr_discipline *sd, int 
                        break;
                } else if (wu == NULL && canwait) {
                        sd->sd_wu_sleep++;
-                       tsleep(&sd->sd_wu_sleep, PRIBIO, "sr_wu_get", 0);
+                       msleep(&sd->sd_wu_sleep, &sd->sd_mtx, PRIBIO,
+                           "sr_wu_get", 0);
                        sd->sd_wu_sleep--;
                } else
                        break;
        }
-
-       splx(s);
+       mtx_leave(&sd->sd_mtx);
 
        DNPRINTF(SR_D_WU, "%s: sr_wu_get: %p\n", DEVNAME(sd->sd_sc), wu);
 
@@ -2542,7 +2535,7 @@ sr_hotspare_rebuild(struct sr_discipline
                do {
                        busy = 0;
 
-                       s = splbio();
+                       mtx_enter(&sd->sd_mtx);
                        TAILQ_FOREACH(wu, &sd->sd_wu_pendq, swu_link) {
                                TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link) {
                                        if (ccb->ccb_target == chunk_no)
@@ -2555,7 +2548,7 @@ sr_hotspare_rebuild(struct sr_discipline
                                                busy = 1;
                                }
                        }
-                       splx(s);
+                       mtx_leave(&sd->sd_mtx);
 
                        if (busy) {
                                tsleep(sd, PRIBIO, "sr_hotspare", hz);
@@ -2795,6 +2788,12 @@ sr_ioctl_createraid(struct sr_softc *sc,
        sd = malloc(sizeof(struct sr_discipline), M_DEVBUF, M_WAITOK | M_ZERO);
        sd->sd_sc = sc;
        SLIST_INIT(&sd->sd_meta_opt);
+       mtx_init(&sd->sd_mtx, IPL_BIO);
+       sd->sd_workq = workq_create("srdis", 1, IPL_BIO);
+       if (sd->sd_workq == NULL) {
+               printf("%s: could not create workq\n");
+               goto unwind;
+       }
        if (sr_discipline_init(sd, bc->bc_level)) {
                printf("%s: could not initialize discipline\n", DEVNAME(sc));
                goto unwind;
@@ -2955,7 +2954,9 @@ sr_ioctl_createraid(struct sr_softc *sc,
 
        if (sd->sd_capabilities & SR_CAP_SYSTEM_DISK) {
                /* set volume status */
+               mtx_enter(&sd->sd_mtx);
                sd->sd_set_vol_state(sd);
+               mtx_leave(&sd->sd_mtx);
                if (sd->sd_vol_status == BIOC_SVOFFLINE) {
                        printf("%s: %s offline, will not be brought online\n",
                            DEVNAME(sc), sd->sd_meta->ssd_devname);
@@ -3353,7 +3354,6 @@ void
 sr_discipline_shutdown(struct sr_discipline *sd)
 {
        struct sr_softc         *sc = sd->sd_sc;
-       int                     s;
 
        if (!sd || !sc)
                return;
@@ -3361,8 +3361,6 @@ sr_discipline_shutdown(struct sr_discipl
        DNPRINTF(SR_D_DIS, "%s: sr_discipline_shutdown %s\n", DEVNAME(sc),
            sd->sd_meta ? sd->sd_meta->ssd_devname : "nodev");
 
-       s = splbio();
-
        sd->sd_ready = 0;
 
        if (sd->sd_shutdownhook)
@@ -3384,10 +3382,11 @@ sr_discipline_shutdown(struct sr_discipl
 
        sr_chunks_unwind(sc, &sd->sd_vol.sv_chunk_list);
 
+       if (sd->sd_workq)
+               workq_destroy(sd->sd_workq);
+
        if (sd)
                sr_discipline_free(sd);
-
-       splx(s);
 }
 
 int
@@ -3574,14 +3573,13 @@ int
 sr_raid_sync(struct sr_workunit *wu)
 {
        struct sr_discipline    *sd = wu->swu_dis;
-       int                     s, rv = 0, ios;
+       int                     rv = 0, ios;
 
        DNPRINTF(SR_D_DIS, "%s: sr_raid_sync\n", DEVNAME(sd->sd_sc));
 
        /* when doing a fake sync don't count the wu */
        ios = wu->swu_fake ? 0 : 1;
 
-       s = splbio();
        sd->sd_sync = 1;
 
        while (sd->sd_wu_pending > ios)
@@ -3593,20 +3591,32 @@ sr_raid_sync(struct sr_workunit *wu)
                }
 
        sd->sd_sync = 0;
-       splx(s);
 
        wakeup(&sd->sd_sync);
 
        return (rv);
 }
 
+void sr_startwu_callback(void *, void *);
+void
+sr_startwu_callback(void *arg1, void *arg2)
+{
+       struct sr_discipline    *sd = arg1;
+       struct sr_workunit      *wu = arg2;
+       struct sr_ccb           *ccb;
+
+       mtx_enter(&sd->sd_mtx);
+       TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link)
+               VOP_STRATEGY(&ccb->ccb_buf);
+       mtx_leave(&sd->sd_mtx);
+}
+
 void
 sr_raid_startwu(struct sr_workunit *wu)
 {
        struct sr_discipline    *sd = wu->swu_dis;
-       struct sr_ccb           *ccb;
 
-       splassert(IPL_BIO);
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
 
        if (wu->swu_state == SR_WU_RESTART)
                /*
@@ -3619,9 +3629,7 @@ sr_raid_startwu(struct sr_workunit *wu)
                TAILQ_INSERT_TAIL(&sd->sd_wu_pendq, wu, swu_link);
 
        /* start all individual ios */
-       TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link) {
-               VOP_STRATEGY(&ccb->ccb_buf);
-       }
+       workq_add_task(sd->sd_workq, WQ_WAITOK, sr_startwu_callback, sd, wu);
 }
 
 void
@@ -3799,7 +3807,7 @@ sr_check_io_collision(struct sr_workunit
        struct sr_discipline    *sd = wu->swu_dis;
        struct sr_workunit      *wup;
 
-       splassert(IPL_BIO);
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
 
        /* walk queue backwards and fill in collider if we have one */
        TAILQ_FOREACH_REVERSE(wup, &sd->sd_wu_pendq, sr_wu_list, swu_link) {
@@ -3848,7 +3856,7 @@ sr_rebuild_thread(void *arg)
        struct sr_workunit      *wu_r, *wu_w;
        struct scsi_xfer        xs_r, xs_w;
        struct scsi_rw_16       cr, cw;
-       int                     c, s, slept, percent = 0, old_percent = -1;
+       int                     c, slept, percent = 0, old_percent = -1;
        u_int8_t                *buf;
 
        whole_blk = sd->sd_meta->ssdi.ssd_size / SR_REBUILD_IO_SIZE;
@@ -3943,16 +3951,13 @@ sr_rebuild_thread(void *arg)
                 */
                wu_w->swu_state = SR_WU_DEFERRED;
                wu_r->swu_collider = wu_w;
-               s = splbio();
-               TAILQ_INSERT_TAIL(&sd->sd_wu_defq, wu_w, swu_link);
 
+               mtx_enter(&sd->sd_mtx);
+               TAILQ_INSERT_TAIL(&sd->sd_wu_defq, wu_w, swu_link);
                /* schedule io */
-               if (sr_check_io_collision(wu_r))
-                       goto queued;
-
-               sr_raid_startwu(wu_r);
-queued:
-               splx(s);
+               if (sr_check_io_collision(wu_r) == 0)
+                       sr_raid_startwu(wu_r);
+               mtx_leave(&sd->sd_mtx);
 
                /* wait for read completion */
                slept = 0;
Index: softraid_crypto.c
===================================================================
RCS file: /cvs/src/sys/dev/softraid_crypto.c,v
retrieving revision 1.54
diff -u -p -r1.54 softraid_crypto.c
--- softraid_crypto.c   2 Jul 2010 09:26:05 -0000       1.54
+++ softraid_crypto.c   29 Jul 2010 19:11:45 -0000
@@ -1134,7 +1134,6 @@ sr_crypto_rw(struct sr_workunit *wu)
 int
 sr_crypto_write(struct cryptop *crp)
 {
-       int                     s;
        struct sr_workunit      *wu = crp->crp_opaque;
 
        DNPRINTF(SR_D_INTR, "%s: sr_crypto_write: wu %x xs: %x\n",
@@ -1144,9 +1143,7 @@ sr_crypto_write(struct cryptop *crp)
                /* fail io */
                ((struct sr_workunit *)(crp->crp_opaque))->swu_xs->error =
                    XS_DRIVER_STUFFUP;
-               s = splbio();
                sr_crypto_finish_io(crp->crp_opaque);
-               splx(s);
        }
 
        return (sr_crypto_rw2(wu, crp));
@@ -1159,7 +1156,6 @@ sr_crypto_rw2(struct sr_workunit *wu, st
        struct scsi_xfer        *xs = wu->swu_xs;
        struct sr_ccb           *ccb;
        struct uio              *uio;
-       int                     s;
        daddr64_t               blk;
 
        if (sr_validate_io(wu, &blk, "sr_crypto_rw2"))
@@ -1169,7 +1165,9 @@ sr_crypto_rw2(struct sr_workunit *wu, st
 
        wu->swu_io_count = 1;
 
+       mtx_enter(&sd->sd_mtx);
        ccb = sr_ccb_get(sd);
+       mtx_leave(&sd->sd_mtx);
        if (!ccb) {
                /* should never happen but handle more gracefully */
                printf("%s: %s: too many ccbs queued\n",
@@ -1205,7 +1203,9 @@ sr_crypto_rw2(struct sr_workunit *wu, st
 
        LIST_INIT(&ccb->ccb_buf.b_dep);
 
+       mtx_enter(&sd->sd_mtx);
        TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
+       mtx_leave(&sd->sd_mtx);
 
        DNPRINTF(SR_D_DIS, "%s: %s: sr_crypto_rw2: b_bcount: %d "
            "b_blkno: %x b_flags 0x%0x b_data %p\n",
@@ -1213,15 +1213,11 @@ sr_crypto_rw2(struct sr_workunit *wu, st
            ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_blkno,
            ccb->ccb_buf.b_flags, ccb->ccb_buf.b_data);
 
-       s = splbio();
+       mtx_enter(&sd->sd_mtx);
+       if (sr_check_io_collision(wu) == 0)
+               sr_raid_startwu(wu);
+       mtx_leave(&sd->sd_mtx);
 
-       if (sr_check_io_collision(wu))
-               goto queued;
-
-       sr_raid_startwu(wu);
-
-queued:
-       splx(s);
        return (0);
 bad:
        /* wu is unwound by sr_wu_put */
@@ -1239,7 +1235,7 @@ sr_crypto_intr(struct buf *bp)
        struct scsi_xfer        *xs = wu->swu_xs;
        struct sr_softc         *sc = sd->sd_sc;
        struct cryptop          *crp;
-       int                     s, s2, pend;
+       int                     s, pend;
 
        DNPRINTF(SR_D_INTR, "%s: sr_crypto_intr bp: %x xs: %x\n",
            DEVNAME(sc), bp, wu->swu_xs);
@@ -1248,8 +1244,6 @@ sr_crypto_intr(struct buf *bp)
            " b_flags: 0x%0x\n", DEVNAME(sc), ccb->ccb_buf.b_bcount,
            ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags);
 
-       s = splbio();
-
        if (ccb->ccb_buf.b_flags & B_ERROR) {
                printf("%s: i/o error on block %lld\n", DEVNAME(sc),
                    ccb->ccb_buf.b_blkno);
@@ -1276,6 +1270,7 @@ sr_crypto_intr(struct buf *bp)
                        xs->error = XS_NOERROR;
 
                pend = 0;
+               mtx_enter(&sd->sd_mtx);
                TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
                        if (wu == wup) {
                                TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link);
@@ -1291,6 +1286,7 @@ sr_crypto_intr(struct buf *bp)
                                break;
                        }
                }
+               mtx_leave(&sd->sd_mtx);
 
                if (!pend)
                        printf("%s: wu: %p not on pending queue\n",
@@ -1303,17 +1299,14 @@ sr_crypto_intr(struct buf *bp)
                        crp->crp_opaque = wu;
                        DNPRINTF(SR_D_INTR, "%s: sr_crypto_intr: crypto_invoke "
                            "%p\n", DEVNAME(sc), crp);
-                       s2 = splvm();
+                       s = splvm();
                        crypto_invoke(crp);
-                       splx(s2);
-                       goto done;
+                       splx(s);
+                       return;
                }
 
                sr_crypto_finish_io(wu);
        }
-
-done:
-       splx(s);
 }
 
 void
@@ -1326,18 +1319,18 @@ sr_crypto_finish_io(struct sr_workunit *
        struct sr_softc         *sc = sd->sd_sc;
 #endif /* SR_DEBUG */
 
-       splassert(IPL_BIO);
-
        DNPRINTF(SR_D_INTR, "%s: sr_crypto_finish_io: wu %x xs: %x\n",
            DEVNAME(sc), wu, xs);
 
        xs->resid = 0;
 
+       mtx_enter(&sd->sd_mtx);
        TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link) {
                if (ccb->ccb_opaque == NULL)
                        continue;
                sr_crypto_putcryptop(ccb->ccb_opaque);
        }
+       mtx_leave(&sd->sd_mtx);
 
        /* do not change the order of these 2 functions */
        sr_wu_put(wu);
@@ -1350,7 +1343,6 @@ sr_crypto_finish_io(struct sr_workunit *
 int
 sr_crypto_read(struct cryptop *crp)
 {
-       int                     s;
        struct sr_workunit      *wu = crp->crp_opaque;
 
        DNPRINTF(SR_D_INTR, "%s: sr_crypto_read: wu %x xs: %x\n",
@@ -1359,9 +1351,7 @@ sr_crypto_read(struct cryptop *crp)
        if (crp->crp_etype)
                wu->swu_xs->error = XS_DRIVER_STUFFUP;
 
-       s = splbio();
        sr_crypto_finish_io(wu);
-       splx(s);
 
        return (0);
 }
Index: softraid_raid0.c
===================================================================
RCS file: /cvs/src/sys/dev/softraid_raid0.c,v
retrieving revision 1.22
diff -u -p -r1.22 softraid_raid0.c
--- softraid_raid0.c    2 Jul 2010 09:20:26 -0000       1.22
+++ softraid_raid0.c    29 Jul 2010 18:51:26 -0000
@@ -166,14 +166,13 @@ sr_raid0_free_resources(struct sr_discip
 void
 sr_raid0_set_chunk_state(struct sr_discipline *sd, int c, int new_state)
 {
-       int                     old_state, s;
+       int                     old_state;
 
        DNPRINTF(SR_D_STATE, "%s: %s: %s: sr_raid_set_chunk_state %d -> %d\n",
            DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname,
            sd->sd_vol.sv_chunks[c]->src_meta.scmi.scm_devname, c, new_state);
 
-       /* ok to go to splbio since this only happens in error path */
-       s = splbio();
+       mtx_enter(&sd->sd_mtx);
        old_state = sd->sd_vol.sv_chunks[c]->src_meta.scm_status;
 
        /* multiple IOs to the same chunk that fail will come through here */
@@ -193,7 +192,7 @@ sr_raid0_set_chunk_state(struct sr_disci
 
        default:
 die:
-               splx(s); /* XXX */
+               mtx_leave(&sd->sd_mtx); /* XXX */
                panic("%s: %s: %s: invalid chunk state transition "
                    "%d -> %d\n", DEVNAME(sd->sd_sc),
                    sd->sd_meta->ssd_devname,
@@ -208,7 +207,7 @@ die:
        sd->sd_must_flush = 1;
        workq_add_task(NULL, 0, sr_meta_save_callback, sd, NULL);
 done:
-       splx(s);
+       mtx_leave(&sd->sd_mtx);
 }
 
 void
@@ -218,6 +217,8 @@ sr_raid0_set_vol_state(struct sr_discipl
        int                     new_state, i, s, nd;
        int                     old_state = sd->sd_vol_status;
 
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+
        DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state\n",
            DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname);
 
@@ -276,7 +277,6 @@ sr_raid0_rw(struct sr_workunit *wu)
        struct scsi_xfer        *xs = wu->swu_xs;
        struct sr_ccb           *ccb;
        struct sr_chunk         *scp;
-       int                     s;
        daddr64_t               blk, lbaoffs, strip_no, chunk, stripoffs;
        daddr64_t               strip_size, no_chunk, chunkoffs, physoffs;
        daddr64_t               strip_bits, length, leftover;
@@ -312,7 +312,9 @@ sr_raid0_rw(struct sr_workunit *wu)
                        goto bad;
                }
 
+               mtx_enter(&sd->sd_mtx);
                ccb = sr_ccb_get(sd);
+               mtx_leave(&sd->sd_mtx);
                if (!ccb) {
                        /* should never happen but handle more gracefully */
                        printf("%s: %s: too many ccbs queued\n",
@@ -348,7 +350,9 @@ sr_raid0_rw(struct sr_workunit *wu)
                if ((ccb->ccb_buf.b_flags & B_READ) == 0)
                        ccb->ccb_buf.b_vp->v_numoutput++;
                LIST_INIT(&ccb->ccb_buf.b_dep);
+               mtx_enter(&sd->sd_mtx);
                TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
+               mtx_leave(&sd->sd_mtx);
 
                DNPRINTF(SR_D_DIS, "%s: %s: sr_raid0: b_bcount: %d "
                    "b_blkno: %lld b_flags 0x%0x b_data %p\n",
@@ -369,14 +373,11 @@ sr_raid0_rw(struct sr_workunit *wu)
                length = MIN(leftover,strip_size);
        }
 
-       s = splbio();
-
-       if (sr_check_io_collision(wu))
-               goto queued;
+       mtx_enter(&sd->sd_mtx);
+       if (sr_check_io_collision(wu) == 0)
+               sr_raid_startwu(wu);
+       mtx_leave(&sd->sd_mtx);
 
-       sr_raid_startwu(wu);
-queued:
-       splx(s);
        return (0);
 bad:
        /* wu is unwound by sr_wu_put */
@@ -391,7 +392,7 @@ sr_raid0_intr(struct buf *bp)
        struct sr_discipline    *sd = wu->swu_dis;
        struct scsi_xfer        *xs = wu->swu_xs;
        struct sr_softc         *sc = sd->sd_sc;
-       int                     s, pend;
+       int                     pend;
 
        DNPRINTF(SR_D_INTR, "%s: sr_intr bp %x xs %x\n",
            DEVNAME(sc), bp, xs);
@@ -401,8 +402,6 @@ sr_raid0_intr(struct buf *bp)
            ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags,
            ccb->ccb_buf.b_blkno, ccb->ccb_target);
 
-       s = splbio();
-
        if (ccb->ccb_buf.b_flags & B_ERROR) {
                printf("%s: i/o error on block %lld target: %d b_error: %d\n",
                    DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target,
@@ -434,6 +433,7 @@ sr_raid0_intr(struct buf *bp)
                xs->resid = 0;
 
                pend = 0;
+               mtx_enter(&sd->sd_mtx);
                TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
                        if (wu == wup) {
                                /* wu on pendq, remove */
@@ -451,6 +451,7 @@ sr_raid0_intr(struct buf *bp)
                                break;
                        }
                }
+               mtx_leave(&sd->sd_mtx);
 
                if (!pend)
                        printf("%s: wu: %p not on pending queue\n",
@@ -464,11 +465,9 @@ sr_raid0_intr(struct buf *bp)
                        wakeup(sd);
        }
 
-       splx(s);
        return;
 bad:
-       xs->error = XS_DRIVER_STUFFUP;
        sr_wu_put(wu);
+       xs->error = XS_DRIVER_STUFFUP;
        sr_scsi_done(sd, xs);
-       splx(s);
 }
Index: softraid_raid1.c
===================================================================
RCS file: /cvs/src/sys/dev/softraid_raid1.c,v
retrieving revision 1.25
diff -u -p -r1.25 softraid_raid1.c
--- softraid_raid1.c    2 Jul 2010 09:20:26 -0000       1.25
+++ softraid_raid1.c    29 Jul 2010 21:30:07 -0000
@@ -150,14 +150,13 @@ sr_raid1_free_resources(struct sr_discip
 void
 sr_raid1_set_chunk_state(struct sr_discipline *sd, int c, int new_state)
 {
-       int                     old_state, s;
+       int                     old_state;
 
        DNPRINTF(SR_D_STATE, "%s: %s: %s: sr_raid_set_chunk_state %d -> %d\n",
            DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname,
            sd->sd_vol.sv_chunks[c]->src_meta.scmi.scm_devname, c, new_state);
 
-       /* ok to go to splbio since this only happens in error path */
-       s = splbio();
+       mtx_enter(&sd->sd_mtx);
        old_state = sd->sd_vol.sv_chunks[c]->src_meta.scm_status;
 
        /* multiple IOs to the same chunk that fail will come through here */
@@ -217,7 +216,7 @@ sr_raid1_set_chunk_state(struct sr_disci
 
        default:
 die:
-               splx(s); /* XXX */
+               mtx_leave(&sd->sd_mtx); /* XXX */
                panic("%s: %s: %s: invalid chunk state transition "
                    "%d -> %d\n", DEVNAME(sd->sd_sc),
                    sd->sd_meta->ssd_devname,
@@ -232,7 +231,7 @@ die:
        sd->sd_must_flush = 1;
        workq_add_task(NULL, 0, sr_meta_save_callback, sd, NULL);
 done:
-       splx(s);
+       mtx_leave(&sd->sd_mtx);
 }
 
 void
@@ -240,7 +239,10 @@ sr_raid1_set_vol_state(struct sr_discipl
 {
        int                     states[SR_MAX_STATES];
        int                     new_state, i, s, nd;
-       int                     old_state = sd->sd_vol_status;
+       int                     old_state;
+
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+       old_state = sd->sd_vol_status;
 
        DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state\n",
            DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname);
@@ -373,7 +375,7 @@ sr_raid1_rw(struct sr_workunit *wu)
        struct sr_ccb           *ccb;
        struct buf              *b;
        struct sr_chunk         *scp;
-       int                     ios, x, i, s, rt;
+       int                     ios, x, i, rt;
        daddr64_t               blk;
 
        /* blk and scsi error will be handled by sr_validate_io */
@@ -390,7 +392,9 @@ sr_raid1_rw(struct sr_workunit *wu)
        wu->swu_io_count = ios;
 
        for (i = 0; i < ios; i++) {
+               mtx_enter(&sd->sd_mtx);
                ccb = sr_ccb_get(sd);
+               mtx_leave(&sd->sd_mtx);
                if (!ccb) {
                        /* should never happen but handle more gracefully */
                        printf("%s: %s: too many ccbs queued\n",
@@ -443,7 +447,9 @@ ragain:
                                /* volume offline */
                                printf("%s: is offline, can't read\n",
                                    DEVNAME(sd->sd_sc));
+                               mtx_enter(&sd->sd_mtx);
                                sr_ccb_put(ccb);
+                               mtx_leave(&sd->sd_mtx);
                                goto bad;
                        }
                } else {
@@ -460,7 +466,9 @@ ragain:
                        case BIOC_SDHOTSPARE: /* should never happen */
                        case BIOC_SDOFFLINE:
                                wu->swu_io_count--;
+                               mtx_enter(&sd->sd_mtx);
                                sr_ccb_put(ccb);
+                               mtx_leave(&sd->sd_mtx);
                                continue;
 
                        default:
@@ -476,7 +484,9 @@ ragain:
 
                LIST_INIT(&b->b_dep);
 
+               mtx_enter(&sd->sd_mtx);
                TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
+               mtx_leave(&sd->sd_mtx);
 
                DNPRINTF(SR_D_DIS, "%s: %s: sr_raid1: b_bcount: %d "
                    "b_blkno: %x b_flags 0x%0x b_data %p\n",
@@ -485,7 +495,7 @@ ragain:
                    b->b_flags, b->b_data);
        }
 
-       s = splbio();
+       mtx_enter(&sd->sd_mtx);
 
        /* rebuild io, let rebuild routine deal with it */
        if (wu->swu_flags & SR_WUF_REBUILD)
@@ -505,7 +515,7 @@ ragain:
 start:
        sr_raid_startwu(wu);
 queued:
-       splx(s);
+       mtx_leave(&sd->sd_mtx);
        return (0);
 bad:
        /* wu is unwound by sr_wu_put */
@@ -559,7 +569,9 @@ sr_raid1_intr(struct buf *bp)
                        if (xs->flags & SCSI_DATA_IN) {
                                printf("%s: retrying read on block %lld\n",
                                    DEVNAME(sc), b->b_blkno);
+                               mtx_enter(&sd->sd_mtx);
                                sr_ccb_put(ccb);
+                               mtx_leave(&sd->sd_mtx);
                                TAILQ_INIT(&wu->swu_ccb);
                                wu->swu_state = SR_WU_RESTART;
                                if (sd->sd_scsi_rw(wu))
@@ -578,6 +590,7 @@ sr_raid1_intr(struct buf *bp)
                xs->resid = 0;
 
                pend = 0;
+               mtx_enter(&sd->sd_mtx);
                TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
                        if (wu == wup) {
                                /* wu on pendq, remove */
@@ -585,9 +598,11 @@ sr_raid1_intr(struct buf *bp)
                                pend = 1;
 
                                if (wu->swu_collider) {
-                                       if (wu->swu_ios_failed)
+                                       if (wu->swu_ios_failed) {
                                                /* toss all ccbs and recreate */
                                                
sr_raid1_recreate_wu(wu->swu_collider);
+                                               
MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+                                       }
 
                                        /* restart deferred wu */
                                        wu->swu_collider->swu_state =
@@ -599,6 +614,7 @@ sr_raid1_intr(struct buf *bp)
                                break;
                        }
                }
+               mtx_leave(&sd->sd_mtx);
 
                if (!pend)
                        printf("%s: wu: %p not on pending queue\n",
@@ -612,7 +628,7 @@ sr_raid1_intr(struct buf *bp)
                } else {
                        /* do not change the order of these 2 functions */
                        sr_wu_put(wu);
-                       scsi_done(xs);
+                       sr_scsi_done(sd, xs);
                }
 
                if (sd->sd_sync && sd->sd_wu_pending == 0)
@@ -630,7 +646,7 @@ bad:
        } else {
                /* do not change the order of these 2 functions */
                sr_wu_put(wu);
-               scsi_done(xs);
+               sr_scsi_done(sd, xs);
        }
 
        splx(s);
@@ -643,6 +659,12 @@ sr_raid1_recreate_wu(struct sr_workunit 
        struct sr_workunit      *wup = wu;
        struct sr_ccb           *ccb;
 
+       /*
+        * watch out!
+        * must have mutex on way in and out but can't call rw with it
+        */
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+
        do {
                DNPRINTF(SR_D_INTR, "%s: sr_raid1_recreate_wu: %p\n", wup);
 
@@ -655,8 +677,10 @@ sr_raid1_recreate_wu(struct sr_workunit 
 
                /* recreate ccbs */
                wup->swu_state = SR_WU_REQUEUE;
+               mtx_leave(&sd->sd_mtx);
                if (sd->sd_scsi_rw(wup))
                        panic("could not requeue io");
+               mtx_enter(&sd->sd_mtx);
 
                wup = wup->swu_collider;
        } while (wup);
Index: softraid_raid6.c
===================================================================
RCS file: /cvs/src/sys/dev/softraid_raid6.c,v
retrieving revision 1.18
diff -u -p -r1.18 softraid_raid6.c
--- softraid_raid6.c    2 Jul 2010 09:20:26 -0000       1.18
+++ softraid_raid6.c    29 Jul 2010 21:35:37 -0000
@@ -246,15 +246,14 @@ sr_raid6_free_resources(struct sr_discip
 void
 sr_raid6_set_chunk_state(struct sr_discipline *sd, int c, int new_state)
 {
-       int                     old_state, s;
+       int                     old_state;
 
        /* XXX this is for RAID 0 */
        DNPRINTF(SR_D_STATE, "%s: %s: %s: sr_raid_set_chunk_state %d -> %d\n",
            DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname,
            sd->sd_vol.sv_chunks[c]->src_meta.scmi.scm_devname, c, new_state);
 
-       /* ok to go to splbio since this only happens in error path */
-       s = splbio();
+       mtx_enter(&sd->sd_mtx);
        old_state = sd->sd_vol.sv_chunks[c]->src_meta.scm_status;
 
        /* multiple IOs to the same chunk that fail will come through here */
@@ -301,7 +300,7 @@ sr_raid6_set_chunk_state(struct sr_disci
 
        default:
 die:
-               splx(s); /* XXX */
+               mtx_leave(&sd->sd_mtx);
                panic("%s: %s: %s: invalid chunk state transition "
                    "%d -> %d\n", DEVNAME(sd->sd_sc),
                    sd->sd_meta->ssd_devname,
@@ -316,18 +315,21 @@ die:
        sd->sd_must_flush = 1;
        workq_add_task(NULL, 0, sr_meta_save_callback, sd, NULL);
 done:
-       splx(s);
+       mtx_leave(&sd->sd_mtx);
 }
 
 void
 sr_raid6_set_vol_state(struct sr_discipline *sd)
 {
        int                     states[SR_MAX_STATES];
-       int                     new_state, i, s, nd;
-       int                     old_state = sd->sd_vol_status;
+       int                     new_state, i, st, nd;
+       int                     old_state;
 
        /* XXX this is for RAID 0 */
 
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+       old_state = sd->sd_vol_status;
+
        DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state\n",
            DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname);
 
@@ -337,13 +339,13 @@ sr_raid6_set_vol_state(struct sr_discipl
                states[i] = 0;
 
        for (i = 0; i < nd; i++) {
-               s = sd->sd_vol.sv_chunks[i]->src_meta.scm_status;
-               if (s >= SR_MAX_STATES)
+               st = sd->sd_vol.sv_chunks[i]->src_meta.scm_status;
+               if (st >= SR_MAX_STATES)
                        panic("%s: %s: %s: invalid chunk state",
                            DEVNAME(sd->sd_sc),
                            sd->sd_meta->ssd_devname,
                            sd->sd_vol.sv_chunks[i]->src_meta.scmi.scm_devname);
-               states[s]++;
+               states[st]++;
        }
 
        if (states[BIOC_SDONLINE] == nd)
@@ -458,7 +460,7 @@ sr_raid6_rw(struct sr_workunit *wu)
        struct sr_discipline    *sd = wu->swu_dis;
        struct scsi_xfer        *xs = wu->swu_xs;
        struct sr_chunk         *scp;
-       int                     s, fail, i, rwmode, gxinv, pxinv;
+       int                     fail, i, rwmode, gxinv, pxinv;
        daddr64_t               blk, lbaoffs, strip_no, chunk, qchunk, pchunk, 
fchunk;
        daddr64_t               strip_size, no_chunk, lba, chunk_offs, 
phys_offs;
        daddr64_t               strip_bits, length, strip_offs, datalen, 
row_size;
@@ -703,7 +705,7 @@ sr_raid6_rw(struct sr_workunit *wu)
                data += length;
        }
 
-       s = splbio();
+       mtx_enter(&sd->sd_mtx);
        if (wu_w) {
                /* collide write request with reads */
                wu_w->swu_blk_start = wu->swu_blk_start;
@@ -739,7 +741,7 @@ sr_raid6_rw(struct sr_workunit *wu)
 start:
        sr_raid_startwu(wu);
 queued:
-       splx(s);
+       mtx_leave(&sd->sd_mtx);
        return (0);
 bad:
        /* wu is unwound by sr_wu_put */
@@ -755,6 +757,8 @@ sr_failio(struct sr_workunit *wu)
        struct sr_discipline    *sd = wu->swu_dis;
        struct sr_ccb           *ccb;
 
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+
        if (!(wu->swu_flags & SR_WUF_FAIL))
                return (0);
 
@@ -774,7 +778,7 @@ sr_raid6_intr(struct buf *bp)
        struct scsi_xfer        *xs = wu->swu_xs;
        struct sr_softc         *sc = sd->sd_sc;
        struct sr_raid6_opaque  *pq = ccb->ccb_opaque;
-       int                     s, pend;
+       int                     pend;
 
        DNPRINTF(SR_D_INTR, "%s: sr_intr bp %p xs %p\n",
            DEVNAME(sc), bp, xs);
@@ -784,8 +788,6 @@ sr_raid6_intr(struct buf *bp)
            ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags,
            ccb->ccb_buf.b_blkno, ccb->ccb_target);
 
-       s = splbio();
-
        if (ccb->ccb_buf.b_flags & B_ERROR) {
                DNPRINTF(SR_D_INTR, "%s: i/o error on block %lld target: %d\n",
                    DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target);
@@ -834,8 +836,10 @@ sr_raid6_intr(struct buf *bp)
                        if (xs->flags & SCSI_DATA_IN) {
                                printf("%s: retrying read on block %lld\n",
                                    DEVNAME(sc), ccb->ccb_buf.b_blkno);
+                               mtx_enter(&sd->sd_mtx);
                                sr_ccb_put(ccb);
                                TAILQ_INIT(&wu->swu_ccb);
+                               mtx_leave(&sd->sd_mtx);
                                wu->swu_state = SR_WU_RESTART;
                                if (sd->sd_scsi_rw(wu))
                                        goto bad;
@@ -856,6 +860,7 @@ sr_raid6_intr(struct buf *bp)
                }
 
                pend = 0;
+               mtx_enter(&sd->sd_mtx);
                TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
                        if (wu == wup) {
                                /* wu on pendq, remove */
@@ -863,9 +868,11 @@ sr_raid6_intr(struct buf *bp)
                                pend = 1;
 
                                if (wu->swu_collider) {
-                                       if (wu->swu_ios_failed)
+                                       if (wu->swu_ios_failed) {
                                                /* toss all ccbs and recreate */
                                                
sr_raid6_recreate_wu(wu->swu_collider);
+                                               
MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+                                       }
 
                                        /* restart deferred wu */
                                        wu->swu_collider->swu_state =
@@ -878,6 +885,7 @@ sr_raid6_intr(struct buf *bp)
                                break;
                        }
                }
+               mtx_leave(&sd->sd_mtx);
 
                if (!pend)
                        printf("%s: wu: %p not on pending queue\n",
@@ -892,7 +900,7 @@ sr_raid6_intr(struct buf *bp)
                        /* do not change the order of these 2 functions */
                        sr_wu_put(wu);
                        if (xs != NULL)
-                               scsi_done(xs);
+                               sr_scsi_done(sd, xs);
                }
 
                if (sd->sd_sync && sd->sd_wu_pending == 0)
@@ -900,7 +908,6 @@ sr_raid6_intr(struct buf *bp)
        }
 
 retry:
-       splx(s);
        return;
 bad:
        xs->error = XS_DRIVER_STUFFUP;
@@ -910,10 +917,8 @@ bad:
        } else {
                /* do not change the order of these 2 functions */
                sr_wu_put(wu);
-               scsi_done(xs);
+               sr_scsi_done(sd, xs);
        }
-
-       splx(s);
 }
 
 void
@@ -923,6 +928,12 @@ sr_raid6_recreate_wu(struct sr_workunit 
        struct sr_workunit      *wup = wu;
        struct sr_ccb           *ccb;
 
+       /*
+        * watch out!
+        * must have mutex on way in and out but can't call rw with it
+        */
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+
        do {
                DNPRINTF(SR_D_INTR, "%s: sr_raid6_recreate_wu: %p\n", wup);
 
@@ -935,8 +946,10 @@ sr_raid6_recreate_wu(struct sr_workunit 
 
                /* recreate ccbs */
                wup->swu_state = SR_WU_REQUEUE;
+               mtx_leave(&sd->sd_mtx);
                if (sd->sd_scsi_rw(wup))
                        panic("could not requeue io");
+               mtx_enter(&sd->sd_mtx);
 
                wup = wup->swu_collider;
        } while (wup);
@@ -950,7 +963,9 @@ sr_raid6_addio(struct sr_workunit *wu, i
        struct sr_ccb           *ccb;
        struct sr_raid6_opaque  *pqbuf;
 
+       mtx_enter(&sd->sd_mtx);
        ccb = sr_ccb_get(sd);
+       mtx_leave(&sd->sd_mtx);
        if (!ccb)
                return (-1);
 
@@ -1001,7 +1016,9 @@ sr_raid6_addio(struct sr_workunit *wu, i
 
                pqbuf = malloc(sizeof(struct sr_raid6_opaque), M_DEVBUF, 
M_CANFAIL);
                if (pqbuf == NULL) {
+                       mtx_enter(&sd->sd_mtx);
                        sr_ccb_put(ccb);
+                       mtx_leave(&sd->sd_mtx);
                        return (-1);
                }
                pqbuf->pbuf = pbuf;
@@ -1011,7 +1028,9 @@ sr_raid6_addio(struct sr_workunit *wu, i
        }
 
        LIST_INIT(&ccb->ccb_buf.b_dep);
+       mtx_enter(&sd->sd_mtx);
        TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
+       mtx_leave(&sd->sd_mtx);
 
        DNPRINTF(SR_D_DIS, "%s: %s: sr_raid6: b_bcount: %d "
            "b_blkno: %x b_flags 0x%0x b_data %p\n",
Index: softraid_raidp.c
===================================================================
RCS file: /cvs/src/sys/dev/softraid_raidp.c,v
retrieving revision 1.18
diff -u -p -r1.18 softraid_raidp.c
--- softraid_raidp.c    2 Jul 2010 09:20:26 -0000       1.18
+++ softraid_raidp.c    29 Jul 2010 21:44:26 -0000
@@ -183,14 +183,13 @@ sr_raidp_free_resources(struct sr_discip
 void
 sr_raidp_set_chunk_state(struct sr_discipline *sd, int c, int new_state)
 {
-       int                     old_state, s;
+       int                     old_state;
 
        DNPRINTF(SR_D_STATE, "%s: %s: %s: sr_raid_set_chunk_state %d -> %d\n",
            DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname,
            sd->sd_vol.sv_chunks[c]->src_meta.scmi.scm_devname, c, new_state);
 
-       /* ok to go to splbio since this only happens in error path */
-       s = splbio();
+       mtx_enter(&sd->sd_mtx);
        old_state = sd->sd_vol.sv_chunks[c]->src_meta.scm_status;
 
        /* multiple IOs to the same chunk that fail will come through here */
@@ -237,7 +236,7 @@ sr_raidp_set_chunk_state(struct sr_disci
 
        default:
 die:
-               splx(s); /* XXX */
+               mtx_leave(&sd->sd_mtx);
                panic("%s: %s: %s: invalid chunk state transition "
                    "%d -> %d\n", DEVNAME(sd->sd_sc),
                    sd->sd_meta->ssd_devname,
@@ -252,15 +251,18 @@ die:
        sd->sd_must_flush = 1;
        workq_add_task(NULL, 0, sr_meta_save_callback, sd, NULL);
 done:
-       splx(s);
+       mtx_leave(&sd->sd_mtx);
 }
 
 void
 sr_raidp_set_vol_state(struct sr_discipline *sd)
 {
        int                     states[SR_MAX_STATES];
-       int                     new_state, i, s, nd;
-       int                     old_state = sd->sd_vol_status;
+       int                     new_state, i, st, nd;
+       int                     old_state;
+
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+       old_state = sd->sd_vol_status;
 
        DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state\n",
            DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname);
@@ -271,13 +273,13 @@ sr_raidp_set_vol_state(struct sr_discipl
                states[i] = 0;
 
        for (i = 0; i < nd; i++) {
-               s = sd->sd_vol.sv_chunks[i]->src_meta.scm_status;
-               if (s >= SR_MAX_STATES)
+               st = sd->sd_vol.sv_chunks[i]->src_meta.scm_status;
+               if (st >= SR_MAX_STATES)
                        panic("%s: %s: %s: invalid chunk state",
                            DEVNAME(sd->sd_sc),
                            sd->sd_meta->ssd_devname,
                            sd->sd_vol.sv_chunks[i]->src_meta.scmi.scm_devname);
-               states[s]++;
+               states[st]++;
        }
 
        if (states[BIOC_SDONLINE] == nd)
@@ -375,7 +377,7 @@ sr_raidp_rw(struct sr_workunit *wu)
        struct sr_discipline    *sd = wu->swu_dis;
        struct scsi_xfer        *xs = wu->swu_xs;
        struct sr_chunk         *scp;
-       int                     s, i;
+       int                     i;
        daddr64_t               blk, lbaoffs, strip_no, chunk, row_size;
        daddr64_t               strip_size, no_chunk, lba, chunk_offs, 
phys_offs;
        daddr64_t               strip_bits, length, parity, strip_offs, datalen;
@@ -512,7 +514,7 @@ sr_raidp_rw(struct sr_workunit *wu)
                data += length;
        }
 
-       s = splbio();
+       mtx_enter(&sd->sd_mtx);
        if (wu_w) {
                /* collide write request with reads */
                wu_w->swu_blk_start = wu->swu_blk_start;
@@ -548,7 +550,7 @@ sr_raidp_rw(struct sr_workunit *wu)
 start:
        sr_raid_startwu(wu);
 queued:
-       splx(s);
+       mtx_leave(&sd->sd_mtx);
        return (0);
 bad:
        /* wu is unwound by sr_wu_put */
@@ -565,7 +567,7 @@ sr_raidp_intr(struct buf *bp)
        struct sr_discipline    *sd = wu->swu_dis;
        struct scsi_xfer        *xs = wu->swu_xs;
        struct sr_softc         *sc = sd->sd_sc;
-       int                     s, pend;
+       int                     pend;
 
        DNPRINTF(SR_D_INTR, "%s: sr_intr bp %p xs %p\n",
            DEVNAME(sc), bp, xs);
@@ -575,8 +577,6 @@ sr_raidp_intr(struct buf *bp)
            ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags,
            ccb->ccb_buf.b_blkno, ccb->ccb_target);
 
-       s = splbio();
-
        if (ccb->ccb_buf.b_flags & B_ERROR) {
                DNPRINTF(SR_D_INTR, "%s: i/o error on block %lld target: %d\n",
                    DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target);
@@ -615,8 +615,10 @@ sr_raidp_intr(struct buf *bp)
                        if (xs->flags & SCSI_DATA_IN) {
                                printf("%s: retrying read on block %lld\n",
                                    DEVNAME(sc), ccb->ccb_buf.b_blkno);
+                               mtx_enter(&sd->sd_mtx);
                                sr_ccb_put(ccb);
                                TAILQ_INIT(&wu->swu_ccb);
+                               mtx_leave(&sd->sd_mtx);
                                wu->swu_state = SR_WU_RESTART;
                                if (sd->sd_scsi_rw(wu))
                                        goto bad;
@@ -637,6 +639,7 @@ sr_raidp_intr(struct buf *bp)
                }
 
                pend = 0;
+               mtx_enter(&sd->sd_mtx);
                TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
                        if (wu == wup) {
                                /* wu on pendq, remove */
@@ -644,9 +647,11 @@ sr_raidp_intr(struct buf *bp)
                                pend = 1;
 
                                if (wu->swu_collider) {
-                                       if (wu->swu_ios_failed)
+                                       if (wu->swu_ios_failed) {
                                                /* toss all ccbs and recreate */
                                                
sr_raidp_recreate_wu(wu->swu_collider);
+                                               
MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+                                       }
 
                                        /* restart deferred wu */
                                        wu->swu_collider->swu_state =
@@ -658,6 +663,7 @@ sr_raidp_intr(struct buf *bp)
                                break;
                        }
                }
+               mtx_leave(&sd->sd_mtx);
 
                if (!pend)
                        printf("%s: wu: %p not on pending queue\n",
@@ -672,7 +678,7 @@ sr_raidp_intr(struct buf *bp)
                        /* do not change the order of these 2 functions */
                        sr_wu_put(wu);
                        if (xs != NULL)
-                               scsi_done(xs);
+                               sr_scsi_done(sd, xs);
                }
 
                if (sd->sd_sync && sd->sd_wu_pending == 0)
@@ -680,7 +686,6 @@ sr_raidp_intr(struct buf *bp)
        }
 
 retry:
-       splx(s);
        return;
 bad:
        xs->error = XS_DRIVER_STUFFUP;
@@ -690,10 +695,8 @@ bad:
        } else {
                /* do not change the order of these 2 functions */
                sr_wu_put(wu);
-               scsi_done(xs);
+               sr_scsi_done(sd, xs);
        }
-
-       splx(s);
 }
 
 void
@@ -703,6 +706,12 @@ sr_raidp_recreate_wu(struct sr_workunit 
        struct sr_workunit      *wup = wu;
        struct sr_ccb           *ccb;
 
+       /*
+        * watch out!
+        * must have mutex on way in and out but can't call rw with it
+        */
+       MUTEX_ASSERT_LOCKED(&sd->sd_mtx);
+
        do {
                DNPRINTF(SR_D_INTR, "%s: sr_raidp_recreate_wu: %p\n", wup);
 
@@ -715,8 +724,10 @@ sr_raidp_recreate_wu(struct sr_workunit 
 
                /* recreate ccbs */
                wup->swu_state = SR_WU_REQUEUE;
+               mtx_leave(&sd->sd_mtx);
                if (sd->sd_scsi_rw(wup))
                        panic("could not requeue io");
+               mtx_enter(&sd->sd_mtx);
 
                wup = wup->swu_collider;
        } while (wup);
@@ -729,7 +740,9 @@ sr_raidp_addio(struct sr_workunit *wu, i
        struct sr_discipline    *sd = wu->swu_dis;
        struct sr_ccb           *ccb;
 
+       mtx_enter(&sd->sd_mtx);
        ccb = sr_ccb_get(sd);
+       mtx_leave(&sd->sd_mtx);
        if (!ccb)
                return (-1);
 
@@ -778,7 +791,9 @@ sr_raidp_addio(struct sr_workunit *wu, i
        ccb->ccb_opaque = xorbuf;
 
        LIST_INIT(&ccb->ccb_buf.b_dep);
+       mtx_enter(&sd->sd_mtx);
        TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
+       mtx_leave(&sd->sd_mtx);
 
        DNPRINTF(SR_D_DIS, "%s: %s: sr_raidp: b_bcount: %d "
            "b_blkno: %x b_flags 0x%0x b_data %p\n",
@@ -828,7 +843,7 @@ sr_raidp_scrub(struct sr_discipline *sd)
        daddr64_t strip_no, strip_size, no_chunk, parity, max_strip, strip_bits;
        daddr64_t i;
        struct sr_workunit *wu_r, *wu_w;
-       int s, slept;
+       int slept;
        void *xorbuf;
 
        if ((wu_r = sr_wu_get(sd, 1)) == NULL)
@@ -864,14 +879,12 @@ sr_raidp_scrub(struct sr_discipline *sd)
                wu_w->swu_state = SR_WU_DEFERRED;
                wu_r->swu_collider = wu_w;
 
-               s = splbio();
+               mtx_enter(&sd->sd_mtx);
                TAILQ_INSERT_TAIL(&sd->sd_wu_defq, wu_w, swu_link);
 
-               if (sr_check_io_collision(wu_r))
-                       goto queued;
-               sr_raid_startwu(wu_r);
-       queued:
-               splx(s);
+               if (sr_check_io_collision(wu_r) == 0)
+                       sr_raid_startwu(wu_r);
+               mtx_leave(&sd->sd_mtx);
 
                slept = 0;
                while ((wu_w->swu_flags & SR_WUF_REBUILDIOCOMP) == 0) {
Index: softraidvar.h
===================================================================
RCS file: /cvs/src/sys/dev/softraidvar.h,v
retrieving revision 1.94
diff -u -p -r1.94 softraidvar.h
--- softraidvar.h       2 Jul 2010 09:26:05 -0000       1.94
+++ softraidvar.h       29 Jul 2010 18:49:48 -0000
@@ -21,6 +21,7 @@
 
 #include <crypto/md5.h>
 #include <sys/vnode.h>
+#include <sys/mutex.h>
 
 #define SR_META_VERSION                4       /* bump when sr_metadata 
changes */
 #define SR_META_SIZE           64      /* save space at chunk beginning */
@@ -479,6 +480,8 @@ struct sr_discipline {
        }                       sd_dis_specific;/* dis specific members */
 #define mds                    sd_dis_specific
 
+       struct workq            *sd_workq;
+
        /* discipline metadata */
        struct sr_metadata      *sd_meta;       /* in memory copy of metadata */
        void                    *sd_meta_foreign; /* non native metadata */
@@ -511,6 +514,7 @@ struct sr_discipline {
        struct sr_wu_list       sd_wu_freeq;    /* free wu queue */
        struct sr_wu_list       sd_wu_pendq;    /* pending wu queue */
        struct sr_wu_list       sd_wu_defq;     /* deferred wu queue */
+       struct mutex            sd_mtx;         /* mutex for all wu/ccb ops */
        int                     sd_wu_sleep;    /* wu sleepers counter */
 
        /* discipline stats */

Reply via email to