Skip to content

services: Add the Recovery Agent sequence test for streaming boot - #37

Open
chrysh wants to merge 1 commit into
ocp-recovery-serverfrom
ocp-agent-sequence-test
Open

chrysh wants to merge 1 commit into
ocp-recovery-serverfrom
ocp-agent-sequence-test

Conversation

@chrysh

@chrysh chrysh commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Third of three, based on #36. The register file and the dispatch answer one access at a time, and their in-crate tests check one access at a time. This drives the whole sequence the BMC runs for a streaming boot: read PROT_CAP and DEVICE_ID, read the reason code that says the device has no image to boot, watch the heartbeat move, program INDIRECT_FIFO_CTRL, push the image in transport-sized chunks while polling INDIRECT_FIFO_STATUS, activate through RECOVERY_CTRL, then poll RECOVERY_STATUS and DEVICE_STATUS to the terminal values.

The agent half goes through dispatch with command bytes and payloads, the device half through the owner methods, which is the split the i2c server-runtime and the policy loop will run. The test decodes register bytes rather than calling the accessors, because that is what the agent has: a response buffer.

The claims the sequence cannot make in passing get their own test: a failed stage names the image index it failed on, an activate value of 0x1 is refused and leaves the field at ACTIVATE_IDLE rather than the 0xe a bitwise clear would leave, an activation with the image still short reaches the device because the verify path checks completeness and the dispatch does not, and arming forced recovery survives the reset take that clears only byte 0.

The transport is out of scope, so the chunk size and the transport_max argument are one constant, MAX_TRANSFER_BYTES, and nothing here assumes SMBus.

Gap found while writing this, reported rather than fixed: RecoveryCommand::scope() has no caller. HW_STATUS, INDIRECT_FIFO_CTRL, INDIRECT_FIFO_STATUS and INDIRECT_FIFO_DATA are Scope::RecoveryMode, and the dispatch serves them whether or not the device is in recovery mode. The test asserts what the code does today.

Verification: bazel test //services/ocp-recovery/... passes all three targets, the clippy aspect is clean and ./pw format --check is clean. The asserts were checked against mutations of clear_activation and record_drained_write; each makes the sequence fail.

Stack, review in order:

  1. services: Add the OCP recovery register layouts #35, the register layouts
  2. services: Add the OCP recovery device dispatch #36, the device dispatch
  3. this PR, the Recovery Agent sequence test

The register file and the dispatch answer one access at a time, and their
in-crate tests check one access at a time. This drives the whole sequence
the BMC runs for a streaming boot: read PROT_CAP and DEVICE_ID, read the
reason code that says the device has no image to boot, watch the heartbeat
move, program INDIRECT_FIFO_CTRL, push the image in transport-sized chunks
while polling INDIRECT_FIFO_STATUS, activate through RECOVERY_CTRL, then
poll RECOVERY_STATUS and DEVICE_STATUS to the terminal values. The agent
half goes through dispatch with command bytes and payloads, the device half
through the owner methods, which is the split the i2c server-runtime and
the policy loop will run.

The test decodes register bytes rather than calling the accessors, because
that is what the agent has: a response buffer. StagingSpy wraps RamStaging
to record the size the device announced to the region, which RamStaging
does not keep.

The claims the sequence cannot make in passing get their own test: a failed
stage names the image index it failed on, an activate value of 0x1 is
refused and leaves the field at ACTIVATE_IDLE rather than the 0xe a bitwise
clear would leave, an activation with the image still short reaches the
device because the verify path checks completeness and the dispatch does
not, and arming forced recovery survives the reset take that clears only
byte 0.

The transport is out of scope, so the chunk size and the transport_max
argument are one constant, MAX_TRANSFER_BYTES, and nothing here assumes
SMBus.

Gap found while writing this: RecoveryCommand::scope() has no caller.
HW_STATUS, INDIRECT_FIFO_CTRL, INDIRECT_FIFO_STATUS and INDIRECT_FIFO_DATA
are Scope::RecoveryMode, and the dispatch serves them whether or not the
device is in recovery mode. The test asserts what the code does today and
leaves the scope check to the crate that owns the dispatch.

Signed-off-by: Christina Quast <christina.quast@9elements.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant