--- a/sys/dev/disk/sbp/sbp.c +++ b/sys/dev/disk/sbp/sbp.c @@ -1597,7 +1597,11 @@ ocb = target->mgm_ocb_cur; if (ocb != NULL) { if (OCB_MATCH(ocb, sbp_status)) { - callout_stop(&target->mgm_ocb_timeout); + /* DF-3982: recv1 runs in the fwohci hard + * interrupt path under crit; the modern + * callout_stop() would sleep in 'costp' + * while the callback is INPROG. */ + callout_stop_async(&target->mgm_ocb_timeout); target->mgm_ocb_cur = NULL; break; } @@ -2129,6 +2133,15 @@ struct sbp_dev *sdev = ocb->sdev; struct sbp_target *target = sdev->target; + crit_enter(); + if (target->mgm_ocb_cur != ocb) { + /* DF-3982: completion raced us (recv1 uses the async stop); + * the ocb has already been completed and freed. */ + crit_exit(); + return; + } + crit_exit(); + sbp_show_sdev_info(sdev, 2); kprintf("request timeout(mgm orb:0x%08x) ... ", (u_int32_t)ocb->bus_addr); @@ -2587,7 +2600,8 @@ /* found */ STAILQ_REMOVE(&sdev->ocbs, ocb, sbp_ocb, ocb); if (ocb->ccb != NULL) - callout_stop(ocb->ccb->ccb_h.timeout_ch); + callout_stop_async( + ocb->ccb->ccb_h.timeout_ch); if (ntohl(ocb->orb[4]) & 0xffff) { bus_dmamap_sync(sdev->target->sbp->dmat, ocb->dmamap, @@ -2702,7 +2716,7 @@ bus_dmamap_unload(sdev->target->sbp->dmat, ocb->dmamap); } if (ocb->ccb != NULL) { - callout_stop(ocb->ccb->ccb_h.timeout_ch); + callout_stop_async(ocb->ccb->ccb_h.timeout_ch); ocb->ccb->ccb_h.status = status; xpt_done(ocb->ccb); }