/* mscp_server.hpp: Implementation of a simple MSCP server. Copyright Vulcan Inc. 2019 via Living Computers: Museum + Labs, Seattle, WA. Contributed under the BSD 2-clause license. */ #pragma once #include #include class uda_c; class Message; class mscp_drive_c; // Builds a uint32_t containing the status, flags, and endcode for a response message, // used to simplify returning the appropriate status bits from command functions. #define STATUS(status, modifier, flags) ((flags) << 8) | (((status) | ((modifier) * 0x20)) << 16) #define GET_STATUS(status) (((status) >> 16) & 0xffff) #define GET_FLAGS(status) (((status) >> 8) & 0xff) #define MAX_CREDITS 14 #define INIT_CREDITS 1 // // ControlMessageHeader encapsulates the standard MSCP control // message header: a 12-byte header followed by up to 36 bytes of // parameters. // Note: This struct (and many others like it in this code) assumes // little-endian byte orderings. Probably not a big deal unless this // someday runs on something other than a Beaglebone. // #pragma pack(push,1) struct ControlMessageHeader { uint32_t ReferenceNumber; uint16_t UnitNumber; uint16_t Reserved; union { struct { uint8_t Opcode : 8; uint8_t Reserved : 8; uint16_t Modifiers : 16; } Command; struct { uint8_t Endcode : 8; uint8_t Flags : 8; uint16_t Status : 16; } End; } Word3; // M9312 DU boot loader writes invalid big messages sizes. // Temporary patch: enlarge buffer behind all reasonable limits. // uint8_t Parameters[512]; uint8_t Parameters[10240]; // overkill }; #pragma pack(pop) // Size in bytes of the non-parameter portion of a ControlMessageHeader #define HEADER_SIZE 12 enum Opcodes { ABORT = 0x1, ACCESS = 0x10, AVAILABLE = 0x8, COMPARE_HOST_DATA = 0x20, DETERMINE_ACCESS_PATHS = 0x0b, ERASE = 0x12, GET_COMMAND_STATUS = 0x2, GET_UNIT_STATUS = 0x3, ONLINE = 0x9, READ = 0x21, REPLACE = 0x14, SET_CONTROLLER_CHARACTERISTICS = 0x4, SET_UNIT_CHARACTERISTICS = 0xa, WRITE = 0x22 }; enum Endcodes { END = 0x80, SERIOUS_EXCEPTION = 0x7, }; enum Status { SUCCESS = 0x0, INVALID_COMMAND = 0x1, COMMAND_ABORTED = 0x2, UNIT_OFFLINE = 0x3, UNIT_AVAILABLE = 0x4, MEDIA_FORMAT_ERROR = 0x5, WRITE_PROTECTED = 0x6, COMPARE_ERROR = 0x7, DATA_ERROR = 0x8, HOST_BUFFER_ACCESS_ERROR = 0x9, CONTROLLER_ERROR = 0xa, DRIVE_ERROR = 0xb, DIAGNOSTIC_MESSAGE = 0x1f }; enum SuccessSubcodes { NORMAL = 0x0, SPIN_DOWN_IGNORED = 0x20, STILL_CONNECTED = 0x40, DUPLICATE_UNIT_NUMBER = 0x80, ALREADY_ONLINE = 0x100, STILL_ONLINE = 0x200, }; enum UnitOfflineSubcodes { UNIT_UNKNOWN = 0x0, NO_VOLUME = 0x1, UNIT_INOPERATIVE = 0x2, DUPLICATE_UNIT = 0x4, UNIT_DISABLED = 0x8, EXCLUSIVE = 0x10, }; enum MessageTypes { Sequential = 0, Datagram = 1, CreditNotification = 2, Maintenance = 15, }; // // This inherits from device_c solely so the logging macros work. // class mscp_server : public device_c { public: mscp_server(uda_c *port); ~mscp_server(); bool on_param_changed(parameter_c *param) override ; public: void Reset(void); void InitPolling(void); void Poll(void); public: void on_power_changed(void) override {} void on_init_changed(void) override {} private: uint32_t Abort(void); uint32_t Access(std::shared_ptr message, uint16_t unitNumber); uint32_t Available(uint16_t unitNumber, uint16_t modifiers); uint32_t CompareHostData(std::shared_ptr message, uint16_t unitNumber); uint32_t DetermineAccessPaths(uint16_t unitNumber); uint32_t Erase(std::shared_ptr message, uint16_t unitNumber, uint16_t modifiers); uint32_t GetCommandStatus(std::shared_ptr message); uint32_t GetUnitStatus(std::shared_ptr message, uint16_t unitNumber, uint16_t modifiers); uint32_t Online(std::shared_ptr message, uint16_t unitNumber, uint16_t modifiers); uint32_t SetControllerCharacteristics(std::shared_ptr message); uint32_t SetUnitCharacteristics(std::shared_ptr message, uint16_t unitNumber, uint16_t modifiers); uint32_t Read(std::shared_ptr message, uint16_t unitNumber, uint16_t modifiers); uint32_t Replace(std::shared_ptr message, uint16_t unitNumber); uint32_t Write(std::shared_ptr message, uint16_t unitNumber, uint16_t modifiers); uint32_t SetUnitCharacteristicsInternal( std::shared_ptr message, uint16_t unitNumber, uint16_t modifiers, bool bringOnline); uint32_t DoDiskTransfer(uint16_t operation, std::shared_ptr message, uint16_t unitNumber, uint16_t modifiers); uint8_t* GetParameterPointer(std::shared_ptr message); mscp_drive_c* GetDrive(uint32_t unitNumber); private: void StartPollingThread(void); void AbortPollingThread(void); private: uint32_t _hostTimeout; uint32_t _controllerFlags; private: uda_c* _port; enum PollingState { Wait = 0, Run, InitRestart, InitRun }; bool _abort_polling; PollingState _pollState; pthread_t polling_pthread; pthread_cond_t polling_cond; pthread_mutex_t polling_mutex; // Credits available uint8_t _credits; };