--- a/sys/dev/disk/trm/trm.c +++ b/sys/dev/disk/trm/trm.c @@ -120,6 +120,7 @@ static void NVRAM_trm_read_all(PNVRAMTYPE pEEpromBuf,PACB pACB); static u_int8_t NVRAM_trm_get_data(PACB pACB, u_int8_t bAddr); static void NVRAM_trm_write_all(PNVRAMTYPE pEEpromBuf,PACB pACB); +static void trm_detach_flush(PACB pACB); static void NVRAM_trm_set_data(PACB pACB, u_int8_t bAddr, u_int8_t bData); static void NVRAM_trm_write_cmd(PACB pACB, u_int8_t bCmd, u_int8_t bAddr); static void NVRAM_trm_wait_30us(PACB pACB); @@ -2781,6 +2782,66 @@ return; } +/* + * DF-3830: complete every SRB still owned by the adapter (active, going + * and waiting lists) so that no CCB and no dma map outlives the softc. + * Called from trm_detach() before any resource is released. + */ +static void +trm_detach_flush(PACB pACB) +{ + PDCB pDCB, pdcb; + PSRB psrb; + int i; + + crit_enter(); + /* mask chip interrupts before touching anything else */ + trm_reg_write8(0x00, TRMREG_DMA_INTEN); + trm_reg_write8(0x00, TRMREG_SCSI_INTEN); + pACB->pActiveDCB = NULL; + + pDCB = pACB->pLinkDCB; + if (pDCB != NULL) { + pdcb = pDCB; + do { + if ((psrb = pdcb->pActiveSRB) != NULL) { + if (psrb->pccb != NULL) { + psrb->pccb->ccb_h.status = CAM_UNEXP_BUSFREE; + xpt_done(psrb->pccb); + psrb->pccb = NULL; + } + pdcb->pActiveSRB = NULL; + } + for (i = 0; i < pdcb->GoingSRBCnt && pdcb->pGoingSRB; i++) { + psrb = pdcb->pGoingSRB; + pdcb->pGoingSRB = psrb->pNextSRB; + if (psrb->pccb != NULL) { + psrb->pccb->ccb_h.status = CAM_UNEXP_BUSFREE; + xpt_done(psrb->pccb); + psrb->pccb = NULL; + } + } + while ((psrb = pdcb->pWaitingSRB) != NULL) { + pdcb->pWaitingSRB = psrb->pNextSRB; + if (psrb->pccb != NULL) { + psrb->pccb->ccb_h.status = CAM_REQ_ABORTED; + xpt_done(psrb->pccb); + psrb->pccb = NULL; + } + } + pdcb->GoingSRBCnt = 0; + pdcb->pGoingSRB = NULL; + pdcb->pGoingLastSRB = NULL; + pdcb->pWaitingSRB = NULL; + pdcb->pWaitingLastSRB = NULL; + pdcb = pdcb->pNextDCB; + } while (pdcb != pDCB); + } + pACB->pLinkDCB = NULL; + pACB->pDCBRunRobin = NULL; + crit_exit(); +} + static void trm_ScsiRstDetect(PACB pACB) { @@ -3693,7 +3754,25 @@ { PACB pACB = device_get_softc(dev); - bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), pACB->iores); + /* + * DF-3830: teardown order matters. + * 1. take the SIM out of CAM so no new CCB reaches us, + * 2. quiesce the chip and complete every in-flight CCB, + * 3. tear down the interrupt, + * 4. free DMA memory and tags, + * 5. release the I/O port last. + */ + xpt_freeze_simq(pACB->psim, 1); + xpt_bus_deregister(cam_sim_path(pACB->psim)); + + trm_detach_flush(pACB); /* completes all outstanding CCBs */ + + xpt_async(AC_LOST_DEVICE, pACB->ppath, NULL); + bus_teardown_intr(dev, pACB->irq, pACB->ih); + bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irq); + xpt_free_path(pACB->ppath); + cam_sim_free(pACB->psim); + trm_destroySRB(pACB); bus_dma_tag_destroy(pACB->sg_dmat); bus_dmamap_unload(pACB->srb_dmat, pACB->srb_dmamap); @@ -3707,12 +3786,7 @@ bus_dmamap_destroy(pACB->sense_dmat, pACB->sense_dmamap); bus_dma_tag_destroy(pACB->sense_dmat); bus_dma_tag_destroy(pACB->buffer_dmat); - bus_teardown_intr(dev, pACB->irq, pACB->ih); - bus_release_resource(dev, SYS_RES_IRQ, 0, pACB->irq); - xpt_async(AC_LOST_DEVICE, pACB->ppath, NULL); - xpt_free_path(pACB->ppath); - xpt_bus_deregister(cam_sim_path(pACB->psim)); - cam_sim_free(pACB->psim); + bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), pACB->iores); return (0); } static device_method_t trm_methods[] = {