1
0
mirror of https://github.com/livingcomputermuseum/UniBone.git synced 2026-01-29 21:21:25 +00:00
Files
livingcomputermuseum.UniBone/10.02_devices/2_src/mscp_server.hpp

212 lines
5.4 KiB
C++

/*
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 <stdint.h>
#include <memory>
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> message, uint16_t unitNumber);
uint32_t Available(uint16_t unitNumber, uint16_t modifiers);
uint32_t CompareHostData(std::shared_ptr<Message> message, uint16_t unitNumber);
uint32_t DetermineAccessPaths(uint16_t unitNumber);
uint32_t Erase(std::shared_ptr<Message> message, uint16_t unitNumber, uint16_t modifiers);
uint32_t GetCommandStatus(std::shared_ptr<Message> message);
uint32_t GetUnitStatus(std::shared_ptr<Message> message, uint16_t unitNumber, uint16_t modifiers);
uint32_t Online(std::shared_ptr<Message> message, uint16_t unitNumber, uint16_t modifiers);
uint32_t SetControllerCharacteristics(std::shared_ptr<Message> message);
uint32_t SetUnitCharacteristics(std::shared_ptr<Message> message, uint16_t unitNumber, uint16_t modifiers);
uint32_t Read(std::shared_ptr<Message> message, uint16_t unitNumber, uint16_t modifiers);
uint32_t Replace(std::shared_ptr<Message> message, uint16_t unitNumber);
uint32_t Write(std::shared_ptr<Message> message, uint16_t unitNumber, uint16_t modifiers);
uint32_t SetUnitCharacteristicsInternal(
std::shared_ptr<Message> message,
uint16_t unitNumber,
uint16_t modifiers,
bool bringOnline);
uint32_t DoDiskTransfer(uint16_t operation, std::shared_ptr<Message> message, uint16_t unitNumber, uint16_t modifiers);
uint8_t* GetParameterPointer(std::shared_ptr<Message> 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;
};