DF-3831 / fix.diff
--- a/sys/dev/disk/trm/trm.c +++ b/sys/dev/disk/trm/trm.c @@ -163,6 +163,7 @@ static void trm_EnableMsgOutAbort2(PACB pACB, PSRB pSRB); static void trm_EnableMsgOutAbort1(PACB pACB, PSRB pSRB); static void trm_SendSRB(PACB pACB, PSRB pSRB); +static void trm_timeout(void *arg); static int trm_probe(device_t tag); static int trm_attach(device_t tag); static void trm_reset(PACB pACB); @@ -423,6 +424,19 @@ ccb = pSRB->pccb; pACB = (PACB)ccb->ccb_h.ccb_trmacb_ptr; TRM_DPRINTF("trm_ExecuteSRB..........\n"); + if (error != 0) { + /* + * DF-3831: the dmamap load failed (e.g. EFBIG). Fail the + * CCB instead of orphaning it -- there is no timeout + * handler to recover it later. + */ + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; + ccb->ccb_h.status = CAM_DEV_QFRZN | CAM_REQ_INVALID; + xpt_done(ccb); + crit_exit(); + return; + } if (nseg != 0) { PSEG psg; bus_dma_segment_t *end_seg; @@ -467,11 +481,13 @@ return; } ccb->ccb_h.status |= CAM_SIM_QUEUED; -#if 0 - /* XXX Need a timeout handler */ - callout_reset(&ccb->ccb_h.timeout_ch, (ccb->ccb_h.timeout * hz) / 1000, - trmtimeout, srb); -#endif + /* + * DF-3831: arm the CCB timeout so a lost command does not wedge + * the SIM queue forever. + */ + if (ccb->ccb_h.timeout != 0) + callout_reset(&ccb->ccb_h.timeout_ch, + (ccb->ccb_h.timeout * hz) / 1000, trm_timeout, pSRB); trm_SendSRB(pACB, pSRB); crit_exit(); return; @@ -527,6 +543,27 @@ } +/* + * DF-3831: CCB timeout -- the command was accepted by a target but never + * completed. Reset the SCSI bus so the adapter state machine (and every + * queued CCB) is recovered by the existing trm_reset() machinery. + */ +static void +trm_timeout(void *arg) +{ + PSRB pSRB = arg; + PACB pACB; + union ccb *ccb; + + ccb = pSRB->pccb; + if (ccb == NULL) + return; + pACB = (PACB)ccb->ccb_h.ccb_trmacb_ptr; + kprintf("trm%d: command timeout, resetting SCSI bus\n", + pACB->AdapterUnit); + trm_reset(pACB); +} + static void trm_action(struct cam_sim *psim, union ccb *pccb) { @@ -2488,6 +2525,7 @@ pccb = pSRB->pccb; if (pccb == NULL) return; + callout_stop(&pccb->ccb_h.timeout_ch); pcsio = &pccb->csio; target_id = pSRB->pccb->ccb_h.target_id; target_lun = pSRB->pccb->ccb_h.target_lun; |