# lsscsi-sysfs-fixture.sh — materialise the lsscsi sysfs fixture tree under $1. # # SOURCED (not exec'd) by 99-lsscsi.test, which is why it takes no shebang and # sets no options: the suite owns the shell. # # WHAT THIS IS. lsscsi(8) reads /sys and nothing else — it issues no ioctl and # opens no device — so the whole tool is measurable offline against a synthetic # sysfs. This is that sysfs: four hosts on four different transports carrying a # disk, a tape, an enclosure, a cd/dvd and a second and third disk, plus one # NVMe controller. Every attribute lsscsi 0.30 reads for any of its listing # forms is present, so no form renders a placeholder for want of a fixture. # # IT IS THE FIXTURE, IN REVIEWABLE FORM. brintos-selftests installs data/ with # `install -m 0644 data/*`, which is a flat file copy and cannot carry a # directory tree, so the ~330-file tree is shipped as the deterministic script # that builds it rather than as the tree itself. The expected outputs beside it # (data/lsscsi-expected-*.txt) were captured from a native x86-64 build of the # same lsscsi source against the tree THIS script produces, so a drift here # reddens the comparison rather than passing quietly. # # IT IS WRITTEN FOR A GUEST THAT IS SLOW TO exec. Every path is spelled out # instead of being computed with dirname/cut, mkdir is called once per group # rather than once per file, and file bodies go out through the shell's own # `printf >` — so the whole tree costs ~40 execs rather than ~400. The argv of # each mkdir is kept well under this platform's 8192 B __wasm32_args_buf # (brintos/hardwarejs#15); do not collapse them into one call. R=$1 P=$R/devices/pci0000:00 H0=$P/0000:00:10.0/host0 H1=$P/0000:00:11.0/host1 H2=$P/0000:00:12.0/host2 H3=$P/0000:00:13.0/host3 D0=$H0/target0:0:0/0:0:0:0 D1=$H0/target0:0:1/0:0:1:0 D2=$H1/port-1:0/end_device-1:0/target1:0:0/1:0:0:0 D3=$H1/port-1:1/end_device-1:1/target1:0:1/1:0:1:0 D4=$H2/rport-2:0-0/target2:0:0/2:0:0:0 D5=$H3/session3/target3:0:0/3:0:0:0 N0=$P/0000:00:14.0/nvme/nvme0 mkdir -p "$D0/block/sda/queue" "$D0/scsi_generic/sg0" "$D0/scsi_disk/0:0:0:0" mkdir -p "$D1/scsi_tape/st0" "$D1/scsi_generic/sg1" mkdir -p "$D2/block/sdb/queue" "$D2/block/sdb/integrity" "$D2/scsi_generic/sg2" "$D2/scsi_disk/1:0:0:0" mkdir -p "$D3/enclosure/1:0:1:0" "$D3/scsi_generic/sg3" mkdir -p "$D4/block/sr0/queue" "$D4/scsi_generic/sg4" mkdir -p "$D5/block/sdc/queue" "$D5/scsi_generic/sg5" "$D5/scsi_disk/3:0:0:0" mkdir -p "$N0/nvme0n1/queue" # --- the six logical units --------------------------------------------------- # Common attributes first; the per-LU differences follow each block. for d in "$D0" "$D1" "$D2" "$D3" "$D4" "$D5"; do printf 'running\n' > "$d/state" printf '32\n' > "$d/queue_depth" printf '0\n' > "$d/device_blocked" printf '30\n' > "$d/timeout" printf '0x10\n' > "$d/iodone_cnt" printf '0x10\n' > "$d/iorequest_cnt" printf '0x0\n' > "$d/ioerr_cnt" printf 'EMCRAFT\n' > "$d/vendor" done printf '0\n' > "$D0/type" printf 'BRINTOS DISK A\n' > "$D0/model" printf '1.00\n' > "$D0/rev" printf '5\n' > "$D0/scsi_level" printf '247:0\n' > "$D0/block/sda/dev" printf '2097152\n' > "$D0/block/sda/size" printf '512\n' > "$D0/block/sda/queue/logical_block_size" printf '512\n' > "$D0/block/sda/queue/physical_block_size" printf '512\n' > "$D0/block/sda/queue/hw_sector_size" printf '247:64\n' > "$D0/scsi_generic/sg0/dev" printf '0\n' > "$D0/scsi_disk/0:0:0:0/protection_type" printf 'none\n' > "$D0/scsi_disk/0:0:0:0/protection_mode" printf '0\n' > "$D0/scsi_disk/0:0:0:0/app_tag_own" printf 'write back\n' > "$D0/scsi_disk/0:0:0:0/cache_type" printf '1\n' > "$D0/scsi_disk/0:0:0:0/FUA" # VPD page 0x83: one NAA-6 (IEEE Registered Extended) designator, binary code # set. This is what --unit renders as the logical-unit name. printf '\000\203\000\024\001\003\000\020\140\005\014\301\340\253\315\000\000\000\000\000\000\000\000\001' > "$D0/vpd_pg83" printf '1\n' > "$D1/type" printf 'BRINTOS TAPE A\n' > "$D1/model" printf '2.10\n' > "$D1/rev" printf '3\n' > "$D1/scsi_level" printf '247:1\n' > "$D1/scsi_tape/st0/dev" printf '247:65\n' > "$D1/scsi_generic/sg1/dev" # lsscsi 0.30 resolves a tape node through the legacy `scsi_tape:st` link, # not through the `scsi_tape/` directory the modern kernel also presents. Carry # both, so the fixture is faithful AND the tool has something it can follow. ln -sfn scsi_tape/st0 "$D1/scsi_tape:st0" printf '0\n' > "$D2/type" printf 'BRINTOS DISK B\n' > "$D2/model" printf '3.02\n' > "$D2/rev" printf '6\n' > "$D2/scsi_level" printf '247:16\n' > "$D2/block/sdb/dev" printf '20971520\n' > "$D2/block/sdb/size" printf '512\n' > "$D2/block/sdb/queue/logical_block_size" printf '4096\n' > "$D2/block/sdb/queue/physical_block_size" printf '512\n' > "$D2/block/sdb/queue/hw_sector_size" printf 'T10-DIF-TYPE1-CRC\n' > "$D2/block/sdb/integrity/format" printf '0\n' > "$D2/block/sdb/integrity/tag_size" printf '1\n' > "$D2/block/sdb/integrity/read_verify" printf '1\n' > "$D2/block/sdb/integrity/write_generate" printf '247:66\n' > "$D2/scsi_generic/sg2/dev" printf '1\n' > "$D2/scsi_disk/1:0:0:0/protection_type" printf 'dix1+dif1\n' > "$D2/scsi_disk/1:0:0:0/protection_mode" printf '0\n' > "$D2/scsi_disk/1:0:0:0/app_tag_own" printf 'write through\n' > "$D2/scsi_disk/1:0:0:0/cache_type" printf '1\n' > "$D2/scsi_disk/1:0:0:0/FUA" printf '13\n' > "$D3/type" printf 'BRINTOS ENCL A\n' > "$D3/model" printf '0.55\n' > "$D3/rev" printf '5\n' > "$D3/scsi_level" printf '247:67\n' > "$D3/scsi_generic/sg3/dev" printf '5\n' > "$D4/type" printf 'BRINTOS CDROM A\n' > "$D4/model" printf '1.50\n' > "$D4/rev" printf '5\n' > "$D4/scsi_level" printf '247:32\n' > "$D4/block/sr0/dev" printf '1385920\n' > "$D4/block/sr0/size" printf '2048\n' > "$D4/block/sr0/queue/logical_block_size" printf '2048\n' > "$D4/block/sr0/queue/physical_block_size" printf '2048\n' > "$D4/block/sr0/queue/hw_sector_size" printf '247:68\n' > "$D4/scsi_generic/sg4/dev" printf '0\n' > "$D5/type" printf 'BRINTOS DISK C\n' > "$D5/model" printf '4.44\n' > "$D5/rev" printf '7\n' > "$D5/scsi_level" printf '247:48\n' > "$D5/block/sdc/dev" printf '41943040\n' > "$D5/block/sdc/size" printf '4096\n' > "$D5/block/sdc/queue/logical_block_size" printf '4096\n' > "$D5/block/sdc/queue/physical_block_size" printf '512\n' > "$D5/block/sdc/queue/hw_sector_size" printf '247:69\n' > "$D5/scsi_generic/sg5/dev" printf '0\n' > "$D5/scsi_disk/3:0:0:0/protection_type" printf 'none\n' > "$D5/scsi_disk/3:0:0:0/protection_mode" # --- the four hosts ---------------------------------------------------------- for h in "$H0" "$H1" "$H2" "$H3"; do printf '0\n' > "$h/host_busy" printf '1\n' > "$h/cmd_per_lun" printf '128\n' > "$h/can_queue" printf '128\n' > "$h/sg_tablesize" printf '0\n' > "$h/unchecked_isa_dma" printf '0\n' > "$h/prot_capabilities" printf '0\n' > "$h/prot_guard_type" printf 'running\n' > "$h/state" done printf 'sym53c8xx\n' > "$H0/proc_name"; printf '0\n' > "$H0/unique_id" printf 'mpt3sas\n' > "$H1/proc_name"; printf '1\n' > "$H1/unique_id" printf 'qla2xxx\n' > "$H2/proc_name"; printf '2\n' > "$H2/unique_id" printf 'iscsi_tcp\n' > "$H3/proc_name"; printf '3\n' > "$H3/unique_id" # --- the NVMe controller ----------------------------------------------------- printf 'EMCRAFT BRINTOS NVME\n' > "$N0/model" printf '1.0\n' > "$N0/firmware_rev" printf 'BRINTOS0000001\n' > "$N0/serial" printf '1\n' > "$N0/cntlid" printf 'live\n' > "$N0/state" printf 'pcie\n' > "$N0/transport" printf '247:80\n' > "$N0/nvme0n1/dev" printf '1\n' > "$N0/nvme0n1/nsid" printf '4194304\n' > "$N0/nvme0n1/size" printf '512\n' > "$N0/nvme0n1/queue/logical_block_size" printf '512\n' > "$N0/nvme0n1/queue/physical_block_size" # --- the class and bus views ------------------------------------------------- mkdir -p "$R/class/scsi_host" "$R/class/scsi_device/0:0:0:0" \ "$R/class/scsi_device/0:0:1:0" "$R/class/scsi_device/1:0:0:0" mkdir -p "$R/class/scsi_device/1:0:1:0" "$R/class/scsi_device/2:0:0:0" \ "$R/class/scsi_device/3:0:0:0" "$R/bus/scsi/devices" mkdir -p "$R/class/block" "$R/class/nvme" ln -sfn ../../devices/pci0000:00/0000:00:10.0/host0 "$R/class/scsi_host/host0" ln -sfn ../../devices/pci0000:00/0000:00:11.0/host1 "$R/class/scsi_host/host1" ln -sfn ../../devices/pci0000:00/0000:00:12.0/host2 "$R/class/scsi_host/host2" ln -sfn ../../devices/pci0000:00/0000:00:13.0/host3 "$R/class/scsi_host/host3" R0=devices/pci0000:00/0000:00:10.0/host0/target0:0:0/0:0:0:0 R1=devices/pci0000:00/0000:00:10.0/host0/target0:0:1/0:0:1:0 R2=devices/pci0000:00/0000:00:11.0/host1/port-1:0/end_device-1:0/target1:0:0/1:0:0:0 R3=devices/pci0000:00/0000:00:11.0/host1/port-1:1/end_device-1:1/target1:0:1/1:0:1:0 R4=devices/pci0000:00/0000:00:12.0/host2/rport-2:0-0/target2:0:0/2:0:0:0 R5=devices/pci0000:00/0000:00:13.0/host3/session3/target3:0:0/3:0:0:0 ln -sfn "../../../$R0" "$R/class/scsi_device/0:0:0:0/device" ln -sfn "../../../$R1" "$R/class/scsi_device/0:0:1:0/device" ln -sfn "../../../$R2" "$R/class/scsi_device/1:0:0:0/device" ln -sfn "../../../$R3" "$R/class/scsi_device/1:0:1:0/device" ln -sfn "../../../$R4" "$R/class/scsi_device/2:0:0:0/device" ln -sfn "../../../$R5" "$R/class/scsi_device/3:0:0:0/device" ln -sfn "../../../$R0" "$R/bus/scsi/devices/0:0:0:0" ln -sfn "../../../$R1" "$R/bus/scsi/devices/0:0:1:0" ln -sfn "../../../$R2" "$R/bus/scsi/devices/1:0:0:0" ln -sfn "../../../$R3" "$R/bus/scsi/devices/1:0:1:0" ln -sfn "../../../$R4" "$R/bus/scsi/devices/2:0:0:0" ln -sfn "../../../$R5" "$R/bus/scsi/devices/3:0:0:0" ln -sfn "../../../${R0%/*}" "$R/bus/scsi/devices/target0:0:0" ln -sfn "../../../${R1%/*}" "$R/bus/scsi/devices/target0:0:1" ln -sfn "../../../${R2%/*}" "$R/bus/scsi/devices/target1:0:0" ln -sfn "../../../${R3%/*}" "$R/bus/scsi/devices/target1:0:1" ln -sfn "../../../${R4%/*}" "$R/bus/scsi/devices/target2:0:0" ln -sfn "../../../${R5%/*}" "$R/bus/scsi/devices/target3:0:0" ln -sfn ../../../devices/pci0000:00/0000:00:10.0/host0 "$R/bus/scsi/devices/host0" ln -sfn ../../../devices/pci0000:00/0000:00:11.0/host1 "$R/bus/scsi/devices/host1" ln -sfn ../../../devices/pci0000:00/0000:00:12.0/host2 "$R/bus/scsi/devices/host2" ln -sfn ../../../devices/pci0000:00/0000:00:13.0/host3 "$R/bus/scsi/devices/host3" ln -sfn "../../$R0/block/sda" "$R/class/block/sda" ln -sfn "../../$R2/block/sdb" "$R/class/block/sdb" ln -sfn "../../$R4/block/sr0" "$R/class/block/sr0" ln -sfn "../../$R5/block/sdc" "$R/class/block/sdc" ln -sfn ../../devices/pci0000:00/0000:00:14.0/nvme/nvme0 "$R/class/nvme/nvme0" # --- the four transport classes ---------------------------------------------- mkdir -p "$R/class/spi_host/host0" "$R/class/spi_transport/target0:0:0" \ "$R/class/spi_transport/target0:0:1" printf 'LVD\n' > "$R/class/spi_host/host0/signalling" printf '320\n' > "$R/class/spi_transport/target0:0:0/max_speed" printf '1\n' > "$R/class/spi_transport/target0:0:0/width" printf '8\n' > "$R/class/spi_transport/target0:0:0/period" printf '63\n' > "$R/class/spi_transport/target0:0:0/offset" printf '160\n' > "$R/class/spi_transport/target0:0:1/max_speed" printf '1\n' > "$R/class/spi_transport/target0:0:1/width" printf '12\n' > "$R/class/spi_transport/target0:0:1/period" printf '31\n' > "$R/class/spi_transport/target0:0:1/offset" mkdir -p "$R/class/sas_host/host1" "$R/class/sas_device/end_device-1:0" \ "$R/class/sas_device/end_device-1:1" mkdir -p "$R/class/sas_end_device/end_device-1:0" "$R/class/sas_end_device/end_device-1:1" \ "$R/class/sas_phy/phy-1:0" "$R/class/sas_phy/phy-1:1" printf '0x5000c50012345678\n' > "$R/class/sas_host/host1/device_name" printf '0x5000c5001234abcd\n' > "$R/class/sas_device/end_device-1:0/sas_address" printf '0\n' > "$R/class/sas_device/end_device-1:0/phy_identifier" printf 'end device\n' > "$R/class/sas_device/end_device-1:0/device_type" printf '0x5000c5001234abce\n' > "$R/class/sas_device/end_device-1:1/sas_address" printf '1\n' > "$R/class/sas_device/end_device-1:1/phy_identifier" printf 'end device\n' > "$R/class/sas_device/end_device-1:1/device_type" printf '0\n' > "$R/class/sas_end_device/end_device-1:0/initiator_response_timeout" printf '2000\n' > "$R/class/sas_end_device/end_device-1:0/I_T_nexus_loss_timeout" printf '0\n' > "$R/class/sas_end_device/end_device-1:1/initiator_response_timeout" printf '2000\n' > "$R/class/sas_end_device/end_device-1:1/I_T_nexus_loss_timeout" printf '0x5000c50012345678\n' > "$R/class/sas_phy/phy-1:0/sas_address" printf '0\n' > "$R/class/sas_phy/phy-1:0/phy_identifier" printf '12.0 Gbit\n' > "$R/class/sas_phy/phy-1:0/negotiated_linkrate" printf '0x5000c50012345678\n' > "$R/class/sas_phy/phy-1:1/sas_address" printf '1\n' > "$R/class/sas_phy/phy-1:1/phy_identifier" printf '12.0 Gbit\n' > "$R/class/sas_phy/phy-1:1/negotiated_linkrate" mkdir -p "$R/class/fc_host/host2" "$R/class/fc_remote_ports/rport-2:0-0" \ "$R/class/fc_transport/target2:0:0" printf '0x21000024ff123456\n' > "$R/class/fc_host/host2/port_name" printf '0x20000024ff123456\n' > "$R/class/fc_host/host2/node_name" printf '0x010200\n' > "$R/class/fc_host/host2/port_id" printf 'Online\n' > "$R/class/fc_host/host2/port_state" printf '8 Gbit\n' > "$R/class/fc_host/host2/speed" printf '0x50060160c1e0abcd\n' > "$R/class/fc_remote_ports/rport-2:0-0/port_name" printf '0x50060160c1e0abce\n' > "$R/class/fc_remote_ports/rport-2:0-0/node_name" printf '0x010300\n' > "$R/class/fc_remote_ports/rport-2:0-0/port_id" printf 'FCP Target\n' > "$R/class/fc_remote_ports/rport-2:0-0/roles" printf '0x50060160c1e0abcd\n' > "$R/class/fc_transport/target2:0:0/port_name" printf '0x50060160c1e0abce\n' > "$R/class/fc_transport/target2:0:0/node_name" printf '0x010300\n' > "$R/class/fc_transport/target2:0:0/port_id" # The device-level iSCSI probe walks class/iscsi_host/hostN/device looking for # the session that carries this LU's target, so the host has to reach it. mkdir -p "$R/class/iscsi_host/host3/device/session3/target3:0:0" \ "$R/class/iscsi_session/session3" printf '52:54:00:12:34:56\n' > "$R/class/iscsi_host/host3/hwaddress" printf '10.0.2.15\n' > "$R/class/iscsi_host/host3/ipaddress" printf 'iqn.2026-08.com.emcraft:brintos\n' > "$R/class/iscsi_host/host3/initiatorname" printf 'iqn.2026-08.com.emcraft:target0\n' > "$R/class/iscsi_session/session3/targetname" printf '1\n' > "$R/class/iscsi_session/session3/tpgt" ln -sfn ../../../iscsi_session/session3 "$R/class/iscsi_host/host3/device/session3/iscsi_session"