mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-28 05:29:33 +00:00
* Fixed buster compile-time issue
* Host services inherit from ModePageDevice
* Call base class
* Visibility update
* Updated includes
* Updated dispatcher
* Added TODOs
* Logging update
* Code cleanup
* Use namespace instead of class for ScsiDefs
* Renaming
* Cleanup
* Use dispatcher template in order to remove duplicate code
* Updated all dispatchers
* Clean up commands
* Removed duplicate code
* Removed duplicate code
* Updated template definition
* Fixed typo
* Fixed warning
* Code cleanup
* Device list must be static
* Cleanup
* Logging update
* Added comments
* Cleanup
* Base class update
* SCSIBR is not a subclass of Disk anymore, but of PrimaryDevice
* Updated includes
* Fixed compile-time issue on the Pi
* Header file cleanup
* Interface cleanup
* Removed wrong override
* include file cleanup
* Removed obsolete usage of streams
* Removed more stream usages
* Stream usage cleanup
* Include cleanup
* Renaming
* Include cleanup
* Interface update
* SCLP device skeleton
* Initial RELEASE/RESERVE UNIT
* Added full set of commands
* Extracted command phase code
* Stripped SCSI controller code
* Removed unused code
* Commented out code
* Initial naive implementation
* Added debug output
* Disable printing for now
* Updated file handling
* Updated DataOut()
* Added comment
* Updated assertion
* Comment update
* Updated assertion
* Code cleanup
* Reset bytes to transfer
* Reverted change
* Refactoring
* Moved assertion
* Updated ReceiveBytes()
* Removed override
* Added interface
* Code cleanup
* Updated TEST UNIT READY
* Added flag for byte-oriented transfer
* Updated TEST UNIT READY
* Length handling update
* Updated bytecount handling
* Fixed warning
* Added TODO
* Updated assertion
* Enabled priting
* Updated error handling
* Code cleanup
* Logging update
* First working version
* Use temporary file
* Logging update
* Handle parameters
* Updated format string
* Updated logging
* File handling update
* Code cleanup
* Fixed buffer size
* Updated file handling
* Manpage update
* Initial reservation handling
* Updated reservation handling
* Initial reservation testing
* Remember initiator ID
* Extract initiator ID
* Updated SCSI initiator ID handling
* Logging update
* Added reservation timeout
* Updated timeout handling
* Code cleanup
* Only pass initiator ID to *SCSI* controller
* Added comments
* Added comment
* Implemented STOP PRINT
* Comment update
* Comment update
* Comment update
* Added comment
* Comment update
* Removed useless comments
* Updated printer parameter handling
* Updated parameter handling
* Manpage update
* Manpage update
* Comment update
* Default printer product name update
* Renaming
* Updated logging
* Logging update
* Logging update
* Comment update
* Code cleanup
* Added printer shortcut
* Comment update
* Comment update
* Output formatting update
* Updated error handling
* Code cleanup
* More cleanup
* Revert "More cleanup"
This reverts commit 05708986ee
.
* Output formatting update
* Output format update
* Sort parameters
* Comment update
* Improved parsing of parameters
* Manpage update
* Updated SCSI level
* Removed magic constants
* Removed magic constant
* Template update
* Template usage update
* Get rid of SASIDEV for printer
* Get rid of SASIDEV for host services
* Moved initiator_id field
* Moved field
* Moved field
* Added comment
* Error handling must use effective LUN
* Removed obsolete casts
* Removed unused method declarations
* Comment update
* Code cleanup
* More code cleanup
* Optimization
* Removed duplicate code
* Logging update
* Fixed warning
* Code cleanup
* Added TODOs
* TODO update
* Backwards compatibility update
* Comment update
197 lines
4.6 KiB
C++
197 lines
4.6 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// SCSI Target Emulator RaSCSI (*^..^*)
|
|
// for Raspberry Pi
|
|
//
|
|
// Copyright (C) 2022 Uwe Seimet
|
|
//
|
|
// Host Services with realtime clock and shutdown support
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
// Features of the host services device:
|
|
//
|
|
// 1. Vendor-specific mode page 0x20 returns the current date and time (realtime clock)
|
|
//
|
|
// typedef struct {
|
|
// // Major and minor version of this data structure
|
|
// uint8_t major_version;
|
|
// uint8_t minor_version;
|
|
// // Current date and time, with daylight savings time adjustment applied
|
|
// uint8_t year; // year - 1900
|
|
// uint8_t month; // 0-11
|
|
// uint8_t day; // 1-31
|
|
// uint8_t hour; // 0-23
|
|
// uint8_t minute; // 0-59
|
|
// uint8_t second; // 0-59
|
|
// } mode_page_datetime;
|
|
//
|
|
// 2. STOP UNIT shuts down RaSCSI or the Raspberry Pi
|
|
// a) !start && !load (STOP): Shut down RaSCSI
|
|
// b) !start && load (EJECT): Shut down the Raspberry Pi
|
|
//
|
|
|
|
#include "controllers/scsidev_ctrl.h"
|
|
#include "host_services.h"
|
|
|
|
using namespace scsi_defs;
|
|
|
|
HostServices::HostServices() : ModePageDevice("SCHS")
|
|
{
|
|
dispatcher.AddCommand(eCmdTestUnitReady, "TestUnitReady", &HostServices::TestUnitReady);
|
|
dispatcher.AddCommand(eCmdStartStop, "StartStopUnit", &HostServices::StartStopUnit);
|
|
}
|
|
|
|
bool HostServices::Dispatch(SCSIDEV *controller)
|
|
{
|
|
// The superclass class handles the less specific commands
|
|
return dispatcher.Dispatch(this, controller) ? true : super::Dispatch(controller);
|
|
}
|
|
|
|
void HostServices::TestUnitReady(SCSIDEV *controller)
|
|
{
|
|
// Always successful
|
|
controller->Status();
|
|
}
|
|
|
|
int HostServices::Inquiry(const DWORD *cdb, BYTE *buf)
|
|
{
|
|
// Processor device, not removable
|
|
return PrimaryDevice::Inquiry(3, false, cdb, buf);
|
|
}
|
|
|
|
void HostServices::StartStopUnit(SCSIDEV *controller)
|
|
{
|
|
bool start = ctrl->cmd[4] & 0x01;
|
|
bool load = ctrl->cmd[4] & 0x02;
|
|
|
|
if (!start) {
|
|
// Delete all other devices. This will also flush any caches.
|
|
for (const Device *device : devices) {
|
|
if (device != this) {
|
|
delete device;
|
|
}
|
|
}
|
|
|
|
if (load) {
|
|
((SCSIDEV *)controller)->ShutDown(SCSIDEV::rascsi_shutdown_mode::PI);
|
|
}
|
|
else {
|
|
((SCSIDEV *)controller)->ShutDown(SCSIDEV::rascsi_shutdown_mode::RASCSI);
|
|
}
|
|
|
|
controller->Status();
|
|
return;
|
|
}
|
|
|
|
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
|
|
}
|
|
|
|
int HostServices::ModeSense6(const DWORD *cdb, BYTE *buf)
|
|
{
|
|
// Get length, clear buffer
|
|
int length = (int)cdb[4];
|
|
memset(buf, 0, length);
|
|
|
|
// Get page code (0x00 is valid from the beginning)
|
|
int page = cdb[2] & 0x3f;
|
|
bool valid = page == 0x00;
|
|
|
|
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page);
|
|
|
|
// Basic information
|
|
int size = 4;
|
|
|
|
int ret = AddRealtimeClockPage(page, &buf[size]);
|
|
if (ret > 0) {
|
|
size += ret;
|
|
valid = true;
|
|
}
|
|
|
|
if (!valid) {
|
|
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page);
|
|
SetStatusCode(STATUS_INVALIDCDB);
|
|
return 0;
|
|
}
|
|
|
|
// Do not return more than ALLOCATION LENGTH bytes
|
|
if (size > length) {
|
|
LOGTRACE("%s %d bytes available, %d bytes requested", __PRETTY_FUNCTION__, size, length);
|
|
size = length;
|
|
}
|
|
|
|
// Final setting of mode data length
|
|
buf[0] = size;
|
|
|
|
return size;
|
|
}
|
|
|
|
int HostServices::ModeSense10(const DWORD *cdb, BYTE *buf)
|
|
{
|
|
// Get length, clear buffer
|
|
int length = cdb[7];
|
|
length <<= 8;
|
|
length |= cdb[8];
|
|
if (length > 0x800) {
|
|
length = 0x800;
|
|
}
|
|
memset(buf, 0, length);
|
|
|
|
// Get page code (0x00 is valid from the beginning)
|
|
int page = cdb[2] & 0x3f;
|
|
bool valid = page == 0x00;
|
|
|
|
LOGTRACE("%s Requesting mode page $%02X", __PRETTY_FUNCTION__, page);
|
|
|
|
// Basic Information
|
|
int size = 8;
|
|
|
|
int ret = AddRealtimeClockPage(page, &buf[size]);
|
|
if (ret > 0) {
|
|
size += ret;
|
|
valid = true;
|
|
}
|
|
|
|
if (!valid) {
|
|
LOGTRACE("%s Unsupported mode page $%02X", __PRETTY_FUNCTION__, page);
|
|
SetStatusCode(STATUS_INVALIDCDB);
|
|
return 0;
|
|
}
|
|
|
|
// Do not return more than ALLOCATION LENGTH bytes
|
|
if (size > length) {
|
|
LOGTRACE("%s %d bytes available, %d bytes requested", __PRETTY_FUNCTION__, size, length);
|
|
size = length;
|
|
}
|
|
|
|
// Final setting of mode data length
|
|
buf[0] = size >> 8;
|
|
buf[1] = size;
|
|
|
|
return size;
|
|
}
|
|
|
|
int HostServices::AddRealtimeClockPage(int page, BYTE *buf)
|
|
{
|
|
if (page == 0x20) {
|
|
// Data structure version 1.0
|
|
buf[0] = 0x01;
|
|
buf[1] = 0x00;
|
|
|
|
std::time_t t = std::time(NULL);
|
|
std::tm tm = *std::localtime(&t);
|
|
buf[2] = tm.tm_year;
|
|
buf[3] = tm.tm_mon;
|
|
buf[4] = tm.tm_mday;
|
|
buf[5] = tm.tm_hour;
|
|
buf[6] = tm.tm_min;
|
|
// Ignore leap second for simplicity
|
|
buf[7] = tm.tm_sec < 60 ? tm.tm_sec : 59;
|
|
|
|
return 8;
|
|
}
|
|
|
|
return 0;
|
|
}
|