Skip to content

scsi: one bus layer for every controller, on top of BlockNode - #357

Merged
techomancer merged 11 commits into
techomancer:mainfrom
jamesbraid:scsi-bus
Oct 30, 2026
Merged

techomancer merged 11 commits into
techomancer:mainfrom
jamesbraid:scsi-bus

Conversation

@jamesbraid

Copy link
Copy Markdown
Contributor

Follow-up to #336 and #337. The AIC-7880, ISP1040 and WD33C93A each had their own target table and their own copy of attach, overlay export and CHD sync, and every machine had its own [scsi.N] loop. This puts them all on one SCSI bus layer above BlockNode. The commit messages have the details.

  • ScsiTarget is what varies on the bus (disk/CD-ROM or DaynaPort), ScsiBus is the shared mechanism.
  • The machine builds each bus from the config and hands it to the controller at construction, as @techomancer asked in scsi: replace the DiskBackend enum with a layered BlockNode interface? #336. Controllers no longer open images.
  • One function, block_node::open_image, picks CHD, CHD CD, COW or raw, for attach and for disc changes.
  • The CD changer moves to the node level: a ChangerNode behind a small Removable trait. I kept Removable out of BlockNode so a tape can use it later without being a block device.

Things you'll notice:

  • The O2 and Octane now report IRIS EMUL DISK / IRIS EMUL CDROM in INQUIRY. The Indy and Indigo2 keep their Sony CD-ROM.
  • sync_chd now folds on every controller, not just the WD33C93A.
  • A CHD CD can be swapped in at run time.

Snapshot formats are unchanged and Indy/Indigo2 snapshots come out byte-identical. Tested on all four machines alongside the other open branches, with no change in boot time or diskperf.

The AIC-7880, the ISP1040 and the WD33C93A each kept their own array
of disks and their own copy of the attach, query, overlay export and
CHD sync code. Each now owns a ScsiBus and keeps only its registers
and DMA.

ScsiTarget is what varies on a bus. A disk or CD-ROM (ScsiDevice) and
a DaynaPort implement it. Besides request it has optional behaviour
with do-nothing defaults: a copy-on-write layer, CHD sync, a disc
changer, a block size. Controllers and the monitor ask a target for
behaviour, not for its type, so a DaynaPort is no longer a mode of
ScsiDevice. ScsiBus is the shared mechanism: the id table, attach,
request, and overlay export and import for the snapshot code. Each
controller gives its bus its INQUIRY identities.

attach_from_config walks the [scsi.N] tables once: placement, scratch
volume, CI overlay under /tmp, and the IRIS_NO_EXIT_ON_POWEROFF error
policy, with optional snapshot disk provenance. The machines move onto
it in the following commits.

The WD33C93A snapshot holds registers only and never the targets, so
its format is unchanged. Its bus is eight ids wide and now refuses a
larger id instead of ignoring it.
The O2 and the Octane each walked the [scsi.N] tables with the same
loop: place the table, prepare a scratch volume, send a CI overlay to
/tmp, attach, and either end the run or skip the target under
IRIS_NO_EXIT_ON_POWEROFF. Both now give attach_from_config a route from
controller number to bus and keep nothing else.

The O2 takes its snapshot disk list from the same call. The set is the
one it recorded before, disks without CD-ROMs, so existing manifests
still match. The Octane has no snapshot manifest and records nothing.
…rom_config

The Indy's loop was a third copy of the O2's and Octane's, with the
same overlay, scratch and error handling and an extra DaynaPort branch.
It now routes controller numbers through Hpc3::scsi_bus and hands the
DaynaPort construction, which stays where the gateway is built, to
attach_from_config as a closure. Hpc3's add_scsi_device and its
overlay variant, which only forwarded to the chip, are gone.

Controller 1 on a machine without it is now a reported error naming the
slot instead of a panic. The snapshot disk list is the same set as
before, CD-ROMs included, so Indy and Indigo2 manifests still match.
…chine

The O2 and the Octane answered INQUIRY as "IRIS EMULATED" for both
disks and CD-ROMs, the Indy as "IRIS EMUL DISK", and each controller
defined its own constant. Every machine now reports the Indy's disk
identity from scsi.rs, and every CD-ROM except the Indy's reports a
matching "IRIS EMUL CDROM". The Indy and Indigo2 keep their Sony
CDU-76S.

The disk and CD-ROM model strings on the O2 and Octane change, which a
guest can see in INQUIRY.
impl ScsiTarget for ScsiDevice forwarded a score of methods to inherent
methods of the same name, so every signature existed twice. The bodies
now live in the trait impl and the inherent copies are gone.

attach_from_config also drops its DaynaPort callback and the three-state
provenance enum. The Indy and Indigo2 attach their DaynaPorts themselves,
where Hpc3 builds the gateway, and one flag says whether the snapshot
manifest lists CD-ROMs, which only those two machines have always done.
Manifests are unchanged.
Only the Indy and Indigo2's WD33C93A counted and folded the .diff.chd
sidecars a compressed CHD disk writes to. On the O2 (AIC-7880), the Octane
(ISP1040) and an Indigo2's second controller the Workstation hooks fell
through to their defaults, so a clean exit with sync_chd left the diffs
unfolded.

The count and the fold now live on ScsiBus and take the buses of every
controller on the board; the WD33C93A's copies are gone and each machine
passes its own buses.
ScsiDevice::open chose between a CHD, a CHD CD, a copy-on-write overlay and
a raw file, while a disc change opened its file as raw only, so a changer
could not swap to a CHD CD although a drive could be started with one.

The choice moves to block_node::open_image. The bus builds the node when it
attaches a target and hands it to ScsiDevice::new, and the changer's load,
eject and insert paths open through the same function.
A CD-ROM's disc list, active path, size, tray state and pending medium
change lived in ScsiDevice next to a backend that was None when the tray
was empty, and ScsiTarget carried seven methods to edit them.

Removable media is now a trait of its own, Removable (present, changed,
eject, load), and a ChangerNode implements it and BlockNode: it forwards to
the active disc, opens only that disc, and keeps the queue. It is not part
of BlockNode because a tape cartridge is removable without being a block
device. ScsiDevice holds a Media (a disk's node or a changer) with no
Option, asks it for unit attention and not-ready, and ScsiTarget exposes one
changer accessor for the monitor, the CI socket and the window. The queue
rules and the monitor output are unchanged.

A next disc that will not open used to turn the queue anyway and leave the
old disc loaded; the drive is now left as it was.
Each controller made an empty ScsiBus in its constructor and the machine
reached in afterwards to attach targets. The machine now builds the bus,
fills it from the [scsi.N] tables and passes it to the controller, so a
controller exists with its targets and no machine attaches through a
controller.

Each chip owns the kind of bus it drives (width and INQUIRY identities)
and offers it as new_bus(). The bus could take identities at attach
instead, but that would change attach_device and move each identity out
of its chip. A target attached after boot, by the monitor or the CI socket,
goes on the same bus through the controller. The Default impls of the WD33C93A
and ISP1040 had no users and go with the empty-bus constructors, which are
now test-only.

The Indy, Indigo2, O2 and Octane attach their SCSI targets a little earlier
in start-up, so their per-target log lines come before the flash and
NVRAM messages they used to follow.
Both are visible to a user: a CHD CD swapped in at run time now loads, and
quitting with sync_chd folds the diffs on every controller.
@techomancer
techomancer merged commit bbe192e into techomancer:main Oct 30, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants