Files
RASCSI/cpp/test/scsi_host_bridge_test.cpp
T
Daniel Markstedt 485298ffe5 restore X68000 Host Bridge support
Restore the SCBR device as an X68000 Host Bridge, including the Human68k-compatible host file-system service and the bridge-specific SCSI message handlers. Back its Ethernet path with the TAP driver, derive a stable locally administered MAC address, preserve the driver minimum-frame/FCS expectations, and restrict received traffic to its own unicast frames and broadcasts.

Match the RASCTL/RASETHER/RASDRV bridge protocol that originated in the parent RaSCSI project: dispatch its non-standard message format on READ(10)/WRITE(10) (0x28/0x2a), with type, function, phase, and a three-byte byte count carried in the CDB. Advertise the legacy control channel required by RASCTL, translate its list and device-management commands to PiSCSI operations, and defer stop or system-shutdown requests until after the response is sent, while gating this insecure interface behind a new '-c disabled|media|full' runtime option. Preserve the type-1 Ethernet exchange used by RASETHER and the type-2, phased filesystem exchange used by RASDRV.

Register the device in the factory, protobuf API, controller transfer path, command-line tooling, device listings, and web UI. Share the explicit bridge and proxy-ARP topology workflow with DaynaPort so both adapters validate and use the same mode/interface pair.

Add build support for iconv where needed, extend unit coverage for device creation, RAS* protocol handling, CLI parsing, web attachment, and topology selection, and update the man pages and network-profile documentation for Host Bridge operation and its networking limits.
2026-09-01 00:52:00 +02:00

63 lines
2.4 KiB
C++

//---------------------------------------------------------------------------
//
// SCSI Target Emulator PiSCSI
//---------------------------------------------------------------------------
#include "devices/scsi_host_bridge.h"
#include "mocks.h"
TEST(ScsiHostBridgeTest, GetDefaultParams)
{
const auto [controller, bridge] = CreateDevice(SCBR);
const auto params = bridge->GetDefaultParams();
EXPECT_EQ(2, params.size());
}
TEST(ScsiHostBridgeTest, DeriveMac)
{
const array<uint8_t, 6> uplink_mac = { 0xb8, 0x27, 0xeb, 0xb5, 0xa3, 0x15 };
const auto mac = SCSIBR::DeriveMac(uplink_mac);
EXPECT_EQ(0x02, mac[0]);
EXPECT_NE(uplink_mac, mac);
EXPECT_EQ(mac, SCSIBR::DeriveMac(uplink_mac));
const array<uint8_t, 5> invalid_mac = { 0, 1, 2, 3, 4 };
EXPECT_EQ((array<uint8_t, 6> {}), SCSIBR::DeriveMac(invalid_mac));
}
TEST(ScsiHostBridgeTest, InquiryDisablesRasctlControlByDefault)
{
const auto [controller, bridge] = CreateDevice(SCBR);
const auto inquiry = std::dynamic_pointer_cast<SCSIBR>(bridge)->InquiryInternal();
EXPECT_EQ(0, inquiry[36]);
EXPECT_EQ('1', inquiry[38]);
}
TEST(ScsiHostBridgeTest, RasctlControlUsesRasctlMessageFormat)
{
const auto [controller, device] = CreateDevice(SCBR);
const auto bridge = std::dynamic_pointer_cast<SCSIBR>(device);
const array<int, 10> write_cdb = { 0x2a, 0, 0, 0, 0, 0, 0, 4, 0, 0 };
const array<int, 10> read_cdb = { 0x28, 0, 0, 0, 0, 0, 0, 4, 0, 0 };
vector<uint8_t> buffer(1024);
EXPECT_FALSE(bridge->ReadWrite(write_cdb, buffer));
EXPECT_EQ(0, bridge->GetMessage10(read_cdb, buffer));
bridge->SetRasctlControlMode(SCSIBR::rasctl_control_mode::media);
EXPECT_EQ('1', bridge->InquiryInternal()[36]);
memcpy(buffer.data(), "list\n", 5);
EXPECT_TRUE(bridge->ReadWrite(write_cdb, buffer));
const auto command = bridge->TakeRasctlControlRequest();
ASSERT_TRUE(command.has_value());
EXPECT_EQ("list\n", *command);
bridge->SetRasctlControlResponse("No devices currently attached.\n");
buffer.assign(buffer.size(), 0xff);
EXPECT_EQ(1024, bridge->GetMessage10(read_cdb, buffer));
EXPECT_STREQ("No devices currently attached.\n", reinterpret_cast<const char *>(buffer.data()));
bridge->SetRasctlControlResponse("PiSCSI shutdown requested\n", SCSIBR::rasctl_shutdown_mode::stop_piscsi);
EXPECT_EQ(1024, bridge->GetMessage10(read_cdb, buffer));
EXPECT_EQ(SCSIBR::rasctl_shutdown_mode::stop_piscsi, bridge->TakeRasctlShutdownMode());
}