# DF-3657 VERDICT — XPT_ABORT wrong CCB

## Status: not_reproduced (guest has no QLogic HBA; source-level certain)

## The bug

`sys/dev/disk/isp/isp_freebsd.c:4531-4557`, case `XPT_ABORT`:

```c
union ccb *accb = ccb->cab.abort_ccb;
switch (accb->ccb_h.func_code) {
...
case XPT_SCSI_IO:
        error = isp_control(isp, ISPCTL_ABORT_CMD, ccb);   /* BUG: ccb, not accb */
```

Upstream FreeBSD (`sys/dev/isp/isp_freebsd.c`, case XPT_ABORT) passes
`accb` — verified against current FreeBSD HEAD:

```c
case XPT_SCSI_IO:
        error = isp_control(isp, ISPCTL_ABORT_CMD, accb);
```

## Why the abort always fails — full trace

1. `isp_control(ISPCTL_ABORT_CMD, xs)` at `isp.c:4603` takes `xs` and calls
   `handle = isp_find_handle(isp, xs)` (`isp.c:4611`).
2. `isp_find_handle()` (`isp_library.c:260-274`) matches by **pointer
   equality** against `isp->isp_xflist[i].cmd` — the table filled only by
   `isp_start()` for commands actually queued to the firmware.
3. The XPT_ABORT CCB is a *synchronous control* CCB; it was never passed to
   `isp_start()`, so it is in no `isp_xflist[]` slot → `ISP_HANDLE_FREE` (0).
4. `isp.c:4612-4616`: `handle == 0` → warning "cannot find handle for command
   to abort" → `break` → `isp_control` returns `-1` (`isp.c:4845`).
5. `isp_freebsd.c:4542-4546`: error ⇒ `ccb->ccb_h.status = CAM_UA_ABORT`.

Net effect: **every XPT_ABORT of an XPT_SCSI_IO on isp(4) fails**, on all
chip generations (the IS_24XX / IS_FC / SCSI branches are all behind the
failed handle lookup). The command that should have been aborted keeps
running; callers must escalate to XPT_RESET_DEV / XPT_RESET_BUS.

## Impact

- CAM periph error recovery (`cam_periph_timeout` → abort → BDR ladder) degrades:
  the abort rung always fails, so any timed-out command forces device reset /
  bus reset escalation. More resets = more I/O disruption on a live bus
  (all LUNs/targets on the channel see the reset).
- No memory corruption: the wrongly-passed CCB is only used for the (failing)
  pointer lookup; `tgt`/`chan` derived from it stay in range because they come
  from the (valid) abort path.
- Callers are in-kernel CAM periphs (da/cd/...), or `camcontrol abort` style
  tools on hosts with the HBA. DragonFly userland `/dev/xpt0` cannot issue
  XPT_ABORT at all (xptioctl whitelist, `sys/bus/cam/cam_xpt.c:1028+`) —
  demonstrated live in `run.log` (errno 45, CCB never reaches a SIM).

## Why not reproduced on the guest

- `pciconf -l`: zero devices with vendor 0x1077 → isp(4) never attaches,
  no `/dev/isp*`, no isp CAM bus (bus0 is ATAPI). The cited path
  (`isp_action` XPT_ABORT) cannot execute at runtime on this guest.
- Verification is therefore the source-level trace above plus the upstream
  FreeBSD diff — both conclusive.

## Fix validation

`fix.diff` (ccb → accb) is the minimal, upstream-equivalent fix. Fix build/boot
validation on the guest is `not_testable`: with no HBA the fixed kernel
cannot execute the abort path (nothing to observe); a compile check alone
would prove nothing beyond syntax. The one-word change is byte-identical in
effect to upstream FreeBSD's code, which has shipped for a decade.

## Kernel references

- sys/dev/disk/isp/isp_freebsd.c:4531-4557 (XPT_ABORT case; wrong arg at 4541)
- sys/dev/disk/isp/isp.c:4603-4616 (ISPCTL_ABORT_CMD; handle lookup)
- sys/dev/disk/isp/isp.c:4845 (isp_control fallthrough return -1)
- sys/dev/disk/isp/isp_library.c:260-274 (isp_find_handle pointer match)
- sys/bus/cam/cam_xpt.c:1028+ (userland CAMIOCOMMAND whitelist — no XPT_ABORT)

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
