From 398c54ee3fb63ed8c98af0b2ec5ecc5534750fa4 Mon Sep 17 00:00:00 2001 From: Josh Dersch Date: Fri, 17 May 2019 00:47:11 +0200 Subject: [PATCH] Fixed Unit and Controller ID fields (word order was scrambled) and removed hacked-in constant values for same. Made RCT table size dynamic based on the drive type. The above allow RSTS/E to boot! Huzzah! --- 10.02_devices/2_src/mscp_drive.cpp | 39 ++++++++------- 10.02_devices/2_src/mscp_drive.hpp | 60 +++++++++++++---------- 10.02_devices/2_src/mscp_server.cpp | 74 +++++++++++++++++++---------- 10.02_devices/2_src/uda.cpp | 12 +++-- 10.02_devices/2_src/uda.hpp | 3 +- 5 files changed, 117 insertions(+), 71 deletions(-) diff --git a/10.02_devices/2_src/mscp_drive.cpp b/10.02_devices/2_src/mscp_drive.cpp index d66a41c..9bb257b 100644 --- a/10.02_devices/2_src/mscp_drive.cpp +++ b/10.02_devices/2_src/mscp_drive.cpp @@ -23,12 +23,7 @@ mscp_drive_c::mscp_drive_c( SetOffline(); // Calculate the unit's ID: - // drive number in upper 32 bits, class/model in lower. - _unitID = (static_cast(driveNumber + 1) << 32) | 0xffffffff; - - // Initialize the RCT area - _rctData.reset(new uint8_t[GetBlockSize()]); - memset(reinterpret_cast(_rctData.get()), 0, GetBlockSize()); + _unitIDDeviceNumber = driveNumber + 1; } mscp_drive_c::~mscp_drive_c() @@ -65,12 +60,7 @@ uint32_t mscp_drive_c::GetBlockCount() uint32_t mscp_drive_c::GetRCTBlockCount() { - // - // We provide only a single RCT block. Per the latest MSCP spec no RCT is required, - // however several operating systems appear to expect at least one block be present - // for volume write-protect flags. - // - return 1; + return _driveInfo.RCTSize * GetRCTCopies(); } uint32_t mscp_drive_c::GetMediaID() @@ -78,14 +68,19 @@ uint32_t mscp_drive_c::GetMediaID() return _driveInfo.MediaID; } -uint64_t mscp_drive_c::GetUnitID() +uint32_t mscp_drive_c::GetUnitIDDeviceNumber() { - return _unitID; + return _unitIDDeviceNumber; +} + +uint16_t mscp_drive_c::GetUnitIDClassModel() +{ + return _unitIDClassModel; } uint16_t mscp_drive_c::GetRCTSize() { - return 1; + return _driveInfo.RCTSize; } uint8_t mscp_drive_c::GetRBNs() @@ -207,6 +202,17 @@ void mscp_drive_c::UpdateCapacity() GetBlockCount() * GetBlockSize(); } +void mscp_drive_c::UpdateMetadata() +{ + _unitIDClassModel = 0x0200 | _driveInfo.Model; + + // Initialize the RCT area + size_t rctSize = _driveInfo.RCTSize * GetBlockSize(); + _rctData.reset(new uint8_t[rctSize]); + assert(_rctData != nullptr); + memset(reinterpret_cast(_rctData.get()), 0, rctSize); +} + bool mscp_drive_c::on_param_changed( parameter_c *param) { @@ -253,7 +259,8 @@ bool mscp_drive_c::SetDriveType(const char* typeName) { _driveInfo = g_driveTable[index]; type_name.value = _driveInfo.TypeName; - UpdateCapacity(); + UpdateCapacity(); + UpdateMetadata(); return true; } diff --git a/10.02_devices/2_src/mscp_drive.hpp b/10.02_devices/2_src/mscp_drive.hpp index 32fca80..a54cc24 100644 --- a/10.02_devices/2_src/mscp_drive.hpp +++ b/10.02_devices/2_src/mscp_drive.hpp @@ -22,7 +22,8 @@ public: uint32_t GetBlockCount(void); uint32_t GetRCTBlockCount(void); uint32_t GetMediaID(void); - uint64_t GetUnitID(void); + uint32_t GetUnitIDDeviceNumber(void); + uint16_t GetUnitIDClassModel(void); uint16_t GetRCTSize(void); uint8_t GetRBNs(void); uint8_t GetRCTCopies(void); @@ -66,41 +67,50 @@ private: char TypeName[16]; size_t BlockCount; uint32_t MediaID; + uint8_t Model; + uint16_t RCTSize; bool Removable; bool ReadOnly; }; - DriveInfo g_driveTable[22] + // + // TODO: add a lot more drive types. + // Does it make sense to support drive types not native to Unibus machines (SCSI types, for example?) + // Need to add a ClassID table entry in that eventuality... + // Also TODO: RCTSize parameters taken from SIMH rq source; how valid are these? + DriveInfo g_driveTable[21] { - { "RX50", 800, 0x25658032, true, false }, - { "RX33", 2400, 0x25658021, true, false }, - { "RD51", 21600, 0x25644033, false, false }, - { "RD31", 41560, 0x2564401f, false, false }, - { "RC25", 50902, 0x20643019, true, false }, - { "RC25F", 50902, 0x20643319, true, false }, - { "RD52", 60480, 0x25644034, false, false }, - { "RD32", 83236, 0x25641047, false, false }, - { "RD53", 138672, 0x25644035, false, false }, - { "RA80", 237212, 0x20643019, false, false }, - { "RD54", 311200, 0x25644036, false, false }, - { "RA60", 400176, 0x22a4103c, true, false }, - { "RA70", 547041, 0x20643019, false, false }, - { "RA81", 891072, 0x25641051, false, false }, - { "RA82", 1216665, 0x25641052, false, false }, - { "RA71", 1367310, 0x25641047, false, false }, - { "RRD40", 1331200, 0x25652228, true, true }, - { "RA72", 1953300, 0x25641048, false, false }, - { "RA90", 2376153, 0x2564105a, false, false }, - { "RA92", 2940951, 0x2564105c, false, false }, - { "RA73", 3920490, 0x25641049, false, false }, - { "", 0, 0, false, false } +// Name Blocks MediaID Model RCTSize Removable ReadOnly + { "RX50", 800, 0x25658032, 7, 0, true, false }, + { "RX33", 2400, 0x25658021, 10, 0, true, false }, + { "RD51", 21600, 0x25644033, 6, 36, false, false }, + { "RD31", 41560, 0x2564401f, 12, 3, false, false }, + { "RC25", 50902, 0x20643019, 2, 0, true, false }, + { "RC25F", 50902, 0x20643319, 3, 0, true, false }, + { "RD52", 60480, 0x25644034, 8, 4, false, false }, + { "RD32", 83236, 0x25641047, 15, 4, false, false }, + { "RD53", 138672, 0x25644035, 9, 5, false, false }, + { "RA80", 237212, 0x20643019, 1, 0, false, false }, + { "RD54", 311200, 0x25644036, 13, 7, false, false }, + { "RA60", 400176, 0x22a4103c, 4, 1008, true, false }, + { "RA70", 547041, 0x20643019, 18, 198, false, false }, + { "RA81", 891072, 0x25641051, 5, 2856, false, false }, + { "RA82", 1216665, 0x25641052, 11, 3420, false, false }, + { "RA71", 1367310, 0x25641047, 40, 1428, false, false }, + { "RA72", 1953300, 0x25641048, 37, 2040, false, false }, + { "RA90", 2376153, 0x2564105a, 19, 1794, false, false }, + { "RA92", 2940951, 0x2564105c, 29, 949, false, false }, + { "RA73", 3920490, 0x25641049, 47, 198, false, false }, + { "", 0, 0, 0, 0, false, false } }; bool SetDriveType(const char* typeName); void UpdateCapacity(void); + void UpdateMetadata(void); DriveInfo _driveInfo; bool _online; - uint64_t _unitID; + uint32_t _unitIDDeviceNumber; + uint16_t _unitIDClassModel; bool _useImageSize; // diff --git a/10.02_devices/2_src/mscp_server.cpp b/10.02_devices/2_src/mscp_server.cpp index 88f1d8b..052fca4 100644 --- a/10.02_devices/2_src/mscp_server.cpp +++ b/10.02_devices/2_src/mscp_server.cpp @@ -195,7 +195,7 @@ mscp_server::Poll(void) ControlMessageHeader* header = reinterpret_cast(message->Message); - INFO ("Message size 0x%x opcode 0x%x rsvd 0x%x mod 0x%x unit %d, ursvd 0x%x, ref 0x%x", + DEBUG("Message size 0x%x opcode 0x%x rsvd 0x%x mod 0x%x unit %d, ursvd 0x%x, ref 0x%x", message->MessageLength, header->Word3.Command.Opcode, header->Word3.Command.Reserved, @@ -270,7 +270,7 @@ mscp_server::Poll(void) break; } - INFO ("cmd 0x%x st 0x%x fl 0x%x", cmdStatus, GET_STATUS(cmdStatus), GET_FLAGS(cmdStatus)); + DEBUG("cmd 0x%x st 0x%x fl 0x%x", cmdStatus, GET_STATUS(cmdStatus), GET_FLAGS(cmdStatus)); // // Set the endcode and status bits @@ -491,7 +491,9 @@ mscp_server::GetUnitStatus( uint16_t MultiUnitCode; uint16_t UnitFlags; uint32_t Reserved0; - uint64_t UnitIdentifier; + uint32_t UnitIdDeviceNumber; + uint16_t UnitIdUnused; + uint16_t UnitIdClassModel; uint32_t MediaTypeIdentifier; uint16_t ShadowUnit; uint16_t Reserved1; @@ -505,7 +507,7 @@ mscp_server::GetUnitStatus( }; #pragma pack(pop) - INFO ("MSCP GET UNIT STATUS drive %d", unitNumber); + DEBUG("MSCP GET UNIT STATUS drive %d", unitNumber); // Adjust message length for response message->MessageLength = sizeof(GetUnitStatusResponseParameters) + @@ -534,29 +536,24 @@ mscp_server::GetUnitStatus( reinterpret_cast( GetParameterPointer(message)); - if (nullptr == drive) + if (nullptr == drive || !drive->IsAvailable()) { - // No such drive - params->UnitIdentifier = 0; + // No such drive or drive image not loaded. + params->UnitIdDeviceNumber = 0; + params->UnitIdClassModel = 0; + params->UnitIdUnused = 0; params->ShadowUnit = 0; return STATUS(Status::UNIT_OFFLINE, UnitOfflineSubcodes::UNIT_UNKNOWN, 0); } - if(!drive->IsAvailable()) - { - // Known drive, but not available at this time. - params->UnitIdentifier = 0; - params->ShadowUnit = 0; - - return STATUS(Status::UNIT_OFFLINE, UnitOfflineSubcodes::NO_VOLUME, 0); // offline; no volume available - } - params->Reserved0 = 0; params->Reserved1 = 0; params->Reserved2 = 0; params->UnitFlags = 0; // TODO: 0 for now, which is sane. params->MultiUnitCode = 0; // Controller dependent, we don't support multi-unit drives. - params->UnitIdentifier = drive->GetUnitID(); + params->UnitIdDeviceNumber = drive->GetUnitIDDeviceNumber(); + params->UnitIdClassModel = drive->GetUnitIDClassModel(); + params->UnitIdUnused = 0; params->MediaTypeIdentifier = drive->GetMediaID(); params->ShadowUnit = unitNumber; // Always equal to unit number @@ -631,7 +628,9 @@ mscp_server::Online( uint16_t UnitFlags; uint16_t MultiUnitCode; uint32_t Reserved0; - uint64_t UnitIdentifier; + uint32_t UnitIdDeviceNumber; + uint16_t UnitIdUnused; + uint16_t UnitIdClassModel; uint32_t MediaTypeIdentifier; uint32_t Reserved1; uint32_t UnitSize; @@ -663,7 +662,9 @@ mscp_server::Online( params->UnitFlags = 0; // TODO: 0 for now, which is sane. params->MultiUnitCode = 0; // Controller dependent, we don't support multi-unit drives. - params->UnitIdentifier = drive->GetUnitID(); + params->UnitIdDeviceNumber = drive->GetUnitIDDeviceNumber(); + params->UnitIdClassModel = drive->GetUnitIDClassModel(); + params->UnitIdUnused = 0; params->MediaTypeIdentifier = drive->GetMediaID(); params->UnitSize = drive->GetBlockCount(); params->VolumeSerialNumber = 1; // We report no serial @@ -710,7 +711,16 @@ mscp_server::SetControllerCharacteristics( uint16_t ControllerFlags; uint16_t HostTimeout; uint16_t Reserved; - uint64_t TimeAndDate; + union + { + uint64_t TimeAndDate; + struct + { + uint32_t UniqueDeviceNumber; + uint16_t Unused; + uint16_t ClassModel; + } ControllerId; + } w; }; #pragma pack(pop) @@ -743,8 +753,10 @@ mscp_server::SetControllerCharacteristics( params->ControllerFlags = _controllerFlags & 0xfe; // Mask off 576 byte sectors bit. // it's read-only and we're a 512 // byte sector shop here. - params->HostTimeout = 0x10; // Controller timeout: return the max value. - params->TimeAndDate = _port->GetControllerIdentifier(); // Controller ID + params->HostTimeout = 0xff; // Controller timeout: return the max value. + params->w.ControllerId.UniqueDeviceNumber = _port->GetControllerIdentifier(); + params->w.ControllerId.ClassModel = _port->GetControllerClassModel(); + params->w.ControllerId.Unused = 0; return STATUS(Status::SUCCESS, 0, 0); } @@ -781,7 +793,9 @@ mscp_server::SetUnitCharacteristics( uint16_t UnitFlags; uint16_t MultiUnitCode; uint32_t Reserved0; - uint64_t UnitIdentifier; + uint32_t UnitIdDeviceNumber; + uint16_t UnitIdUnused; + uint16_t UnitIdClassModel; uint32_t MediaTypeIdentifier; uint32_t Reserved1; uint16_t ShadowUnit; @@ -808,7 +822,9 @@ mscp_server::SetUnitCharacteristics( params->UnitFlags = 0; // TODO: 0 for now, which is sane. params->MultiUnitCode = 0; // Controller dependent, we don't support multi-unit drives. - params->UnitIdentifier = drive->GetUnitID(); + params->UnitIdDeviceNumber = drive->GetUnitIDDeviceNumber(); + params->UnitIdClassModel = drive->GetUnitIDClassModel(); + params->UnitIdUnused = 0; params->MediaTypeIdentifier = drive->GetMediaID(); params->UnitSize = drive->GetBlockCount(); params->VolumeSerialNumber = 0; // We report no serial @@ -864,7 +880,7 @@ mscp_server::DoDiskTransfer( ReadWriteEraseParameters* params = reinterpret_cast(GetParameterPointer(message)); - INFO ("MSCP RWE 0x%x unit %d mod 0x%x chan o%o pa o%o count %d lbn %d", + DEBUG("MSCP RWE 0x%x unit %d mod 0x%x chan o%o pa o%o count %d lbn %d", operation, unitNumber, modifiers, @@ -886,6 +902,11 @@ mscp_server::DoDiskTransfer( return STATUS(Status::UNIT_OFFLINE, UnitOfflineSubcodes::UNIT_UNKNOWN, 0); } + if (!drive->IsOnline()) + { + return STATUS(Status::UNIT_AVAILABLE, 0, 0); + } + // Are we accessing the RCT area? bool rctAccess = params->LBN >= drive->GetBlockCount(); uint32_t rctBlockNumber = params->LBN - drive->GetBlockCount(); @@ -967,7 +988,7 @@ mscp_server::DoDiskTransfer( case Opcodes::READ: { unique_ptr diskBuffer; - + if (rctAccess) { diskBuffer.reset(drive->ReadRCTBlock(rctBlockNumber)); @@ -981,6 +1002,7 @@ mscp_server::DoDiskTransfer( params->BufferPhysicalAddress & 0x00ffffff, params->ByteCount, diskBuffer.get()); + } break; diff --git a/10.02_devices/2_src/uda.cpp b/10.02_devices/2_src/uda.cpp index 7e7b9dc..d05ed60 100644 --- a/10.02_devices/2_src/uda.cpp +++ b/10.02_devices/2_src/uda.cpp @@ -715,12 +715,18 @@ uda_c::PostResponse( return res; } -uint64_t +uint32_t uda_c::GetControllerIdentifier() { // TODO: make this not hardcoded - // ID 0x1234568, device class 1 (mass storage), model 2 (UDA50) - return 0x1234567801020000; + // ID 0x12345678 + return 0x12345678; +} + +uint16_t +uda_c::GetControllerClassModel() +{ + return 0x0102; // Class 1 (mass storage), model 2 (UDA50) } void diff --git a/10.02_devices/2_src/uda.hpp b/10.02_devices/2_src/uda.hpp index f33ff83..71fbfff 100644 --- a/10.02_devices/2_src/uda.hpp +++ b/10.02_devices/2_src/uda.hpp @@ -68,7 +68,8 @@ public: // Returns FALSE if the ring is full. bool PostResponse(Message* response); - uint64_t GetControllerIdentifier(void); + uint32_t GetControllerIdentifier(void); + uint16_t GetControllerClassModel(void); uint32_t GetDriveCount(void); mscp_drive_c* GetDrive(uint32_t driveNumber);