⬢ DragonFlyBSD Kernel Audit
DF-3845 / fix.diff
← back to finding ↓ download raw
diff -u -p -r /tmp/opencode/fix/p3845_base/raid/mrsas.c /tmp/opencode/fix/p3845_mod/raid/mrsas.c
--- a/sys/dev/raid/mrsas/mrsas.c	2026-09-16 14:47:26.472997301 +0000
+++ b/sys/dev/raid/mrsas/mrsas.c	2026-09-16 14:47:26.476997252 +0000
@@ -2334,8 +2334,14 @@ int mrsas_reset_ctrl(struct mrsas_softc
         /* Now return commands back to the CAM layer */
         for (i = 0 ; i < sc->max_fw_cmds; i++) {
             mpt_cmd = sc->mpt_cmd_list[i];
-            if (mpt_cmd->ccb_ptr) {
-                ccb = (union ccb *)(mpt_cmd->ccb_ptr);
+            ccb = (union ccb *)(mpt_cmd->ccb_ptr);
+            if (ccb != NULL) {
+                /*
+                 * DF-3845: set the reset status before mrsas_cmd_done()
+                 * claims the ccb; if the ISR completed it concurrently,
+                 * the atomic claim inside mrsas_cmd_done() makes the
+                 * call a no-op instead of a double completion.
+                 */
                 ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
                 mrsas_cmd_done(sc, mpt_cmd);
                 atomic_dec(&sc->fw_outstanding);
diff -u -p -r /tmp/opencode/fix/p3845_base/raid/mrsas_cam.c /tmp/opencode/fix/p3845_mod/raid/mrsas_cam.c
--- a/sys/dev/raid/mrsas/mrsas_cam.c	2026-09-16 14:47:26.472997301 +0000
+++ b/sys/dev/raid/mrsas/mrsas_cam.c	2026-09-16 14:47:26.472997301 +0000
@@ -362,13 +362,13 @@ mrsas_scsiio_timeout(void *data)
         return;
     }
 
-    /* Below callout is dummy entry so that it will be
-     * cancelled from mrsas_cmd_done(). Now Controller will
-     * go to OCR/Kill Adapter based on OCR enable/disable
-     * property of Controller from ocr_thread context.
+    /*
+     * DF-3845: do NOT re-arm on a command that may already have
+     * completed on another CPU -- callout_stop() in mrsas_cmd_done()
+     * does not wait for a concurrently-running callback, and a 600 s
+     * re-arm later fires on the command's next owner.  Request the
+     * reset once; the ocr thread owns recovery from here.
      */
-    callout_reset(&cmd->cm_callout, (600000 * hz) / 1000,
-    mrsas_scsiio_timeout, cmd);
     sc->do_timedout_reset = 1;
     if(sc->ocr_thread_active)
         wakeup(&sc->ocr_chan);
@@ -1079,11 +1079,24 @@ void mrsas_xpt_release(struct mrsas_soft
  */
 void mrsas_cmd_done(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd)
 {
+    union ccb *ccb;
+
+    /*
+     * DF-3845: the ISR completion path, the OCR return-to-CAM flush and
+     * the timeout path can all reach this function for one cmd with no
+     * common lock.  Claim the command atomically: exactly one caller
+     * performs the completion; the others are no-ops.
+     */
+    ccb = cmd->ccb_ptr;
+    if (ccb == NULL ||
+        !atomic_cmpset_ptr((volatile uintptr_t *)&cmd->ccb_ptr,
+                           (uintptr_t)ccb, (uintptr_t)NULL))
+        return;
+
     callout_stop(&cmd->cm_callout);
     mrsas_unmap_request(sc, cmd);
     lockmgr(&sc->sim_lock, LK_EXCLUSIVE);
-    xpt_done(cmd->ccb_ptr);
-    cmd->ccb_ptr = NULL;
+    xpt_done(ccb);
     lockmgr(&sc->sim_lock, LK_RELEASE);
     mrsas_release_mpt_cmd(cmd);
 }