WIPMacPlus

This commit is contained in:
Eric Helgeson
2026-01-12 16:44:54 -06:00
parent cda36815b6
commit 16b5be8724
6 changed files with 89 additions and 3 deletions
+31
View File
@@ -29,11 +29,22 @@
using namespace scsi_defs;
// Static member initialization
CompatibilityMode ScsiController::default_compat_mode = CompatibilityMode::STANDARD;
ScsiController::ScsiController(BUS& bus, int target_id) : AbstractController(bus, target_id, ControllerManager::GetScsiLunMax())
{
// The initial buffer size will default to either the default buffer size OR
// the size of an Ethernet message, whichever is larger.
AllocateBuffer(std::max(DEFAULT_BUFFER_SIZE, ETH_FRAME_LEN + 16 + ETH_FCS_LEN));
// Initialize compatibility mode from static default
compat_mode = default_compat_mode;
// If Mac Plus mode is explicitly enabled, enable SCSI-1 compatibility behaviors
if (compat_mode == CompatibilityMode::MAC_PLUS || compat_mode == CompatibilityMode::SCSI1_COMPAT) {
scsi1_detected = true;
}
}
void ScsiController::Reset()
@@ -126,6 +137,14 @@ void ScsiController::Selection()
if (GetBus().GetATN()) {
MsgOut();
} else {
// No ATN during selection indicates SCSI-1 host (e.g., Mac Plus)
// SCSI-2 hosts assert ATN to send IDENTIFY message
if (!scsi1_detected) {
scsi1_detected = true;
LogInfo("SCSI-1 host detected (no ATN during selection) - enabling compatibility mode");
// Enable Unit Attention suppression on all attached devices
EnableScsi1Compatibility();
}
Command();
}
}
@@ -985,4 +1004,16 @@ void ScsiController::Sleep()
execstart = 0;
}
void ScsiController::EnableScsi1Compatibility()
{
// Enable Unit Attention suppression on all attached devices
// This is critical for Mac Plus which triggers SCSI reset on Unit Attention
for (int lun = 0; lun < GetMaxLuns(); lun++) {
if (auto device = GetDeviceForLun(lun); device != nullptr) {
device->SetSuppressUnitAttention(true);
LogTrace("Enabled Unit Attention suppression for LUN " + to_string(lun));
}
}
}
unsigned int ScsiController::MIN_EXEC_TIME = 50;
+26
View File
@@ -22,6 +22,14 @@ using namespace std;
class PrimaryDevice;
// Mac Plus/SCSI-1 compatibility mode
// Mac Plus and other early SCSI-1 hosts have timing and protocol quirks
enum class CompatibilityMode {
STANDARD, // Standard SCSI-2 operation
MAC_PLUS, // Mac Plus compatibility (SCSI-1 with specific quirks)
SCSI1_COMPAT // Generic SCSI-1 compatibility
};
class ScsiController : public AbstractController
{
// For timing adjustments
@@ -29,6 +37,11 @@ public:
static unsigned int MIN_EXEC_TIME;
static void SetMinExecTime(unsigned int usec) { MIN_EXEC_TIME = usec; }
// Mac Plus/SCSI-1 compatibility mode
static CompatibilityMode default_compat_mode;
static void SetDefaultCompatibilityMode(CompatibilityMode mode) { default_compat_mode = mode; }
static CompatibilityMode GetDefaultCompatibilityMode() { return default_compat_mode; }
// Transfer period factor (limited to 50 x 4 = 200ns)
static const int MAX_SYNC_PERIOD = 50;
@@ -87,6 +100,19 @@ private:
// The LUN from the IDENTIFY message
int identified_lun = -1;
// SCSI-1 host detected (no ATN during selection - e.g., Mac Plus)
bool scsi1_detected = false;
// Instance-level compatibility mode (initialized from static default)
CompatibilityMode compat_mode = CompatibilityMode::STANDARD;
// Enable SCSI-1 compatibility behaviors on all attached devices
void EnableScsi1Compatibility();
// Check if running in Mac Plus or SCSI-1 compatibility mode
bool IsMacPlusMode() const { return compat_mode == CompatibilityMode::MAC_PLUS; }
bool IsScsi1Mode() const { return scsi1_detected || compat_mode != CompatibilityMode::STANDARD; }
// Data transfer
void Send();
bool XferMsg(int);
+8
View File
@@ -51,6 +51,10 @@ class Device //NOSONAR The number of fields and methods is justified, the comple
bool lockable = false;
bool locked = false;
// Mac Plus compatibility: suppress Unit Attention to avoid reset loops
// Mac Plus ROM triggers SCSI reset on Unit Attention, causing infinite boot loop
bool suppress_unit_attention = false;
// A device can be created with parameters
bool supports_params = false;
@@ -120,6 +124,10 @@ public:
bool IsLockable() const { return lockable; }
bool IsLocked() const { return locked; }
// Mac Plus compatibility: Unit Attention suppression
bool GetSuppressUnitAttention() const { return suppress_unit_attention; }
void SetSuppressUnitAttention(bool b) { suppress_unit_attention = b; }
virtual int GetId() const = 0;
int GetLun() const { return lun; }
+11 -2
View File
@@ -186,14 +186,23 @@ void PrimaryDevice::CheckReady()
if (IsReset()) {
SetReset(false);
LogTrace("Device in reset");
throw scsi_exception(sense_key::unit_attention, asc::power_on_or_reset);
// Mac Plus compatibility: suppress Unit Attention to avoid reset loops
// Mac Plus ROM triggers SCSI reset on Unit Attention, causing infinite boot loop
if (!GetSuppressUnitAttention()) {
throw scsi_exception(sense_key::unit_attention, asc::power_on_or_reset);
}
LogTrace("Unit Attention suppressed (SCSI-1/Mac Plus compatibility mode)");
}
// Not ready if it needs attention
if (IsAttn()) {
SetAttn(false);
LogTrace("Device in needs attention");
throw scsi_exception(sense_key::unit_attention, asc::not_ready_to_ready_change);
// Mac Plus compatibility: suppress Unit Attention to avoid reset loops
if (!GetSuppressUnitAttention()) {
throw scsi_exception(sense_key::unit_attention, asc::not_ready_to_ready_change);
}
LogTrace("Unit Attention suppressed (SCSI-1/Mac Plus compatibility mode)");
}
// Return status if not ready
+5
View File
@@ -51,6 +51,11 @@ const static int SCSI_DELAY_FAST_DESKEW_DELAY_NS = 20;
const static int SCSI_DELAY_FAST_HOLD_TIME_NS = 10;
const static int SCSI_DELAY_FAST_NEGATION_PERIOD_NS = 30;
// Mac Plus compatibility: Mac Plus ROM has extremely tight selection timing
// Standard SCSI allows 250ms selection abort time, but Mac Plus expects < 1ms
// This constant is for documentation purposes - actual timing depends on GPIO polling speed
const static int SCSI_DELAY_SELECTION_ABORT_MACPLUS_US = 1000; // 1ms (vs standard 250ms)
// The DaynaPort SCSI Link do a short delay in the middle of transfering
// a packet. This is the number of uS that will be delayed between the
// header and the actual data.
+8 -1
View File
@@ -147,13 +147,20 @@ string Piscsi::ParseArguments(span<char *> args, PbCommand& command, int& port,
opterr = 1;
int opt;
while ((opt = getopt(static_cast<int>(args.size()), args.data(), "-Iib:d:n:p:r:s:t:z:D:F:L:P:R:C:v")) != -1) {
while ((opt = getopt(static_cast<int>(args.size()), args.data(), "-Iib:d:mn:p:r:s:t:z:D:F:L:P:R:C:v")) != -1) {
switch (opt) {
// The two options below are kind of a compound option with two letters
case 'i':
case 'I':
continue;
case 'm':
// Mac Plus compatibility mode - enables SCSI-1 quirk handling
// Mac Plus has tight selection timing and triggers reset loops on Unit Attention
ScsiController::SetDefaultCompatibilityMode(CompatibilityMode::MAC_PLUS);
spdlog::info("Mac Plus compatibility mode enabled");
continue;
case 'd':
case 'D':
id_and_lun = optarg;