⬢ DragonFlyBSD Kernel Audit
DF-3830 / fix.diff
← back to finding ↓ download raw
--- 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[] = {