diff --git a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/pci.h b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/pci.h index 73405fc90c..3cac83ccbe 100644 --- a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/pci.h +++ b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/pci.h @@ -122,10 +122,12 @@ extern int pci_restore_state(struct pci_dev *dev); #define PCI_ERR_FATAL 2 /* Action discriminants (must match redox-driver-core::RecoveryAction). */ -#define PCI_RECOV_HANDLED 0 -#define PCI_RECOV_RESET 1 -#define PCI_RECOV_RESCAN_BUS 2 -#define PCI_RECOV_FATAL 3 +#define PCI_RECOV_HANDLED 0 +#define PCI_RECOV_RESET 1 +#define PCI_RECOV_RESCAN_BUS 2 +#define PCI_RECOV_FATAL 3 +#define PCI_RECOV_CAN_RECOVER 4 +#define PCI_RECOV_RECOVERED 5 /* * Register a C error handler and start the worker thread that diff --git a/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs b/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs index 95650eee61..fcf15a7c04 100644 --- a/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs +++ b/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs @@ -29,6 +29,8 @@ enum RecoveryAction { ResetDevice = 1, RescanBus = 2, Fatal = 3, + CanRecover = 4, + Recovered = 5, } /// Wire payload sent from driver-manager to the spawned driver. @@ -143,6 +145,8 @@ fn worker_loop(fd: i32) { 0 => RecoveryAction::Handled, 1 => RecoveryAction::ResetDevice, 2 => RecoveryAction::RescanBus, + 4 => RecoveryAction::CanRecover, + 5 => RecoveryAction::Recovered, _ => RecoveryAction::Fatal, }; let response = DriverErrorResponse(action).encode(); diff --git a/local/recipes/drivers/redox-driver-core/source/src/driver.rs b/local/recipes/drivers/redox-driver-core/source/src/driver.rs index b4fff86081..142d325827 100644 --- a/local/recipes/drivers/redox-driver-core/source/src/driver.rs +++ b/local/recipes/drivers/redox-driver-core/source/src/driver.rs @@ -49,16 +49,31 @@ pub enum ErrorSeverity { } /// Action the manager should take in response to a `Driver::on_error` callback. +/// +/// Mirrors Linux's `pci_ers_result` (include/linux/pci.h). The four historical +/// variants (`Handled`/`ResetDevice`/`RescanBus`/`Fatal`) are stable and +/// occupy discriminants 0..=3 on the wire. The two newer variants (`CanRecover` +/// and `Recovered`) extend the set to match Linux's 6-state model and occupy +/// discriminants 4 and 5; both must be handled by any consumer that parses +/// the sidecar IPC payload. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RecoveryAction { - /// Driver handled the error; continue normally. + /// Driver handled the error; continue normally. Maps to `PCI_ERS_RESULT_NONE`. Handled, - /// Driver requests a reset of the device via pcid. + /// Driver requests a reset of the device via pcid. Maps to `PCI_ERS_RESULT_NEED_RESET`. ResetDevice, - /// Driver requests the entire slot to be rescanned. + /// Driver requests the entire slot to be rescanned. Maps to a hard rescan, not a + /// specific `pci_ers_result` value; used by `route_to_driver` when the bound + /// driver does not respond on the sidecar IPC and the severity is Fatal. RescanBus, - /// Driver failed to recover; escalate to the operator. + /// Driver failed to recover; escalate to the operator. Maps to `PCI_ERS_RESULT_DISCONNECT`. Fatal, + /// Driver can recover without a slot reset. Maps to `PCI_ERS_RESULT_CAN_RECOVER`. + /// The manager clears the AER status registers via pcid and lets I/O resume. + CanRecover, + /// Recovery completed successfully. Maps to `PCI_ERS_RESULT_RECOVERED`. + /// The manager acknowledges completion and resumes normal scheduling. + Recovered, } /// The 6-state PCI error-recovery result, mirroring Linux's diff --git a/local/recipes/system/driver-manager/source/src/scheme.rs b/local/recipes/system/driver-manager/source/src/scheme.rs index 3aba75ed9e..833958f202 100644 --- a/local/recipes/system/driver-manager/source/src/scheme.rs +++ b/local/recipes/system/driver-manager/source/src/scheme.rs @@ -414,7 +414,11 @@ impl DriverManagerScheme { /// Map a `RecoveryAction` (from `Driver::on_error` / AER routing) /// to the action vocabulary accepted by `dispatch_recovery`. /// Returns `None` for actions that don't need an auto-dispatch - /// (e.g. `Handled`, `Fatal` which is operator-only). + /// (e.g. `Handled`, `Fatal` which is operator-only). `CanRecover` + /// and `Recovered` map to informational strings so they show up in + /// the AER dispatch log but do not trigger a separate auto-dispatch + /// — `CanRecover` clears AER status via pcid, and `Recovered` is a + /// terminal acknowledgement. #[cfg(any(test, target_os = "redox"))] pub fn recovery_action_str(action: RecoveryAction) -> Option<&'static str> { match action { @@ -422,6 +426,8 @@ impl DriverManagerScheme { RecoveryAction::ResetDevice => Some("reset_device"), RecoveryAction::RescanBus => Some("rescan_bus"), RecoveryAction::Fatal => None, + RecoveryAction::CanRecover => Some("can_recover"), + RecoveryAction::Recovered => Some("recovered"), } } @@ -859,6 +865,22 @@ mod tests { ); } + #[test] + fn recovery_action_can_recover_maps_to_can_recover_str() { + assert_eq!( + DriverManagerScheme::recovery_action_str(RecoveryAction::CanRecover), + Some("can_recover") + ); + } + + #[test] + fn recovery_action_recovered_maps_to_recovered_str() { + assert_eq!( + DriverManagerScheme::recovery_action_str(RecoveryAction::Recovered), + Some("recovered") + ); + } + #[test] fn new_id_parses_vendor_device() { let (driver, entry) = parse_new_id("e1000d 0x8086 0x100E").unwrap();