mirror of
https://github.com/dkgrizzly/GreenSCSI.git
synced 2025-01-16 17:30:19 +00:00
265 lines
8.3 KiB
C++
Executable File
265 lines
8.3 KiB
C++
Executable File
#include "config.h"
|
|
#include "scsi_defs.h"
|
|
|
|
/*
|
|
* Check that the image file is present and the block range is valid.
|
|
*/
|
|
byte checkBlockCommand(uint32_t adds, uint32_t len)
|
|
{
|
|
// Check that image file is present
|
|
if(!m_sel) {
|
|
return STATUS_CHECK;
|
|
}
|
|
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
|
|
m_sel->m_sense.m_key = NOT_READY; // Not ready
|
|
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
|
m_sel->m_sense.m_key_specific[0] = 0x03;
|
|
return STATUS_CHECK;
|
|
}
|
|
// Check block range is valid
|
|
uint32_t bc = m_sel->m_fileSize / m_sel->m_blocksize;
|
|
if (adds >= bc || (adds + len) > bc) {
|
|
m_sel->m_sense.m_key = 5; // Illegal request
|
|
m_sel->m_sense.m_code = INVALID_LBA; // Logical block address out of range
|
|
return STATUS_CHECK;
|
|
}
|
|
return 0x00;
|
|
}
|
|
|
|
void Read6CommandHandler() {
|
|
LOG("[Read6]");
|
|
m_sts |= onReadCommand((((uint32_t)m_cmd[1] & 0x1F) << 16) | ((uint32_t)m_cmd[2] << 8) | m_cmd[3], (m_cmd[4] == 0) ? 0x100 : m_cmd[4]);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void Write6CommandHandler() {
|
|
LOG("[Write6]");
|
|
m_sts |= onWriteCommand((((uint32_t)m_cmd[1] & 0x1F) << 16) | ((uint32_t)m_cmd[2] << 8) | m_cmd[3], (m_cmd[4] == 0) ? 0x100 : m_cmd[4]);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void Seek6CommandHandler() {
|
|
LOG("[Seek6]");
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
/*
|
|
* READ CAPACITY command processing.
|
|
*/
|
|
void ReadCapacityCommandHandler() {
|
|
LOGN("[ReadCapacity]");
|
|
if(!m_sel) {
|
|
m_sts |= STATUS_CHECK;
|
|
m_phase = PHASE_STATUSIN;
|
|
return;
|
|
}
|
|
if(!m_sel->m_rawPart && !m_sel->m_file.isOpen()) {
|
|
m_sts |= STATUS_CHECK;
|
|
m_sel->m_sense.m_key = NOT_READY; // Not ready
|
|
m_sel->m_sense.m_code = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
|
|
m_sel->m_sense.m_key_specific[0] = 0x03;
|
|
m_phase = PHASE_STATUSIN;
|
|
return;
|
|
}
|
|
|
|
uint32_t bl = m_sel->m_blocksize;
|
|
uint32_t bc = m_sel->m_fileSize / bl;
|
|
uint8_t buf[8] = {
|
|
(uint8_t)(((uint32_t)(bc >> 24))&0xff), (uint8_t)(((uint32_t)(bc >> 16))&0xff), (uint8_t)(((uint32_t)(bc >> 8))&0xff), (uint8_t)(((uint32_t)(bc))&0xff),
|
|
(uint8_t)(((uint32_t)(bl >> 24))&0xff), (uint8_t)(((uint32_t)(bl >> 16))&0xff), (uint8_t)(((uint32_t)(bl >> 8))&0xff), (uint8_t)(((uint32_t)(bl))&0xff)
|
|
};
|
|
writeDataPhase(8, buf);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void Read10CommandHandler() {
|
|
LOG("[Read10]");
|
|
m_sts |= onReadCommand(((uint32_t)m_cmd[2] << 24) | ((uint32_t)m_cmd[3] << 16) | ((uint32_t)m_cmd[4] << 8) | m_cmd[5], ((uint32_t)m_cmd[7] << 8) | m_cmd[8]);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void Write10CommandHandler() {
|
|
LOG("[Write10]");
|
|
m_sts |= onWriteCommand(((uint32_t)m_cmd[2] << 24) | ((uint32_t)m_cmd[3] << 16) | ((uint32_t)m_cmd[4] << 8) | m_cmd[5], ((uint32_t)m_cmd[7] << 8) | m_cmd[8]);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void Seek10CommandHandler() {
|
|
LOG("[Seek10]");
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
void Verify10CommandHandler() {
|
|
LOG("[Verify10]");
|
|
m_sts |= onVerifyCommand(((uint32_t)m_cmd[2] << 24) | ((uint32_t)m_cmd[3] << 16) | ((uint32_t)m_cmd[4] << 8) | m_cmd[5], ((uint32_t)m_cmd[7] << 8) | m_cmd[8]);
|
|
m_phase = PHASE_STATUSIN;
|
|
}
|
|
|
|
/*
|
|
* READ6 / 10 Command processing.
|
|
*/
|
|
uint8_t onReadCommand(uint32_t adds, uint32_t len)
|
|
{
|
|
uint8_t sts;
|
|
|
|
LOG("-R ");
|
|
LOGHEX6(adds);
|
|
LOG(" ");
|
|
LOGHEX4N(len);
|
|
|
|
sts = checkBlockCommand(adds, len);
|
|
if(sts) return sts;
|
|
|
|
LED_ON();
|
|
if(m_sel->m_rawPart) {
|
|
writeDataPhaseRaw(adds, len);
|
|
} else {
|
|
writeDataPhaseSD(adds, len);
|
|
}
|
|
LED_OFF();
|
|
return 0x00; //sts
|
|
}
|
|
|
|
/*
|
|
* WRITE6 / 10 Command processing.
|
|
*/
|
|
uint8_t onWriteCommand(uint32_t adds, uint32_t len)
|
|
{
|
|
uint8_t sts;
|
|
|
|
LOG("-W ");
|
|
LOGHEX6(adds);
|
|
LOG(" ");
|
|
LOGHEX4N(len);
|
|
|
|
sts = checkBlockCommand(adds, len);
|
|
if(sts) return sts;
|
|
|
|
LED_ON();
|
|
if(m_sel->m_rawPart) {
|
|
readDataPhaseRaw(adds, len);
|
|
} else {
|
|
readDataPhaseSD(adds, len);
|
|
}
|
|
LED_OFF();
|
|
return 0; //sts
|
|
}
|
|
|
|
/*
|
|
* VERIFY6 / 10 Command processing.
|
|
*/
|
|
uint8_t onVerifyCommand(uint32_t adds, uint32_t len)
|
|
{
|
|
uint8_t sts;
|
|
|
|
LOG("-V ");
|
|
LOGHEX6(adds);
|
|
LOG(" ");
|
|
LOGHEX4N(len);
|
|
|
|
sts = checkBlockCommand(adds, len);
|
|
if(sts) return sts;
|
|
|
|
LED_ON();
|
|
if(m_sel->m_rawPart) {
|
|
verifyDataPhaseRaw(adds, len);
|
|
} else {
|
|
verifyDataPhaseSD(adds, len);
|
|
}
|
|
LED_OFF();
|
|
return 0; //sts
|
|
}
|
|
|
|
void ConfigureDiskHandlers(VirtualDevice_t *vdev) {
|
|
for(int c = 0; c < 256; c++)
|
|
vdev->m_handler[c] = &UnknownCommandHandler;
|
|
|
|
vdev->m_handler[CMD_TEST_UNIT_READY] = &TestUnitCommandHandler;
|
|
vdev->m_handler[CMD_REZERO_UNIT] = &RezeroUnitCommandHandler;
|
|
vdev->m_handler[CMD_REQUEST_SENSE] = &RequestSenseCommandHandler;
|
|
vdev->m_handler[CMD_FORMAT_UNIT] = &FormatUnitCommandHandler;
|
|
vdev->m_handler[CMD_FORMAT_UNIT_ALT] = &FormatUnitCommandHandler;
|
|
vdev->m_handler[CMD_REASSIGN_BLOCKS] = &ReassignBlocksCommandHandler;
|
|
vdev->m_handler[CMD_READ6] = &Read6CommandHandler;
|
|
vdev->m_handler[CMD_WRITE6] = &Write6CommandHandler;
|
|
vdev->m_handler[CMD_SEEK6] = &Seek6CommandHandler;
|
|
vdev->m_handler[CMD_INQUIRY] = &InquiryCommandHandler;
|
|
vdev->m_handler[CMD_MODE_SELECT6] = &ModeSelect6CommandHandler;
|
|
vdev->m_handler[CMD_MODE_SENSE6] = &ModeSenseCommandHandler;
|
|
vdev->m_handler[CMD_START_STOP_UNIT] = &StartStopUnitCommandHandler;
|
|
vdev->m_handler[CMD_PREVENT_REMOVAL] = &PreAllowMediumRemovalCommandHandler;
|
|
vdev->m_handler[CMD_READ_CAPACITY10] = &ReadCapacityCommandHandler;
|
|
vdev->m_handler[CMD_READ10] = &Read10CommandHandler;
|
|
vdev->m_handler[CMD_WRITE10] = &Write10CommandHandler;
|
|
vdev->m_handler[CMD_SEEK10] = &Seek10CommandHandler;
|
|
vdev->m_handler[CMD_VERIFY10] = &Verify10CommandHandler;
|
|
vdev->m_handler[CMD_MODE_SENSE10] = &ModeSenseCommandHandler;
|
|
vdev->m_handler[CMD_SEARCH_DATA_EQUAL] = &SearchDataEqualCommandHandler;
|
|
vdev->m_handler[CMD_READ_DEFECT_DATA] = &ReadDefectCommandHandler;
|
|
vdev->m_handler[CMD_SEND_DIAGNOSTIC] = &SendDiagnosticCommandHandler;
|
|
vdev->m_handler[CMD_PREFETCH_CACHE10] = &PrefetchCommandHandler;
|
|
vdev->m_handler[CMD_SYNCHRONIZE_CACHE10] = &SyncCacheCommandHandler;
|
|
#if SUPPORT_SASI
|
|
if(vdev->m_quirks & QUIRKS_SASI)
|
|
vdev->m_handler[CMD_SET_DRIVE_PARAMETER] = &DTCsetDriveParameterCommandHandler;
|
|
#endif
|
|
#if SUPPORT_APPLE
|
|
if(vdev->m_quirks & QUIRKS_APPLE)
|
|
vdev->m_handler[CMD_MAC_UNKNOWN] = &AppleEECommandHandler;
|
|
#endif
|
|
}
|
|
|
|
// If config file exists, read the first three lines and copy the contents.
|
|
// File must be well formed or you will get junk in the SCSI Vendor fields.
|
|
void ConfigureDisk(VirtualDevice_t *vdev, const char *image_name) {
|
|
for(int i = 0; SCSI_INQUIRY_RESPONSE[i][0] != 0xff; i++) {
|
|
if(SCSI_INQUIRY_RESPONSE[i][0] == DEV_DISK) {
|
|
memcpy(vdev->m_inquiryresponse, SCSI_INQUIRY_RESPONSE[i], SCSI_INQUIRY_RESPONSE_SIZE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
vdev->m_sectors = 63;
|
|
vdev->m_heads = 16;
|
|
vdev->m_cylinders = (uint32_t)((uint64_t)vdev->m_fileSize / ((uint64_t)vdev->m_blocksize * (uint64_t)vdev->m_heads * (uint64_t)vdev->m_sectors));
|
|
|
|
if(image_name) {
|
|
char configname[MAX_FILE_PATH+1];
|
|
memcpy(configname, image_name, MAX_FILE_PATH+1);
|
|
char *psuffix = strstr(configname, ".img");
|
|
if(psuffix) {
|
|
strcpy(psuffix, ".cfg");
|
|
} else {
|
|
sprintf(configname, "hd%d%d.cfg", vdev->m_id, vdev->m_lun);
|
|
}
|
|
|
|
FsFile config_file = sd.open(configname, O_RDONLY);
|
|
if (config_file.isOpen()) {
|
|
char vendor[9];
|
|
memset(vendor, 0, sizeof(vendor));
|
|
config_file.readBytes(vendor, sizeof(vendor));
|
|
LOGN("SCSI VENDOR: ");
|
|
LOGN(vendor);
|
|
memcpy(&(vdev->m_inquiryresponse[8]), vendor, 8);
|
|
|
|
char product[17];
|
|
memset(product, 0, sizeof(product));
|
|
config_file.readBytes(product, sizeof(product));
|
|
LOGN("SCSI PRODUCT: ");
|
|
LOGN(product);
|
|
memcpy(&(vdev->m_inquiryresponse[16]), product, 16);
|
|
|
|
char version[5];
|
|
memset(version, 0, sizeof(version));
|
|
config_file.readBytes(version, sizeof(version));
|
|
LOGN("SCSI VERSION: ");
|
|
LOGN(version);
|
|
memcpy(&(vdev->m_inquiryresponse[32]), version, 4);
|
|
config_file.close();
|
|
}
|
|
}
|
|
|
|
vdev->m_type = DEV_DISK;
|
|
ConfigureDiskHandlers(vdev);
|
|
}
|