⬢ DragonFlyBSD Kernel Audit
DF-3772 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/disk/ahci/ahci.c b/sys/dev/disk/ahci/ahci.c
index 0fda0a32..3a4e8ed6 100644
--- a/sys/dev/disk/ahci/ahci.c
+++ b/sys/dev/disk/ahci/ahci.c
@@ -2619,7 +2619,18 @@ ahci_port_intr(struct ahci_port *ap, int blockable)
 		active = &ap->ap_active;
 	}
 	KKASSERT(!(ap->ap_sactive && ap->ap_active));
-	KKASSERT((ci_saved & (ap->ap_sactive | ap->ap_active)) == ci_saved);
+	/*
+	 * Some chipsets (e.g. AMD after IFS errors) leave stale CI/SACT
+	 * bits set after a port stop.  The driver is designed to survive
+	 * this (see the ahci_pactive() recovery below), so mask-and-warn
+	 * instead of turning a recoverable condition into a panic.
+	 */
+	if ((ci_saved & ~(ap->ap_sactive | ap->ap_active)) != 0) {
+		kprintf("%s: WARNING: stale chip activity %08x\n",
+			PORTNAME(ap),
+			ci_saved & ~(ap->ap_sactive | ap->ap_active));
+		ci_saved &= (ap->ap_sactive | ap->ap_active);
+	}
 #if 0
 	kprintf("CHECK act=%08x/%08x sact=%08x/%08x\n",
 		ap->ap_active, ahci_pread(ap, AHCI_PREG_CI),
@@ -3347,8 +3358,8 @@ ahci_get_err_ccb(struct ahci_port *ap)
 	if (ci) {
 		kprintf("%s: ahci_get_err_ccb: ci not 0 (%08x)\n",
 			ap->ap_name, ci);
+		ahci_pwrite(ap, AHCI_PREG_CI, ci);	/* clear stale bits */
 	}
-	KKASSERT(ci == 0);
 	KKASSERT((ap->ap_flags & AP_F_ERR_CCB_RESERVED) == 0);
 	ap->ap_flags |= AP_F_ERR_CCB_RESERVED;
 
@@ -3396,10 +3407,12 @@ ahci_put_err_ccb(struct ahci_ccb *ccb)
 	}
 	ci = ahci_pread(ap, AHCI_PREG_CI);
 	if (ci) {
-		panic("ahci_put_err_ccb(%d) but CI %08x != 0 "
+		kprintf("%s: ahci_put_err_ccb(%d) but CI %08x != 0 "
 		      "(act=%08x sact=%08x)\n",
+		      PORTNAME(ap),
 		      ccb->ccb_slot, ci,
 		      ap->ap_active, ap->ap_sactive);
+		ahci_pwrite(ap, AHCI_PREG_CI, ci);
 	}
 
 	KKASSERT(ccb == ap->ap_err_ccb);