--- a/sys/dev/disk/trm/trm.c +++ b/sys/dev/disk/trm/trm.c @@ -1336,8 +1336,16 @@ if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) { pDCB = pACB->pActiveDCB; - KASSERT(pDCB != NULL, ("no active DCB")); - pSRB = pDCB->pActiveSRB; + /* + * DF-3833: a stale completion can arrive after a bus + * reset / disconnect cleared pActiveDCB (or pActiveSRB). + * Drop it instead of dereferencing NULL. + */ + if (pDCB == NULL || (pSRB = pDCB->pActiveSRB) == NULL) { + trm_reg_write16(DO_CLRFIFO | DO_HWRESELECT, + TRMREG_SCSI_CONTROL); + return; + } if (pDCB->DCBFlag & ABORT_DEV_) trm_EnableMsgOutAbort1(pACB, pSRB); phase = (u_int16_t) pSRB->ScsiPhase; /* phase: */ @@ -2719,17 +2727,21 @@ pDCB->pGoingSRB = pSRB->pNextSRB; else { psrb = pDCB->pGoingSRB; - while (psrb->pNextSRB != pSRB) { + while (psrb != NULL && psrb->pNextSRB != pSRB) { psrb = psrb->pNextSRB; } + if (psrb == NULL) /* DF-3833: not on the going list */ + goto skip_unlink; psrb->pNextSRB = pSRB->pNextSRB; if (pSRB == pDCB->pGoingLastSRB) { pDCB->pGoingLastSRB = psrb; } } +skip_unlink: pSRB->pNextSRB = pACB->pFreeSRB; pACB->pFreeSRB = pSRB; - pDCB->GoingSRBCnt--; + if (pDCB->GoingSRBCnt) + pDCB->GoingSRBCnt--; trm_DoWaitingSRB(pACB); crit_exit();