#include "ui.h" #include "iop_bmx.h" #include "cray_mainframe.h" #include #include ////////////////////////////////////////////////////////////////////////////////////////// // IopChannelBmx_c ////////////////////////////////////////////////////////////////////////////////////////// void IopChannelBmx_c::Setup(const Configuration_c &aConfig) { mDevices.clear(); mDelayLimit = aConfig.get("DelayLimit", 10); size_t DeviceCount = aConfig.get("DeviceCount", 255); mDevices.resize(DeviceCount); for(const auto &DeviceConfig: aConfig.get_child_safe("Devices")) { std::string DeviceType = DeviceConfig.first; std::shared_ptr Device; const Configuration_c &DeviceParams = DeviceConfig.second; // Create device if (DeviceType == "Tape") { // Create a tape device Device = std::make_shared(DeviceParams, *this); } else { throw InvalidParameter_x(boost::format("Unknown device type: %1%") % DeviceType); } // Add device to all channels (these are smart pointers, so adding a device multiple times is OK) uint8_t DeviceAddress = Device->GetDeviceAddress(); if (mDevices[DeviceAddress].Device != nullptr) { throw InvalidParameter_x(boost::format("expander channel index %1% is already in use") % DeviceAddress); } if (DeviceAddress >= mDevices.size()) { throw InvalidParameter_x(boost::format("expander channel index %1% is too large") % DeviceAddress); } mDevices[DeviceAddress].Device = Device; if (Device->NeedsTick()) { mTickedDevices.emplace_back(Device.get()); } } } IopInt_t IopChannelBmx_c::DoIo(IopIoFunction_t aFunction, IopInt_t aData) { uint16_t RetVal; switch (aFunction) { case 000: mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " CLEAR_CHANNEL_BUSY/DONE with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; mBusy = false; mDone = false; mInterruptEnabled = false; //TODO: this should disable DMAs too, but there's no function to enabled it again?!!! return 0; case 001: switch (aData & 0x3) { case 0: // Clear output tag lines mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " CLEAR_OUTPUT_TAG_LINES with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; mDone = true; mBusy = false; break; case 1: // Interface disconnect mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " INTERFACE_DISCONNECT with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; CRAY_ASSERT(GetActiveDevice() != nullptr); if (GetActiveDevice()->InterfaceDisconnect()) { // Successfull disconnect mDone = true; mBusy = false; } else { // Error in disconnect mDone = true; mBusy = true; } break; case 2: // Selective reset mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " SELECTIVE_RESET with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; if (GetActiveDevice() != nullptr) GetActiveDevice()->Reset(); mDone = true; mBusy = false; break; case 3: // System reset mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " SYSTEM_RESET with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; for(auto &Device: mDevices) if (Device.Device != nullptr) Device.Device->Reset(); mDone = true; mBusy = false; break; } return 0; case 002: { // CHANNEL COMMAND mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " CHANNEL_COMMAND with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; uint8_t Command = aData & 0xff; mLogger << setloglevel(LogLevel_IoActivity) << "Command: " << HexPrinter(Command) << std::endl; // This operation is a BMX-initiated transfer CRAY_ASSERT(GetActiveDevice() != nullptr); IopBmxDevice_i &ActiveDevice = *GetActiveDevice(); // Test I/O if (Command == 0) { mDeviceStatus = ActiveDevice.TestIo(Command); } else { std::vector Data; size_t BytesTransferred = 0; size_t MaxSize = mByteCounter; IopInt_t ByteCounter = mByteCounter; IopInt_t LocalMemoryAdddress = mLocalMemoryAdddress[mActiveMemoryAddressIdx]; LogLine_c TraceLine = mLogger << setloglevel(LogLevel_IoTrace); switch (Command & 0xf) { case 0x1: // Write case 0x5: // Write case 0x9: // Write case 0xd: // Write case 0x3: // Control case 0x7: // Control case 0xb: // Control case 0xf: // Control while (ByteCounter != 0) { for(size_t Parcel=0;Parcel<4;++Parcel) { IopInt_t Word = mParent.GetDma().ReadWord((LocalMemoryAdddress & 0xfffc) | Parcel); Data.push_back(Word >> 8); --ByteCounter; if (ByteCounter == 0) break; Data.push_back(Word & 0xff); --ByteCounter; if (ByteCounter == 0) break; } LocalMemoryAdddress += 4; } switch (Command & 0x3) { case 0x1: mDeviceStatus = ActiveDevice.Write(Command,Data,BytesTransferred); break; case 0x3: mDeviceStatus = ActiveDevice.Control(Command,Data,BytesTransferred); break; default: CRAY_ASSERT(false); break; } CRAY_ASSERT(BytesTransferred <= mByteCounter); mLocalMemoryAdddress[mActiveMemoryAddressIdx] += IopInt_t(BytesTransferred / 8); mByteCounter -= IopInt_t(BytesTransferred); break; case 0x2: // Read case 0x6: // Read case 0xa: // Read case 0xe: // Read case 0x4: // Sense case 0xc: // Read backward switch (Command & 0xf) { case 0x2: case 0x6: case 0xa: case 0xe: mDeviceStatus = ActiveDevice.Read(Command,Data,MaxSize); break; case 0x4: mDeviceStatus = ActiveDevice.Sense(Command,Data,MaxSize); break; case 0xc: mDeviceStatus = ActiveDevice.ReadBackward(Command,Data,MaxSize); break; default: CRAY_ASSERT(false); break; } mLogger << setloglevel(LogLevel_IoActivity) << "received " << DecPrinter(Data.size()) << " bytes of data with command: " << HexPrinter(Command) << " to address: " << HexPrinter(mLocalMemoryAdddress[mActiveMemoryAddressIdx]) << std::endl; size_t i; for(i=0; iGetRequestIn()) { mActiveDevice = Device.Device->GetDeviceAddress(); mDeviceStatus = Device.Device->GetStatus(); HaveInterrupt = true; break; } } if (HaveInterrupt) { mDone = true; mBusy = false; } else { mDone = true; mBusy = true; } } return 0; case 004: // ASYNCHRONOUS I/O mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " ASYNC_IO with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; CRAY_ASSERT(false); //GetActiveDevice().GetData(mStackStatusFlag); mDone = true; mBusy = false; return 0; case 005: // DELAY COUNTER DIAGNOSTICS mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " DELAY_COUNTER_DIAG with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; mLogger << setloglevel(LogLevel_IoActivity) << "Starting delay counter: " << DecPrinter(mDelayLimit) << std::endl; mDelayCounter = mDelayLimit; mDone = false; mBusy = true; return 0; case 006: mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " INTERRUPT_DISABLE with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; mInterruptEnabled = false; return 0; case 007: mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " INTERRUPT_ENABLE with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; mInterruptEnabled = true; return 0; case 010: // READ LOCAL MEMORY ADDRESS mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " READ_LOCAL_MEM_ADDRESS with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; RetVal = (mLocalMemoryAdddress[aData & 1] & 0xfffe) | (aData & 1); mChainingInterruptActive = false; mLogger << setloglevel(LogLevel_IoActivity) << "\treturning: " << HexPrinter(RetVal) << " (" << DecPrinter(RetVal) << ")" << std::endl; return RetVal; case 011: // READ BYTE COUNTER mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " READ_BYTE_COUNTER with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; if (mByteCountStatusRegValid) { mByteCountStatusRegValid = false; RetVal = mByteCountStatusReg; } else { RetVal = mByteCounter; } mLogger << setloglevel(LogLevel_IoActivity) << "\treturning: " << HexPrinter(RetVal) << " (" << DecPrinter(RetVal) << ")" << std::endl; return RetVal; case 012: // READ STATUS/ADDRESS mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " READ_STATUS/ADDRESS with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; if (mStatusRegValid) { mStatusRegValid = false; RetVal = mStatusReg; } else { RetVal = mDeviceStatus | (mActiveDevice << 8); } mLogger << setloglevel(LogLevel_IoActivity) << "\treturning: " << HexPrinter(RetVal) << " (" << DecPrinter(RetVal) << ")" << std::endl; return RetVal; case 013: // READ INPUT TAGS mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " READ_INPUT_TAGS with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; RetVal = // TODO: do we have to simulate other bits too? (mByteCounter == 0) ? (1 << 13) : 0 | (mActiveMemoryAddressIdx << 11) | (GetDeviceInterrupt() << 4); mLogger << setloglevel(LogLevel_IoActivity) << "\treturning: " << HexPrinter(RetVal) << " (" << DecPrinter(RetVal) << ")" << std::endl; return RetVal; case 014: // ENTER LOCAL MEMORY ADDRESS mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " ENTER_LOCAL_MEM_ADDRES with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; mLocalMemoryAdddress[aData & 1] = aData & 0xfffe; //CRAY_ASSERT((aData & 2) == 0); // For now, make sure chaining is not enabled mLoadByteCounter = true; return 0; case 015: // ENTER BYTE COUNT mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " ENTER_BYTE_COUNT with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; mByteCountStatusReg = aData; mByteCountStatusRegValid = true; if (mLoadByteCounter) mByteCounter = aData; else mNextByteCounter = aData; mLoadByteCounter = false; return 0; case 016: // ENTER DEVICE ADDRESS/MODE mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " ENTER_DEVICE_ADDRESS/MODE with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; mActiveDevice = (aData & 0xff); mSkipFlag = GetBit((uint32_t)aData,8) != 0; mStackStatusFlag = GetBit((uint32_t)aData,9) != 0; mChainingMode = (ChainingMode_e)GetBits((uint32_t)aData,10,11); mInterruptMode = (InterruptMode_e)GetBits((uint32_t)aData,12,13); //CRAY_ASSERT(mInterruptMode != InterruptMode_StatusIn); mStatusReg = aData; mStatusRegValid = true; return 0; case 017: // ENTER OUTPUT TAGS mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " ENTER_OUTPUT_TAGS with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; //CRAY_ASSERT(false); return 0; default: mLogger << setloglevel(LogLevel_IoActivity) << "Processing function " << OctPrinter(aFunction) << " with active device: " << DecPrinter(mActiveDevice) << " and accumulater: " << HexPrinter(aData) << " (" << DecPrinter(aData) << ")" << std::endl; mLogger << setloglevel(LogLevel_Error) << SideEffectIndent << "ERROR: Invalid function code for channel" << std::endl; return 0; } } IopBit_t IopChannelBmx_c::GetInterrupt() { if (mInterruptEnabled && mDone) { mLogger << setloglevel(LogLevel_IoActivity) << "Sending DONE interrupt" << std::endl; return 1; } return GetDeviceInterrupt(); } // These could be further optimized but not all that interesting at the moment... void IopChannelBmx_c::RequestInChanged(uint8_t aDeviceAddr, bool aValue) { UpdateXxxInCnts(); } void IopChannelBmx_c::StatusInChanged(uint8_t aDeviceAddr, bool aValue) { UpdateXxxInCnts(); } void IopChannelBmx_c::DisconnectInChanged(uint8_t aDeviceAddr, bool aValue) { UpdateXxxInCnts(); } void IopChannelBmx_c::UpdateXxxInCnts() { mRequestInCnt = 0; mStatusInCnt = 0; mDisconnectInCnt = 0; for (auto &Device : mDevices) { if (Device.Device != nullptr) { if (Device.Device->GetRequestIn()) ++mRequestInCnt; if (Device.Device->GetStatusIn()) ++mStatusInCnt; if (Device.Device->GetDisconnectIn()) ++mDisconnectInCnt; } } } IopBit_t IopChannelBmx_c::GetDeviceInterrupt() { if (mInterruptMode == InterruptMode_RequestIn) return mRequestInCnt > 0 ? 1 : 0; if (mInterruptMode == InterruptMode_StatusIn) return mStatusInCnt > 0 ? 1 : 0; if (mInterruptMode == InterruptMode_DisconnectIn) return mDisconnectInCnt > 0 ? 1 : 0; return 0; } std::string IopChannelBmx_c::GetName() const { return mName; } void IopChannelBmx_c::Tick() { for (auto &Device : mTickedDevices) { Device->Tick(); } if (mDelayCounter != 0) { --mDelayCounter; if (mDelayCounter == 0) { mLogger << setloglevel(LogLevel_IoActivity) << "Delay counter expired" << std::endl; mDone = true; mBusy = false; } } } void IopChannelBmx_c::GetStatus(StatusReport_c &aStatus, PeripheralType_e aFilter, bool aLongFormat) const { for (auto &Device : mDevices) { if (Device.Device != nullptr && Device.Device->GetType() == aFilter) { StatusReport_c Status; Device.Device->GetStatus(Status, aFilter, aLongFormat); aStatus.put_child(Device.Device->GetName(), Status); } } } void IopChannelBmx_c::RegisterCommands(CommandHooks_t &aHooks) { for (auto &Device : mDevices) { if (Device.Device != nullptr) { Device.Device->RegisterCommands(aHooks); } } } ////////////////////////////////////////////////////////////////////////////////////////// // IopBmxTape_c ////////////////////////////////////////////////////////////////////////////////////////// // First byte is the channel status byte // Second byte is the unit status byte // Bit Designation // 0 Attention // not used // 1 Status modifier // present with busy to indicate interrupt pending // 2 Control unit end // signals completion (with or without error) of an operation // 3 Busy // busy // 4 Channel end // 5 Device end // 6 Unit check // set if any bytes of the channel status byte is set or bit 7 (below) is set // 7 Unit exception enum BmxStat_e { BmxStat_Attention = 1 << 0, BmxStat_StatusModifier = 1 << 1, BmxStat_ControlUnitEnd = 1 << 2, BmxStat_Busy = 1 << 3, BmxStat_ChannelEnd = 1 << 4, BmxStat_DeviceEnd = 1 << 5, BmxStat_UnitCheck = 1 << 6, BmxStat_UnitException = 1 << 7 }; IopBmxTape_c::IopBmxTape_c(const Configuration_c &aConfig, IopChannelBmx_c &aParent): mParent(aParent), mLogger(aConfig, "BMT",aConfig.get("DeviceAddress")), mDeviceAddress(aConfig.get("DeviceAddress")), mReads(0), mWrites(0), mTapeImage(mLogger, aConfig), mIsReadOnly(aConfig.get("ReadOnly", false)) { boost::optional Name = aConfig.get_optional("DeviceName"); mName = (Name.is_initialized()) ? Name.get() : ModuleNameFormatter("BMT", aConfig.get("DeviceAddress")); mLogger.SetHeader(mName.c_str()); mLogger.SetParent(mParent.GetLogger()); ClearState(); mTapeImage.open(aConfig.get("Tape")); } uint8_t IopBmxTape_c::TestIo(uint8_t aCommand) { return BmxStat_DeviceEnd | BmxStat_ControlUnitEnd; } uint8_t IopBmxTape_c::Write(uint8_t aCommand, std::vector &aData, size_t &aBytesTransferred) { mLogger << setloglevel(LogLevel_IoActivity) << "writing " << DecPrinter(aData.size()) << " bytes of data with command: " << HexPrinter(aCommand) << std::endl; CRAY_ASSERT(!mIsReadOnly); LogLine_c TraceLine = mLogger << setloglevel(LogLevel_IoTrace); size_t i; for(i=0; i &aData, size_t &aBytesTransferred) { mLogger << setloglevel(LogLevel_IoActivity) << "control with " << DecPrinter(aData.size()) << " bytes of data and command: " << HexPrinter(aCommand) << std::endl; LogLine_c TraceLine = mLogger << setloglevel(LogLevel_IoTrace); size_t i; for(i=0; i> 2 ) & 1) { case 0: // mode setting operations mLogger << setloglevel(LogLevel_IoActivity) << "Mode setting" << std::endl; break; break; case 1: // Tape motion operations switch ((aCommand >> 3) & 7) { case 0: mLogger << setloglevel(LogLevel_IoActivity) << "Rewind" << std::endl; mTapeImage.ReOpen(); mTapeImage.SeekToBeginningOfTape(); mTapeImage.close(); break; case 1: mLogger << setloglevel(LogLevel_IoActivity) << "Rewind and Unload" << std::endl; mTapeImage.ReOpen(); mTapeImage.SeekToBeginningOfTape(); mTapeImage.close(); if (mTapeImage.GetState() == TapFile_c::State_e::BeginningOfTape) RetVal |= BmxStat_UnitCheck; break; case 2: mLogger << setloglevel(LogLevel_IoActivity) << "Erase Gap" << std::endl; break; case 3: mLogger << setloglevel(LogLevel_IoActivity) << "Write Tape Mark" << std::endl; CRAY_ASSERT(!mIsReadOnly); mTapeImage.ReOpen(); mTapeImage.WriteEndOfFile(); break; case 4: mLogger << setloglevel(LogLevel_IoActivity) << "Backspace Block" << std::endl; mTapeImage.ReOpen(); mTapeImage.SeekToPrevRecord(); if (mTapeImage.GetState() == TapFile_c::State_e::EndOfFile) RetVal |= BmxStat_UnitException; if (mTapeImage.GetState() == TapFile_c::State_e::BeginningOfTape) RetVal |= BmxStat_UnitCheck; break; case 5: mLogger << setloglevel(LogLevel_IoActivity) << "Backspace File" << std::endl; mTapeImage.ReOpen(); do { mTapeImage.SeekToPrevRecord(); if (mTapeImage.GetState() == TapFile_c::State_e::EndOfTape) { mLogger << setloglevel(LogLevel_IoActivity) << "spacing cut short by EOT condition after " << DecPrinter(i) << " records." << std::endl; break; } } while (mTapeImage.GetState() != TapFile_c::State_e::EndOfFile); if (mTapeImage.GetState() == TapFile_c::State_e::BeginningOfTape) RetVal |= BmxStat_UnitCheck; break; case 6: mLogger << setloglevel(LogLevel_IoActivity) << "Forward Space Block" << std::endl; mTapeImage.ReOpen(); mTapeImage.SeekToNextRecord(); if (mTapeImage.GetState() == TapFile_c::State_e::EndOfFile) RetVal |= BmxStat_UnitException; if (mTapeImage.GetState() == TapFile_c::State_e::EndOfTape) RetVal |= BmxStat_UnitCheck; break; case 7: mLogger << setloglevel(LogLevel_IoActivity) << "Forward Space File" << std::endl; mTapeImage.ReOpen(); do { mTapeImage.SeekToNextRecord(); if (mTapeImage.GetState() == TapFile_c::State_e::EndOfTape) { mLogger << setloglevel(LogLevel_IoActivity) << "spacing cut short by EOT condition after " << DecPrinter(i) << " records." << std::endl; break; } } while (mTapeImage.GetState() != TapFile_c::State_e::EndOfFile); if (mTapeImage.GetState() == TapFile_c::State_e::EndOfTape) RetVal |= BmxStat_UnitCheck; break; default: CRAY_ASSERT(false); break; } break; default: CRAY_ASSERT(false); break; } aBytesTransferred = aData.size(); return RetVal; } uint8_t IopBmxTape_c::Read(uint8_t aCommand, std::vector &aData, size_t aMaxSize) { mLogger << setloglevel(LogLevel_IoActivity) << "read with " << DecPrinter(aMaxSize) << " bytes of buffer and command: " << HexPrinter(aCommand) << std::endl; uint8_t RetVal = BmxStat_ControlUnitEnd; mTapeImage.ReOpen(); aData = mTapeImage.Read(uint32_t(aMaxSize)); mReads += aData.size(); if (mTapeImage.GetState() == TapFile_c::State_e::EndOfFile) RetVal |= BmxStat_UnitException; if (mTapeImage.GetState() == TapFile_c::State_e::EndOfTape) RetVal |= BmxStat_UnitCheck; return RetVal; } uint8_t IopBmxTape_c::Sense(uint8_t aCommand, std::vector &aData, size_t aMaxSize) { mLogger << setloglevel(LogLevel_IoActivity) << "sense with " << DecPrinter(aMaxSize) << " bytes of buffer and command: " << HexPrinter(aCommand) << std::endl; // Sense data is documented in // A22-6866-4_2400_Tape_Unit_2803_2804_Tape_Controls_Component_Description_Sep68.pdf // page 29-32 CRAY_ASSERT(aMaxSize >= 6); aData.resize(6); aData[0] = 0; // TU Status A File Protect aData[1] = (1 << 1) | ((mIsReadOnly ? 1:0) << 6); aData[2] = 0; aData[3] = 0; aData[4] = 0; aData[5] = 0; /* aData[0] = 0x36; // TU Status A File Protect aData[1] = (1 << 1) | (1 << 6); aData[2] = 0x47; aData[3] = 0x58; aData[4] = 0x69; aData[5] = 0x7a;*/ return BmxStat_ControlUnitEnd; } uint8_t IopBmxTape_c::ReadBackward(uint8_t aCommand, std::vector &aData, size_t aMaxSize) { mLogger << setloglevel(LogLevel_IoActivity) << "read backward " << DecPrinter(aMaxSize) << " bytes of buffer and command: " << HexPrinter(aCommand) << " - UNIMPLEMENTED!!!" << std::endl; CRAY_ASSERT(false); // This is not implemented aData.resize(aMaxSize); for(size_t i=0; i(&mTapeImage)->tellg()); else aStatus.put(aLongFormat ? "Position" : "Pos", "-"); aStatus.put(aLongFormat ? "File Name" : "FName", mTapeImage.GetFileName()); } std::string IopBmxTape_c::GetName() const { return mName; } void IopBmxTape_c::MountTape(const std::string &aTapeFileName) { if (mTapeImage.is_open()) throw Generic_x("Can't unmount tape while it's in use."); mTapeImage.open(aTapeFileName); mTapeImage.close(); } void IopBmxTape_c::RegisterCommands(CommandHooks_t &aHooks) { class CmdMount_c : public CmdFactoryBase_i { public: explicit CmdMount_c(IopBmxTape_c &aParent) : mParent(aParent) {} virtual bool ParseAndExec(TokenStream_t::const_iterator aBegin, TokenStream_t::const_iterator aEnd) override { bool DoHelp = false; if (aBegin->mValue == "help") { DoHelp = true; ++aBegin; if (aBegin == aEnd) return false; } if (aBegin->mValue != "mount") return false; ++aBegin; if (aBegin == aEnd) return false; if (aBegin->mValue != mParent.GetName()) return false; if (DoHelp) { std::cout << "mount " << mParent.GetName() << " " << std::endl; std::cout << " Mounts a new virtual tape on the tape drive" << std::endl; return true; } else { ++aBegin; if (aBegin == aEnd) return false; std::string FileName = aBegin->mValue; ++aBegin; if (aBegin != aEnd && aBegin->mTokenId != TokenTypes_e::EndOfLine) return false; // TODO: add warning about existing file try { mParent.MountTape(FileName); std::cout << "New virtual tape " << FileName << " mounted" << std::endl; } catch (std::exception &Ex) { std::cout << "Mount failed" << std::endl; std::cout << Ex.what() << std::endl; } return true; } } virtual std::string GetCommandName() const override { return "mount"; } virtual std::string GetDeviceName() const override { return mParent.GetName(); } protected: IopBmxTape_c &mParent; }; aHooks.emplace_back(std::make_unique(*this)); }