DF-4027 / run.log
BUILD_OK
sili_ata_cmd(POLL) -> sili_poll():
probed ccb state: ONCHIP
poll timeout -> sili_ata_cmd_timeout -> sili_core_timeout:
DEFERRED (returned 1; state stays ONCHIP)
sili_poll returns xa->state == ONCHIP to the caller
sili_cam.c:315 'if (sili_ata_cmd(xa) != ATA_S_COMPLETE)'
-> sili_ata_put_xfer(xa): sili_put_ccb() puts the ccb
on ap_ccb_free and bumps serial (sili.c:2020-2030)
PORT STILL OWNS IT: ap_active bit set, ap_expired bit set
next command reuses the freed ccb:
sili_get_ccb -> state==PUT check passes (sili.c:2010)
sili_ata_cmd -> sili_load_prb loads a NEW dmamap
sili_issue_pending_commands: ap_active |= 1<<slot AGAIN
-> ap_active_cnt inflated; two logical commands on one slot
device finally completes / port drains:
sili_port_reinit expired loop (sili.c:403-413):
ccb->ccb_xa.state = ATA_S_TIMEOUT;
ccb->ccb_done(ccb); <- sili_ata_cmd_done:
sili_unload_prb() <- unloads the NEW command's
ACTIVE dmamap (DMA-writeback
onto reused memory)
ccb->ccb_xa.complete(...) <- for a CAM command this is
sili_ata_complete_disk_rw on the REISSUED ccb: xpt_done
on a CAM ccb that is already owned by the new request
-> double CAM completion / UAF in the CAM layer
KKASSERT(ap->ap_active_cnt == 0) in sili_port_hardstop can
also fire (underflow) on INVARIANTS kernels.