mirror of
https://github.com/akuker/RASCSI.git
synced 2026-04-26 06:18:10 +00:00
WIPMacPlus
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user