# DF-4558 — atapi-cam MOD_UNLOAD kfrees the softc while the cam_sim can still be registered

## File
`sys/dev/disk/nata/atapi-cam.c` — `atapi_cam_event_handler()` MOD_UNLOAD case
(:910-936), interacting with `free_softc()` (:878-908).

## Root cause (traced, not executed — see VERDICT.md)
`atapi_cam_event_handler` MOD_UNLOAD does:

    device_t child = devlist[--devcount];
    struct atapi_xpt_softc *scp = device_get_softc(child);
    device_delete_child(device_get_parent(child), child);   /* return value ignored */
    if (scp != NULL)
        kfree(scp, M_ATACAM);                               /* unconditional */

`device_delete_child()` → `atapi_cam_detach()` → `free_softc(scp)`. Inside
`free_softc()`, when the CAM bus is still busy (a `cd0`/`pass0` peripheral still
holds a path on the bus — normal with the medium open/probed),
`xpt_bus_deregister()` returns non-zero (:895-896), `BUS_REGISTERED` is
**kept**, and the SIM is deliberately NOT freed (:898-903, "Can't free %s SIM").
The softc, however, is `lockuninit`ed (:906) and then unconditionally
`kfree`d by the event handler (:927) — the still-registered `cam_sim` keeps
`sim->softc` pointing at freed memory. The next CCB routed to that bus
(`atapi_action`) does `lockmgr(&softc->state_lock, LK_EXCLUSIVE)` (:482) on the
freed, uninitialized lock → use-after-free write; every field access in
`atapi_action` is on freed memory.

Additionally, `device_delete_child()`'s own failure (detach refused / device
busy paths in newbus) is also ignored before the same unconditional kfree.

The softc is an `DF_EXTERNALSOFTC` (allocated in `atapi_cam_identify()`,
`device_set_softc()` at :169, sys/kern/subr_bus.c:1788-1797), so newbus never
frees it — this kfree is the only free, but it happens while the SIM is live.

## Trigger
`kldunload atapicam` (module variant of the driver) while any CAM peripheral on
the atapicam bus is still alive — e.g. `cd0` probed/open — then issue any I/O /
rescan on that bus.

## Guest status
The audit guest (X86_64_GENERIC) compiles `natapicam` **into** the kernel
(sys/config/X86_64_GENERIC:82) — no loadable atapicam.ko exists there, so
`kldunload` cannot execute this path on that guest. Logic verified by trace;
not executed. Severity Low: trigger is privileged (kldunload = root).

## Recommended fix
Only kfree the softc when the SIM was actually freed (registration dropped),
and honor `device_delete_child()` failure.
