#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; }