greenscsi/src/general.ino

524 lines
17 KiB
C++
Executable File

#include "config.h"
#include "scsi_defs.h"
/*
* INQUIRY command processing.
*/
void InquiryCommandHandler() {
LOGN("[Inquiry]");
uint8_t len;
if(!m_sel) {
memset(m_responsebuffer, 0, 96);
m_responsebuffer[0] = 0x7f;
m_responsebuffer[4] = 35 - 4;
len = 36;
} else {
memcpy(m_responsebuffer, m_sel->m_inquiryresponse, 96);
len = m_responsebuffer[4] + 5;
}
len = min(len, m_cmd[4]);
writeDataPhase(len, m_responsebuffer);
m_phase = PHASE_STATUSIN;
}
/*
* REQUEST SENSE command processing.
*/
void RequestSenseCommandHandler() {
LOGN("[RequestSense]");
uint8_t len = m_cmd[4];
uint8_t buf[18] = {
0x70, //CheckCondition
0, //Segment number
0x00, //Sense key
0, 0, 0, 0, //information
17 - 7 , //Additional data length
0,
};
if(!m_sel) {
buf[2] = 2; // Not ready
buf[12] = LUN_NOT_READY; // Logical Unit Not Ready, Manual Intervention Required
buf[13] = 0x03;
} else {
buf[2] = m_sel->m_sense.m_key;
buf[12] = m_sel->m_sense.m_code;
buf[13] = m_sel->m_sense.m_key_specific[0];
buf[14] = m_sel->m_sense.m_key_specific[1];
buf[15] = m_sel->m_sense.m_key_specific[2];
m_sel->m_sense.m_key = 0;
m_sel->m_sense.m_code = 0;
m_sel->m_sense.m_key_specific[0] = 0;
m_sel->m_sense.m_key_specific[1] = 0;
m_sel->m_sense.m_key_specific[2] = 0;
}
writeDataPhase(len < 18 ? len : 18, buf);
m_phase = PHASE_STATUSIN;
}
void TestUnitCommandHandler() {
LOGN("[TestUnit]");
if(!m_sel) {
m_sts |= STATUS_CHECK;
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;
return;
}
m_phase = PHASE_STATUSIN;
}
void RezeroUnitCommandHandler() {
LOGN("[RezeroUnit]");
if(!m_sel) {
m_sts |= STATUS_CHECK;
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;
return;
}
m_phase = PHASE_STATUSIN;
}
void FormatUnitCommandHandler() {
LOGN("[FormatUnit]");
if(!m_sel) {
m_sts |= STATUS_CHECK;
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;
return;
}
m_phase = PHASE_STATUSIN;
}
void ReassignBlocksCommandHandler() {
LOGN("[ReassignBlocks]");
if(!m_sel) {
m_sts |= STATUS_CHECK;
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;
return;
}
m_phase = PHASE_STATUSIN;
}
#if SUPPORT_APPLE
void AppleEECommandHandler() {
LOGN("[Apple:0xEE]");
m_phase = PHASE_STATUSIN;
}
#endif
/*
* MODE SENSE command processing.
*/
void ModeSenseCommandHandler()
{
uint16_t len, maxlen;
int page, pagemax, pagemin;
switch(m_cmd[0]) {
case CMD_MODE_SENSE6:
LOGN("[ModeSense6]");
maxlen = m_cmd[4];
len = 1;
break;
case CMD_MODE_SENSE10:
LOGN("[ModeSense10]");
maxlen = ((uint16_t)m_cmd[7] << 8) | m_cmd[8];
len = 2;
break;
default:
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
/* Check whether medium is present */
if(!m_sel) {
m_sts |= STATUS_CHECK; // Image file absent
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;
}
memset(m_responsebuffer, 0, sizeof(m_responsebuffer));
{
/* Default medium type */
m_responsebuffer[len++] = (m_sel->m_type == DEV_OPTICAL) ? 0xf0 : 0x00;
/* Write protected */
m_responsebuffer[len++] = (m_sel->m_type == DEV_OPTICAL) ? 0x80 : 0x00;
// ModeSense10 has two extra bytes, and Block Descriptor Length has an extra MSB
if(m_cmd[0] == CMD_MODE_SENSE10) {
len += 2;
m_responsebuffer[len++] = 0;
}
/* Add block descriptor if DBD is not set */
if (m_cmd[1] & 0x08) {
m_responsebuffer[len++] = 0; /* No block descriptor */
} else {
if(m_sel->m_type == DEV_TAPE) {
m_responsebuffer[len++] = 8; /* Block descriptor length */
m_responsebuffer[len++] = 0x40; /* Medium Density Code */
m_responsebuffer[len++] = 0x00; /* Number of Blocks (0) */
m_responsebuffer[len++] = 0x00;
m_responsebuffer[len++] = 0x00;
m_responsebuffer[len++] = 0x00; /* Block Length 1024 */
m_responsebuffer[len++] = 0x00;
m_responsebuffer[len++] = 0x04;
m_responsebuffer[len++] = 0x00;
} else {
uint32_t capacity = (m_sel->m_fileSize / m_sel->m_blocksize) - 1;
m_responsebuffer[len++] = 8; /* Block descriptor length */
m_responsebuffer[len++] = (capacity >> 24) & 0xff;
m_responsebuffer[len++] = (capacity >> 16) & 0xff;
m_responsebuffer[len++] = (capacity >> 8) & 0xff;
m_responsebuffer[len++] = capacity & 0xff;
m_responsebuffer[len++] = (m_sel->m_blocksize >> 24) & 0xff;
m_responsebuffer[len++] = (m_sel->m_blocksize >> 16) & 0xff;
m_responsebuffer[len++] = (m_sel->m_blocksize >> 8) & 0xff;
m_responsebuffer[len++] = (m_sel->m_blocksize) & 0xff;
}
}
/* Check for requested mode page */
page = m_cmd[2] & 0x3F;
pagemax = (page != 0x3f) ? page : 0x3e;
pagemin = (page != 0x3f) ? page : 0x00;
for(page = pagemax; page >= pagemin; page--) {
switch (page) {
case MODEPAGE_VENDOR_SPECIFIC:
/* Accept request only for current values */
if (m_cmd[2] & 0xC0) {
//DEBUGPRINT(DBG_TRACE, " [2]==%d", m_cmd[2]);
/* Prepare sense data */
m_sts |= STATUS_CHECK;
m_sel->m_sense.m_key = ILLEGAL_REQUEST;
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 2" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x02;
m_phase = PHASE_STATUSIN;
return;
}
/* Unit attention */
m_responsebuffer[len++] = 0x80; // PS, page id
m_responsebuffer[len++] = 0x02; // Page length
m_responsebuffer[len++] = 0x00;
m_responsebuffer[len++] = 0x00;
break;
case MODEPAGE_RW_ERROR_RECOVERY:
if(m_cmd[2] & 0x40) {
m_sts |= STATUS_CHECK;
m_sel->m_sense.m_key = ILLEGAL_REQUEST;
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 2" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x02;
m_phase = PHASE_STATUSIN;
return;
}
m_responsebuffer[len++] = MODEPAGE_RW_ERROR_RECOVERY; // PS, page id
m_responsebuffer[len++] = 0x0a; // Page length
m_responsebuffer[len++] = 0x05; //
m_responsebuffer[len++] = 0x00; // Read Retry Count
m_responsebuffer[len++] = 0x00; // Reserved
m_responsebuffer[len++] = 0x00; // Reserved
m_responsebuffer[len++] = 0x00; // Reserved
m_responsebuffer[len++] = 0x00; // Reserved
m_responsebuffer[len++] = 0x00; // Write Retry Count
m_responsebuffer[len++] = 0x00; // Reserved
m_responsebuffer[len++] = 0x00; // Recovery Time Limit
m_responsebuffer[len++] = 0x00;
break;
#if 0
case MODEPAGE_DCRC_PARAMETERS:
m_responsebuffer[len++] = 0x82; // PS, page id
m_responsebuffer[len++] = 0x0e; // Page length
m_responsebuffer[len++] = 0xe6; // Buffer full ratio, 90%
m_responsebuffer[len++] = 0x1a; // Buffer empty ratio, 10%
m_responsebuffer[len++] = 0x00; // Bus inactivity limit
m_responsebuffer[len++] = 0x00;
m_responsebuffer[len++] = 0x00; // Disconnect time limit
m_responsebuffer[len++] = 0x00;
m_responsebuffer[len++] = 0x00; // Connect time limit
m_responsebuffer[len++] = 0x00;
m_responsebuffer[len++] = 0x00; // Maximum burst size
m_responsebuffer[len++] = 0x00;
m_responsebuffer[len++] = 0x00; // EMDP, Dimm, DTDC
m_responsebuffer[len++] = 0x00; // Reserved
m_responsebuffer[len++] = 0x00; // Reserved
m_responsebuffer[len++] = 0x00; // Reserved
break;
#endif
#if SUPPORT_APPLE
case MODEPAGE_APPLE:
if( m_sel->m_quirks & QUIRKS_APPLE) {
m_responsebuffer[len++] = 0xb0;
m_responsebuffer[len++] = 0x16;
m_responsebuffer[len++] = 'A';
m_responsebuffer[len++] = 'P';
m_responsebuffer[len++] = 'P';
m_responsebuffer[len++] = 'L';
m_responsebuffer[len++] = 'E';
m_responsebuffer[len++] = ' ';
m_responsebuffer[len++] = 'C';
m_responsebuffer[len++] = 'O';
m_responsebuffer[len++] = 'M';
m_responsebuffer[len++] = 'P';
m_responsebuffer[len++] = 'U';
m_responsebuffer[len++] = 'T';
m_responsebuffer[len++] = 'E';
m_responsebuffer[len++] = 'R';
m_responsebuffer[len++] = ',';
m_responsebuffer[len++] = ' ';
m_responsebuffer[len++] = 'I';
m_responsebuffer[len++] = 'N';
m_responsebuffer[len++] = 'C';
m_responsebuffer[len++] = ' ';
m_responsebuffer[len++] = ' ';
m_responsebuffer[len++] = ' ';
}
break;
#endif
case MODEPAGE_FORMAT_PARAMETERS:
m_responsebuffer[len + 0] = MODEPAGE_FORMAT_PARAMETERS; //Page code
m_responsebuffer[len + 1] = 0x16; // Page length
if((m_cmd[2] >> 6) != 1) {
m_responsebuffer[len + 11] = 0x3F; // Number of sectors / track
m_responsebuffer[len + 12] = (m_sel->m_blocksize >> 8) & 0xff; // Blocksize MSB
m_responsebuffer[len + 13] = (m_sel->m_blocksize >> 0) & 0xff; // Blocksize LSB
m_responsebuffer[len + 15] = 0x1; // Interleave
}
len += 24;
break;
case MODEPAGE_RIGID_GEOMETRY:
m_responsebuffer[len + 0] = MODEPAGE_RIGID_GEOMETRY; //Page code
m_responsebuffer[len + 1] = 0x16; // Page length
if((m_cmd[2] >> 6) != 1) {
m_responsebuffer[len + 2] = m_sel->m_cylinders >> 16; // Number of cylinders
m_responsebuffer[len + 3] = m_sel->m_cylinders >> 8;
m_responsebuffer[len + 4] = m_sel->m_cylinders;
m_responsebuffer[len + 5] = m_sel->m_heads; // Number of heads
memcpy(&m_responsebuffer[len + 6], &m_responsebuffer[len + 2], 3); // Write Precomp Cyl
memcpy(&m_responsebuffer[len + 9], &m_responsebuffer[len + 2], 3); // Reduced Write Current Cyl
m_responsebuffer[len + 20] = 0x1C; // 7200 RPM
m_responsebuffer[len + 21] = 0x20;
}
len += 24;
break;
case MODEPAGE_FLEXIBLE_GEOMETRY:
{
m_responsebuffer[len + 0] = MODEPAGE_FLEXIBLE_GEOMETRY; //Page code
m_responsebuffer[len + 1] = 0x1E; // Page length
m_responsebuffer[len + 2] = 0x03; // Transfer rate 1mbit/s (MSB)
m_responsebuffer[len + 3] = 0xE8; // Transfer rate 1mbit/s (LSB)
m_responsebuffer[len + 4] = 16; // Number of heads
m_responsebuffer[len + 5] = 18; // Sectors per track
m_responsebuffer[len + 6] = 0x20; // Data bytes per sector (MSB)
m_responsebuffer[len + 6] = 0x00; // Data bytes per sector (LSB)
len += 24;
}
break;
default:
if(pagemin == pagemax) {
m_sts |= STATUS_CHECK;
m_sel->m_sense.m_key = ILLEGAL_REQUEST;
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 2" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x02;
m_phase = PHASE_STATUSIN;
return;
}
}
}
/* Report size of requested data */
if(m_cmd[0] == CMD_MODE_SENSE6) {
m_responsebuffer[0] = len;
} else {
m_responsebuffer[0] = (len >> 8) & 0xff;
m_responsebuffer[1] = len & 0xff;
}
/* Truncate data if necessary */
if (maxlen < len) {
len = maxlen;
}
// Send it
writeDataPhase(len, m_responsebuffer);
}
m_phase = PHASE_STATUSIN;
}
uint8_t onModeSelectCommand() {
return STATUS_GOOD;
}
void ModeSelect6CommandHandler() {
LOG("[ModeSelect6] ");
uint16_t len = m_cmd[4];
if(!m_sel) {
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
if(len > MAX_BLOCKSIZE) {
m_sel->m_sense.m_key = ILLEGAL_REQUEST;
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 4" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x04;
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
readDataPhase(len, m_responsebuffer);
for(int i = 1; i < len; i++ ) {
LOG(":");
LOGHEX2(m_responsebuffer[i]);
}
LOGN("");
m_sts |= onModeSelectCommand();
m_phase = PHASE_STATUSIN;
}
void ModeSelect10CommandHandler() {
LOGN("[ModeSelect10]");
uint16_t len = ((uint16_t)m_cmd[7] << 8) | m_cmd[8];
if(!m_sel) {
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
if(len > MAX_BLOCKSIZE) {
m_sel->m_sense.m_key = ILLEGAL_REQUEST;
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 7" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x07;
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
return;
}
readDataPhase(len, m_responsebuffer);
for(int i = 1; i < len; i++ ) {
LOG(":");
LOGHEX2(m_responsebuffer[i]);
}
LOGN("");
m_sts |= onModeSelectCommand();
m_phase = PHASE_STATUSIN;
}
void SearchDataEqualCommandHandler() {
LOGN("[SearchDataEqual]");
m_phase = PHASE_STATUSIN;
}
void SendDiagnosticCommandHandler() {
LOGN("[SendDiagnostic]");
if(!m_sel) {
m_sts |= STATUS_CHECK; // Image file absent
m_phase = PHASE_STATUSIN;
return;
}
if(m_cmd[1] & 0x04) {
} else {
m_sel->m_sense.m_code = INVALID_FIELD_IN_CDB; /* "Invalid field in CDB" */
m_sel->m_sense.m_key_specific[0] = ERROR_IN_OPCODE; /* "Error in Byte 1" */
m_sel->m_sense.m_key_specific[1] = 0x00;
m_sel->m_sense.m_key_specific[2] = 0x01;
m_sts |= STATUS_CHECK;
}
m_phase = PHASE_STATUSIN;
}
void ReadDefectCommandHandler() {
LOGN("[ReadDefect]");
m_responsebuffer[0] = 0x00;
m_responsebuffer[1] = m_cmd[2];
m_responsebuffer[2] = m_cmd[7]; // List Length MSB
m_responsebuffer[3] = m_cmd[8]; // List Length LSB
writeDataPhase(4, m_responsebuffer);
m_phase = PHASE_STATUSIN;
}
void StartStopUnitCommandHandler() {
LOGN("[StartStopUnit]");
m_phase = PHASE_STATUSIN;
}
void PreAllowMediumRemovalCommandHandler() {
LOGN("[PreAllowMed.Removal]");
m_phase = PHASE_STATUSIN;
}
void PrefetchCommandHandler() {
LOGN("[Prefetch]");
m_phase = PHASE_STATUSIN;
}
void SyncCacheCommandHandler() {
LOGN("[SyncCache]");
m_phase = PHASE_STATUSIN;
}
void UnknownCommandHandler() {
LOGN("[*Unknown]");
m_sts |= STATUS_CHECK;
if(m_sel) {
m_sel->m_sense.m_key = 5;
}
m_phase = PHASE_STATUSIN;
}
void BadLunCommandHandler() {
LOGN("[Bad LUN]");
m_sts |= STATUS_CHECK;
m_phase = PHASE_STATUSIN;
}