--- a/sys/bus/cam/scsi/scsi_targ_bh.c +++ b/sys/bus/cam/scsi/scsi_targ_bh.c @@ -89,6 +89,7 @@ targbh_state state; targbh_flags flags; u_int init_level; + u_int active_ctios; /* dispatched CTIOs not yet completed */ u_int inq_data_len; struct ccb_accept_tio *accept_tio_list; struct ccb_hdr_slist immed_notify_slist; @@ -416,6 +417,16 @@ case 1: /* FALLTHROUGH */ default: + /* + * Drain in-flight CTIOs before freeing the softc. A + * fixed hz/2 sleep is not a wakeup protocol: CTIOs + * dispatched by targbhstart() are owned by the SIM and + * are neither tracked nor aborted by targbhdislun() + * (which only aborts idle ATIOs / immediate notifies). + */ + while (softc->active_ctios > 0) + sim_lock_sleep(&softc->active_ctios, 0, "targbhctio", + 0, periph->sim->lock); /* XXX Wait for callback of targbhdislun() */ sim_lock_sleep(softc, 0, "targbh", hz/2, periph->sim->lock); kfree(softc, M_SCSIBH); @@ -492,6 +503,12 @@ start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ; start_ccb->ccb_h.ccb_atio = atio; + + /* + * Account the CTIO before handing it to the SIM: the SIM + * may complete it synchronously from inside xpt_action(). + */ + softc->active_ctios++; CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("Sending a CTIO\n")); xpt_action(start_ccb); @@ -648,6 +665,11 @@ TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h, periph_links.tqe); + /* The CTIO is back from the SIM; release the dtor drain. */ + KKASSERT(softc->active_ctios > 0); + softc->active_ctios--; + wakeup(&softc->active_ctios); + /* * We could check for CAM_SENT_SENSE bein set here, * but since we're not maintaining any CA/UA state,