DF-3845 / fix.diff
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); } |