|
|
@@ -39,7 +39,7 @@
|
|
|
#include <SdFat.h>
|
|
|
#include <setjmp.h>
|
|
|
|
|
|
-#define DEBUG 0 // 0:No debug information output
|
|
|
+#define DEBUG 1 // 0:No debug information output
|
|
|
// 1: Debug information output to USB Serial
|
|
|
// 2: Debug information output to LOG.txt (slow)
|
|
|
|
|
|
@@ -98,6 +98,12 @@ SCSI_COMMAND_HANDLER(onWriteBuffer);
|
|
|
SCSI_COMMAND_HANDLER(onReZeroUnit);
|
|
|
SCSI_COMMAND_HANDLER(onSendDiagnostic);
|
|
|
SCSI_COMMAND_HANDLER(onReadDefectData);
|
|
|
+SCSI_COMMAND_HANDLER(onReadTOC);
|
|
|
+SCSI_COMMAND_HANDLER(onReadDVDStructure);
|
|
|
+SCSI_COMMAND_HANDLER(onReadDiscInformation);
|
|
|
+
|
|
|
+static uint32_t MSFtoLBA(const byte *msf);
|
|
|
+static void LBAtoMSF(const uint32_t lba, byte *msf);
|
|
|
|
|
|
static void flashError(const unsigned error);
|
|
|
void onBusReset(void);
|
|
|
@@ -185,6 +191,23 @@ void readSDCardInfo()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+bool VerifyISOPVD(SCSI_DEVICE *dev, unsigned sector_size, bool mode2)
|
|
|
+{
|
|
|
+ int seek = 16 * sector_size;
|
|
|
+ if(sector_size > CDROM_COMMON_SECTORSIZE) seek += 16;
|
|
|
+ if(mode2) seek += 8;
|
|
|
+ bool ret = false;
|
|
|
+
|
|
|
+ dev->m_file->seekSet(seek);
|
|
|
+ dev->m_file->read(m_buf, 2048);
|
|
|
+
|
|
|
+ ret = ((m_buf[0] == 1 && !strncmp((char *)&m_buf[1], "CD001", 5) && m_buf[6] == 1) ||
|
|
|
+ (m_buf[8] == 1 && !strncmp((char *)&m_buf[9], "CDROM", 5) && m_buf[14] == 1));
|
|
|
+
|
|
|
+ dev->m_file->rewind();
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Open HDD image file
|
|
|
*/
|
|
|
@@ -192,32 +215,83 @@ void readSDCardInfo()
|
|
|
bool hddimageOpen(SCSI_DEVICE *dev, FsFile *file,int id,int lun,int blocksize)
|
|
|
{
|
|
|
dev->m_fileSize= 0;
|
|
|
+ dev->m_offset = 0;
|
|
|
dev->m_blocksize = blocksize;
|
|
|
dev->m_file = file;
|
|
|
- dev->m_type = SCSI_DEVICE_HDD;
|
|
|
- if(dev->m_file->isOpen())
|
|
|
- {
|
|
|
- dev->m_fileSize = dev->m_file->size();
|
|
|
- dev->m_blockcount = dev->m_fileSize / dev->m_blocksize;
|
|
|
- if(dev->m_fileSize>0)
|
|
|
- {
|
|
|
- // check blocksize dummy file
|
|
|
- LOG_FILE.print(" / ");
|
|
|
- LOG_FILE.print(dev->m_fileSize);
|
|
|
- LOG_FILE.print("bytes / ");
|
|
|
- LOG_FILE.print(dev->m_fileSize / 1024);
|
|
|
- LOG_FILE.print("KiB / ");
|
|
|
- LOG_FILE.print(dev->m_fileSize / 1024 / 1024);
|
|
|
- LOG_FILE.println("MiB");
|
|
|
- return true; // File opened
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- LOG_FILE.println(" - file is 0 bytes, can not use.");
|
|
|
- dev->m_file->close();
|
|
|
- dev->m_fileSize = dev->m_blocksize = 0; // no file
|
|
|
+ if(!dev->m_file->isOpen()) { goto failed; }
|
|
|
+
|
|
|
+ dev->m_fileSize = dev->m_file->size();
|
|
|
+
|
|
|
+ if(dev->m_fileSize < 1) {
|
|
|
+ LOG_FILE.println(" - file is 0 bytes, can not use.");
|
|
|
+ goto failed;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(dev->m_type == SCSI_DEVICE_OPTICAL) {
|
|
|
+ LOG_FILE.print(" CDROM");
|
|
|
+
|
|
|
+ // Borrowed from PCEM
|
|
|
+ if(VerifyISOPVD(dev, CDROM_COMMON_SECTORSIZE, false)) {
|
|
|
+ dev->m_blocksize = CDROM_COMMON_SECTORSIZE;
|
|
|
+ dev->m_mode2 = false;
|
|
|
+ } else if(VerifyISOPVD(dev, CDROM_RAW_SECTORSIZE, false)) {
|
|
|
+ dev->m_blocksize = CDROM_RAW_SECTORSIZE;
|
|
|
+ dev->m_rawblocksize = CDROM_COMMON_SECTORSIZE;
|
|
|
+ dev->m_mode2 = false;
|
|
|
+ dev->m_raw = true;
|
|
|
+ dev->m_offset = 16;
|
|
|
+ } else if(VerifyISOPVD(dev, 2336, true)) {
|
|
|
+ dev->m_blocksize = 2336;
|
|
|
+ dev->m_mode2 = true;
|
|
|
+ } else if(VerifyISOPVD(dev, CDROM_RAW_SECTORSIZE, true)) {
|
|
|
+ dev->m_blocksize = CDROM_RAW_SECTORSIZE;
|
|
|
+ dev->m_mode2 = true;
|
|
|
+ dev->m_raw = true;
|
|
|
+ dev->m_offset = 16;
|
|
|
+ } else {
|
|
|
+ // Last ditch effort
|
|
|
+ // size must be less than 700MB
|
|
|
+ if(dev->m_fileSize > 912579600) {
|
|
|
+ goto failed;
|
|
|
+ }
|
|
|
+
|
|
|
+ dev->m_raw = true;
|
|
|
+
|
|
|
+ if(!(dev->m_fileSize % CDROM_COMMON_SECTORSIZE)) {
|
|
|
+ // try a multiple of 2048
|
|
|
+ dev->m_blocksize = CDROM_COMMON_SECTORSIZE;
|
|
|
+ } else {
|
|
|
+ // I give up!
|
|
|
+ LOG_FILE.println(" InvalidISO");
|
|
|
+ goto failed;
|
|
|
+ }
|
|
|
}
|
|
|
+ } else {
|
|
|
+ LOG_FILE.print(" HDD");
|
|
|
}
|
|
|
+ dev->m_blockcount = dev->m_fileSize / dev->m_blocksize;
|
|
|
+
|
|
|
+ // check blocksize dummy file
|
|
|
+ LOG_FILE.print(" / ");
|
|
|
+ LOG_FILE.print(dev->m_fileSize);
|
|
|
+ LOG_FILE.print("bytes / ");
|
|
|
+ LOG_FILE.print(dev->m_fileSize / 1024);
|
|
|
+ LOG_FILE.print("KiB / ");
|
|
|
+ LOG_FILE.print(dev->m_fileSize / 1024 / 1024);
|
|
|
+ LOG_FILE.println("MiB");
|
|
|
+
|
|
|
+ if(dev->m_type == SCSI_DEVICE_OPTICAL) {
|
|
|
+ LOG_FILE.print(" MODE2:");LOG_FILE.print(dev->m_mode2);
|
|
|
+ LOG_FILE.print(" BlockSize:");LOG_FILE.println(dev->m_blocksize);
|
|
|
+ }
|
|
|
+ return true; // File opened
|
|
|
+
|
|
|
+failed:
|
|
|
+
|
|
|
+ dev->m_file->close();
|
|
|
+ dev->m_fileSize = dev->m_blocksize = 0; // no file
|
|
|
+ delete dev->m_file;
|
|
|
+ dev->m_file = NULL;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
@@ -272,6 +346,9 @@ void setup()
|
|
|
scsi_command_table[SCSI_WRITE_BUFFER] = onWriteBuffer;
|
|
|
scsi_command_table[SCSI_SEND_DIAG] = onSendDiagnostic;
|
|
|
scsi_command_table[SCSI_READ_DEFECT_DATA] = onReadDefectData;
|
|
|
+ scsi_command_table[SCSI_READ_TOC] = onReadTOC;
|
|
|
+ scsi_command_table[SCSI_READ_DVD_STRUCTURE] = onReadDVDStructure;
|
|
|
+ scsi_command_table[SCSI_READ_DISC_INFORMATION] = onReadDiscInformation;
|
|
|
|
|
|
// clear and initialize default inquiry blocks
|
|
|
// default SCSI HDD
|
|
|
@@ -462,85 +539,116 @@ void findDriveImages(FsFile root) {
|
|
|
// Valid file, open for reading/writing.
|
|
|
file = new FsFile(SD.open(name, O_RDWR));
|
|
|
if(file && file->isFile()) {
|
|
|
- if(tolower(name[0]) == 'h' && tolower(name[1]) == 'd') {
|
|
|
- // Defaults for Hard Disks
|
|
|
- int id = 1; // 0 and 3 are common in Macs for physical HD and CD, so avoid them.
|
|
|
- int lun = 0;
|
|
|
- int blk = 512;
|
|
|
-
|
|
|
- // Positionally read in and coerase the chars to integers.
|
|
|
- // We only require the minimum and read in the next if provided.
|
|
|
- int file_name_length = strlen(name);
|
|
|
- if(file_name_length > 2) { // HD[N]
|
|
|
- int tmp_id = name[HDIMG_ID_POS] - '0';
|
|
|
-
|
|
|
- // If valid id, set it, else use default
|
|
|
- if(tmp_id > -1 && tmp_id < 8) {
|
|
|
- id = tmp_id;
|
|
|
- } else {
|
|
|
- LOG_FILE.print(name);
|
|
|
- LOG_FILE.println(" - bad SCSI id in filename, Using default ID 1");
|
|
|
- }
|
|
|
+ SCSI_DEVICE_TYPE device_type;
|
|
|
+ if(tolower(name[1]) != 'd') {
|
|
|
+ file->close();
|
|
|
+ delete file;
|
|
|
+ LOG_FILE.print("Not an image: ");
|
|
|
+ LOG_FILE.println(name);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (tolower(name[0])) {
|
|
|
+ case 'h': device_type = SCSI_DEVICE_HDD;
|
|
|
+ break;
|
|
|
+ case 'c': device_type = SCSI_DEVICE_OPTICAL;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ file->close();
|
|
|
+ delete file;
|
|
|
+ LOG_FILE.print("Not an image: ");
|
|
|
+ LOG_FILE.println(name);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Defaults for Hard Disks
|
|
|
+ int id = 1; // 0 and 3 are common in Macs for physical HD and CD, so avoid them.
|
|
|
+ int lun = 0;
|
|
|
+ int blk = 512;
|
|
|
+
|
|
|
+ // Positionally read in and coerase the chars to integers.
|
|
|
+ // We only require the minimum and read in the next if provided.
|
|
|
+ int file_name_length = strlen(name);
|
|
|
+ if(file_name_length > 2) { // HD[N]
|
|
|
+ int tmp_id = name[HDIMG_ID_POS] - '0';
|
|
|
+
|
|
|
+ // If valid id, set it, else use default
|
|
|
+ if(tmp_id > -1 && tmp_id < 8) {
|
|
|
+ id = tmp_id;
|
|
|
+ } else {
|
|
|
+ LOG_FILE.print(name);
|
|
|
+ LOG_FILE.println(" - bad SCSI id in filename, Using default ID 1");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if(file_name_length > 3) { // HDN[N]
|
|
|
- int tmp_lun = name[HDIMG_LUN_POS] - '0';
|
|
|
+ if(file_name_length > 3) { // HDN[N]
|
|
|
+ int tmp_lun = name[HDIMG_LUN_POS] - '0';
|
|
|
|
|
|
- // If valid lun, set it, else use default
|
|
|
- if(tmp_lun == 0 || tmp_lun == 1) {
|
|
|
- lun = tmp_lun;
|
|
|
- } else {
|
|
|
- LOG_FILE.print(name);
|
|
|
- LOG_FILE.println(" - bad SCSI LUN in filename, Using default LUN ID 0");
|
|
|
- }
|
|
|
+ // If valid lun, set it, else use default
|
|
|
+ if(tmp_lun == 0 || tmp_lun == 1) {
|
|
|
+ lun = tmp_lun;
|
|
|
+ } else {
|
|
|
+ LOG_FILE.print(name);
|
|
|
+ LOG_FILE.println(" - bad SCSI LUN in filename, Using default LUN ID 0");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- int blk1 = 0, blk2, blk3, blk4 = 0;
|
|
|
- if(file_name_length > 8) { // HD00_[111]
|
|
|
- blk1 = name[HDIMG_BLK_POS] - '0';
|
|
|
- blk2 = name[HDIMG_BLK_POS+1] - '0';
|
|
|
- blk3 = name[HDIMG_BLK_POS+2] - '0';
|
|
|
- if(file_name_length > 9) // HD00_NNN[1]
|
|
|
- blk4 = name[HDIMG_BLK_POS+3] - '0';
|
|
|
- }
|
|
|
- if(blk1 == 2 && blk2 == 5 && blk3 == 6) {
|
|
|
- blk = 256;
|
|
|
- } else if(blk1 == 1 && blk2 == 0 && blk3 == 2 && blk4 == 4) {
|
|
|
- blk = 1024;
|
|
|
- } else if(blk1 == 2 && blk2 == 0 && blk3 == 4 && blk4 == 8) {
|
|
|
- blk = 2048;
|
|
|
- }
|
|
|
+ int blk1 = 0, blk2, blk3, blk4 = 0;
|
|
|
+ if(file_name_length > 8) { // HD00_[111]
|
|
|
+ blk1 = name[HDIMG_BLK_POS] - '0';
|
|
|
+ blk2 = name[HDIMG_BLK_POS+1] - '0';
|
|
|
+ blk3 = name[HDIMG_BLK_POS+2] - '0';
|
|
|
+ if(file_name_length > 9) // HD00_NNN[1]
|
|
|
+ blk4 = name[HDIMG_BLK_POS+3] - '0';
|
|
|
+ }
|
|
|
+ if(blk1 == 2 && blk2 == 5 && blk3 == 6) {
|
|
|
+ blk = 256;
|
|
|
+ } else if(blk1 == 1 && blk2 == 0 && blk3 == 2 && blk4 == 4) {
|
|
|
+ blk = 1024;
|
|
|
+ } else if(blk1 == 2 && blk2 == 0 && blk3 == 4 && blk4 == 8) {
|
|
|
+ blk = 2048;
|
|
|
+ }
|
|
|
|
|
|
- if(id < NUM_SCSIID && lun < NUM_SCSILUN) {
|
|
|
- dev = &scsi_device_list[id][lun];
|
|
|
- LOG_FILE.print(" - ");
|
|
|
- LOG_FILE.print(name);
|
|
|
- image_ready = hddimageOpen(dev, file, id, lun, blk);
|
|
|
- if(image_ready) { // Marked as a responsive ID
|
|
|
- scsi_id_mask |= 1<<id;
|
|
|
+ if(id < NUM_SCSIID && lun < NUM_SCSILUN) {
|
|
|
+ dev = &scsi_device_list[id][lun];
|
|
|
+ LOG_FILE.print(" - ");
|
|
|
+ LOG_FILE.print(name);
|
|
|
+ dev->m_type = device_type;
|
|
|
+ image_ready = hddimageOpen(dev, file, id, lun, blk);
|
|
|
+ if(image_ready) { // Marked as a responsive ID
|
|
|
+ scsi_id_mask |= 1<<id;
|
|
|
+
|
|
|
+ switch(dev->m_type)
|
|
|
+ {
|
|
|
+ case SCSI_DEVICE_HDD:
|
|
|
+ // default SCSI HDD
|
|
|
+ dev->inquiry_block.ansi_version = 1;
|
|
|
+ dev->inquiry_block.response_format = 1;
|
|
|
+ dev->inquiry_block.additional_length = 31;
|
|
|
+ memcpy(dev->inquiry_block.vendor, "QUANTUM", 7);
|
|
|
+ memcpy(dev->inquiry_block.product, "FIREBALL1", 9);
|
|
|
+ memcpy(dev->inquiry_block.revision, "1.0", 3);
|
|
|
+ break;
|
|
|
|
|
|
- switch(dev->m_type)
|
|
|
- {
|
|
|
- case SCSI_DEVICE_HDD:
|
|
|
- // default SCSI HDD
|
|
|
- dev->inquiry_block = &default_hdd;
|
|
|
- break;
|
|
|
-
|
|
|
- case SCSI_DEVICE_OPTICAL:
|
|
|
- // default SCSI CDROM
|
|
|
- dev->inquiry_block = &default_optical;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- readSCSIDeviceConfig(dev);
|
|
|
+ case SCSI_DEVICE_OPTICAL:
|
|
|
+ // default SCSI CDROM
|
|
|
+ dev->inquiry_block.peripheral_device_type = 5;
|
|
|
+ dev->inquiry_block.rmb = 1;
|
|
|
+ dev->inquiry_block.ansi_version = 1;
|
|
|
+ dev->inquiry_block.response_format = 1;
|
|
|
+ dev->inquiry_block.additional_length = 42;
|
|
|
+ dev->inquiry_block.sync = 1;
|
|
|
+ memcpy(dev->inquiry_block.vendor, "BLUESCSI", 8);
|
|
|
+ memcpy(dev->inquiry_block.product, "CD-ROM CDU-55S", 14);
|
|
|
+ memcpy(dev->inquiry_block.revision, "1.9a", 4);
|
|
|
+ dev->inquiry_block.release = 0x20;
|
|
|
+ memcpy(dev->inquiry_block.revision_date, "1995", 4);
|
|
|
+ break;
|
|
|
}
|
|
|
+
|
|
|
+ readSCSIDeviceConfig(dev);
|
|
|
}
|
|
|
- }
|
|
|
- } else {
|
|
|
- file->close();
|
|
|
- delete file;
|
|
|
- LOG_FILE.print("Not an image: ");
|
|
|
- LOG_FILE.println(name);
|
|
|
+ }
|
|
|
}
|
|
|
LOG_FILE.sync();
|
|
|
}
|
|
|
@@ -815,7 +923,7 @@ void writeDataLoop(uint32_t blocksize, const byte* srcptr)
|
|
|
*/
|
|
|
void writeDataPhase(int len, const byte* p)
|
|
|
{
|
|
|
- LOGN("DATAIN PHASE");
|
|
|
+ LOG(" DI ");
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_DATAIN);
|
|
|
// Bus settle delay 400ns. Following code was measured at 800ns before REQ asserted. STM32F103.
|
|
|
#ifdef XCVR
|
|
|
@@ -831,17 +939,16 @@ void writeDataPhase(int len, const byte* p)
|
|
|
*/
|
|
|
void writeDataPhaseSD(SCSI_DEVICE *dev, uint32_t adds, uint32_t len)
|
|
|
{
|
|
|
- LOGN("DATAIN PHASE(SD)");
|
|
|
+ LOG (" DI(SD) ");
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_DATAIN);
|
|
|
//Bus settle delay 400ns, file.seek() measured at over 1000ns.
|
|
|
-
|
|
|
uint64_t pos = (uint64_t)adds * dev->m_blocksize;
|
|
|
dev->m_file->seekSet(pos);
|
|
|
-
|
|
|
#ifdef XCVR
|
|
|
TRANSCEIVER_IO_SET(vTR_DBP,TR_OUTPUT)
|
|
|
#endif
|
|
|
SCSI_DB_OUTPUT()
|
|
|
+
|
|
|
for(uint32_t i = 0; i < len; i++) {
|
|
|
// Asynchronous reads will make it faster ...
|
|
|
m_resetJmp = false;
|
|
|
@@ -900,7 +1007,7 @@ void readDataLoop(uint32_t blockSize, byte* dstptr)
|
|
|
*/
|
|
|
void readDataPhase(int len, byte* p)
|
|
|
{
|
|
|
- LOGN("DATAOUT PHASE");
|
|
|
+ LOG(" DO ");
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_DATAOUT);
|
|
|
// Bus settle delay 400ns. The following code was measured at 450ns before REQ asserted. STM32F103.
|
|
|
readDataLoop(len, p);
|
|
|
@@ -912,7 +1019,7 @@ void readDataPhase(int len, byte* p)
|
|
|
*/
|
|
|
void readDataPhaseSD(SCSI_DEVICE *dev, uint32_t adds, uint32_t len)
|
|
|
{
|
|
|
- LOGN("DATAOUT PHASE(SD)");
|
|
|
+ LOG(" DO(SD) ");
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_DATAOUT);
|
|
|
//Bus settle delay 400ns, file.seek() measured at over 1000ns.
|
|
|
|
|
|
@@ -938,7 +1045,7 @@ void readDataPhaseSD(SCSI_DEVICE *dev, uint32_t adds, uint32_t len)
|
|
|
*/
|
|
|
void verifyDataPhaseSD(SCSI_DEVICE *dev, uint32_t adds, uint32_t len)
|
|
|
{
|
|
|
- LOGN("DATAOUT PHASE(SD)");
|
|
|
+ LOG(" DO(SD) ");
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_DATAOUT);
|
|
|
//Bus settle delay 400ns, file.seek() measured at over 1000ns.
|
|
|
|
|
|
@@ -956,7 +1063,7 @@ void verifyDataPhaseSD(SCSI_DEVICE *dev, uint32_t adds, uint32_t len)
|
|
|
*/
|
|
|
void MsgIn2(int msg)
|
|
|
{
|
|
|
- LOGN("MsgIn2");
|
|
|
+ LOG(" MI:"); LOGHEX(msg); LOG(" ");
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_MESSAGEIN);
|
|
|
// Bus settle delay 400ns built in to writeHandshake
|
|
|
writeHandshake(msg);
|
|
|
@@ -993,7 +1100,7 @@ void loop()
|
|
|
delayMicroseconds(1);
|
|
|
return;
|
|
|
}
|
|
|
- LOGN("Selection");
|
|
|
+ LOG(" S ");
|
|
|
m_isBusReset = false;
|
|
|
if (setjmp(m_resetJmpBuf) == 1) {
|
|
|
LOGN("Reset, going to BusFree");
|
|
|
@@ -1020,6 +1127,7 @@ void loop()
|
|
|
|
|
|
//
|
|
|
if(isHigh(gpio_read(ATN))) {
|
|
|
+ LOG(" MO:");
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_MESSAGEOUT);
|
|
|
// Bus settle delay 400ns. Following code was measured at 350ns before REQ asserted. Added another 50ns. STM32F103.
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_MESSAGEOUT);// 28ns delay STM32F103
|
|
|
@@ -1032,6 +1140,7 @@ void loop()
|
|
|
m_msb[msc++] = readHandshake();
|
|
|
}
|
|
|
for(int i = 0; i < msc; i++) {
|
|
|
+ LOGHEX(m_msb[i]); LOG(":");
|
|
|
// ABORT
|
|
|
if (m_msb[i] == 0x06) {
|
|
|
goto BusFree;
|
|
|
@@ -1081,7 +1190,7 @@ void loop()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- LOG("Command:");
|
|
|
+ LOG(" CMD:");
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_COMMAND);
|
|
|
// Bus settle delay 400ns. The following code was measured at 20ns before REQ asserted. Added another 380ns. STM32F103.
|
|
|
asm("nop;nop;nop;nop;nop;nop;nop;nop");// This asm causes some code reodering, which adds 270ns, plus 8 nop cycles for an additional 110ns. STM32F103
|
|
|
@@ -1115,7 +1224,7 @@ void loop()
|
|
|
LOG(m_id);
|
|
|
LOG(":LUN ");
|
|
|
LOG(m_lun);
|
|
|
- LOGN("");
|
|
|
+ LOG(" ");
|
|
|
|
|
|
dev = &(scsi_device_list[m_id][m_lun]);
|
|
|
// HDD Image selection
|
|
|
@@ -1133,7 +1242,7 @@ void loop()
|
|
|
if(cmd[0] == SCSI_INQUIRY)
|
|
|
{
|
|
|
// Special INQUIRY handling for invalid LUNs
|
|
|
- LOGN("onInquiry - InvalidLUN");
|
|
|
+ LOG(" onInquiry-InvalidLUN ");
|
|
|
dev = &(scsi_device_list[m_id][0]);
|
|
|
|
|
|
byte temp = dev->inquiry_block.raw[0];
|
|
|
@@ -1157,18 +1266,17 @@ void loop()
|
|
|
LED_OFF();
|
|
|
|
|
|
Status:
|
|
|
- LOGN("Sts");
|
|
|
+ LOG(" S:"); LOGHEX(m_sts);
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_STATUS);
|
|
|
// Bus settle delay 400ns built in to writeHandshake
|
|
|
writeHandshake(m_sts);
|
|
|
|
|
|
- LOGN("MsgIn");
|
|
|
+ LOG(" MI:"); LOGHEX(m_msg);
|
|
|
SCSI_PHASE_CHANGE(SCSI_PHASE_MESSAGEIN);
|
|
|
// Bus settle delay 400ns built in to writeHandshake
|
|
|
writeHandshake(m_msg);
|
|
|
-
|
|
|
BusFree:
|
|
|
- LOGN("BusFree");
|
|
|
+ LOGN(" BF");
|
|
|
m_isBusReset = false;
|
|
|
//SCSI_OUT(vREQ,inactive) // gpio_write(REQ, low);
|
|
|
//SCSI_OUT(vMSG,inactive) // gpio_write(MSG, low);
|
|
|
@@ -1213,7 +1321,7 @@ static byte onNOP(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
*/
|
|
|
byte onInquiry(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
{
|
|
|
- writeDataPhase(cdb[4] < 36 ? cdb[4] : 36, dev->inquiry_block->raw);
|
|
|
+ writeDataPhase(cdb[4] < 47 ? cdb[4] : 47, dev->inquiry_block.raw);
|
|
|
return SCSI_STATUS_GOOD;
|
|
|
}
|
|
|
|
|
|
@@ -1267,6 +1375,9 @@ byte checkBlockCommand(SCSI_DEVICE *dev, uint32_t adds, uint32_t len)
|
|
|
{
|
|
|
// Check block range is valid
|
|
|
if (adds >= dev->m_blockcount || (adds + len) > dev->m_blockcount) {
|
|
|
+ LOG(dev->m_blockcount);
|
|
|
+ if(adds >= dev->m_additional_sense_code) { LOGN(" first "); }
|
|
|
+ if((adds + len) > dev->m_blockcount) { LOGN(" second "); }
|
|
|
dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST;
|
|
|
dev->m_additional_sense_code = SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
|
|
|
return SCSI_STATUS_CHECK_CONDITION;
|
|
|
@@ -1302,13 +1413,14 @@ static byte onRead10(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
{
|
|
|
unsigned adds = ((uint32_t)cdb[2] << 24) | ((uint32_t)cdb[3] << 16) | ((uint32_t)cdb[4] << 8) | cdb[5];
|
|
|
unsigned len = ((uint32_t)cdb[7] << 8) | cdb[8];
|
|
|
- /*
|
|
|
- LOGN("onRead10");
|
|
|
- LOG("-R ");
|
|
|
+
|
|
|
+ LOG (" Read10 ");
|
|
|
+ LOG("A:");
|
|
|
LOGHEX(adds);
|
|
|
LOG(":");
|
|
|
- LOGHEXN(len);
|
|
|
- */
|
|
|
+ LOGHEX(len);
|
|
|
+ LOG(" ");
|
|
|
+
|
|
|
byte sts = checkBlockCommand(dev, adds, len);
|
|
|
if (sts) {
|
|
|
return sts;
|
|
|
@@ -1403,15 +1515,34 @@ byte onVerify(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
*/
|
|
|
byte onModeSense(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
{
|
|
|
- memset(m_buf, 0, sizeof(m_buf));
|
|
|
int pageCode = cdb[2] & 0x3F;
|
|
|
int pageControl = cdb[2] >> 6;
|
|
|
- int a = 4;
|
|
|
- byte dbd = cdb[1] & 0x08;
|
|
|
+ byte dbd = cdb[1] & 0x8;
|
|
|
+ byte block_descriptor_length = 8;
|
|
|
+
|
|
|
+ // saving parameters is not allowed...yet!
|
|
|
+ if(pageControl == 3)
|
|
|
+ {
|
|
|
+ dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST;
|
|
|
+ dev->m_additional_sense_code = SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED;
|
|
|
+ return SCSI_STATUS_CHECK_CONDITION;
|
|
|
+ }
|
|
|
|
|
|
- if(cdb[0] == SCSI_MODE_SENSE10) a = 8;
|
|
|
+ // SCSI_MODE_SENSE6
|
|
|
+ int a = 4;
|
|
|
+ int length = cdb[4];
|
|
|
|
|
|
- if(dbd == 0) {
|
|
|
+ if(cdb[0] == SCSI_MODE_SENSE10) {
|
|
|
+ a = 8;
|
|
|
+ length = cdb[7];
|
|
|
+ length <<= 8;
|
|
|
+ length |= cdb[8];
|
|
|
+ if(length > 0x800) { length = 0x800; };
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(m_buf, 0, length);
|
|
|
+
|
|
|
+ if(!dbd && dev->m_type != SCSI_DEVICE_OPTICAL) {
|
|
|
byte c[8] = {
|
|
|
0,//Density code
|
|
|
dev->m_blockcount >> 16,
|
|
|
@@ -1425,95 +1556,183 @@ byte onModeSense(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
memcpy(&m_buf[a], c, 8);
|
|
|
a += 8;
|
|
|
}
|
|
|
- switch(pageCode) {
|
|
|
- case SCSI_SENSE_MODE_ALL:
|
|
|
- case SCSI_SENSE_MODE_READ_WRITE_ERROR_RECOVERY:
|
|
|
- m_buf[a + 0] = SCSI_SENSE_MODE_READ_WRITE_ERROR_RECOVERY;
|
|
|
- m_buf[a + 1] = 0x0A;
|
|
|
- a += 0x0C;
|
|
|
- if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
-
|
|
|
- case SCSI_SENSE_MODE_DISCONNECT_RECONNECT:
|
|
|
- m_buf[a + 0] = SCSI_SENSE_MODE_DISCONNECT_RECONNECT;
|
|
|
- m_buf[a + 1] = 0x0A;
|
|
|
- a += 0x0C;
|
|
|
- if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
-
|
|
|
- case SCSI_SENSE_MODE_FORMAT_DEVICE: //Drive parameters
|
|
|
- m_buf[a + 0] = SCSI_SENSE_MODE_FORMAT_DEVICE; //Page code
|
|
|
- m_buf[a + 1] = 0x16; // Page length
|
|
|
- if(pageControl != 1) {
|
|
|
- m_buf[a + 11] = 0x3F;//Number of sectors / track
|
|
|
- m_buf[a + 12] = (byte)(dev->m_blocksize >> 8);
|
|
|
- m_buf[a + 13] = (byte)dev->m_blocksize;
|
|
|
- m_buf[a + 15] = 0x1; // Interleave
|
|
|
- }
|
|
|
- a += 0x18;
|
|
|
- if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
-
|
|
|
- case SCSI_SENSE_MODE_DISK_GEOMETRY: //Drive parameters
|
|
|
- m_buf[a + 0] = SCSI_SENSE_MODE_DISK_GEOMETRY; //Page code
|
|
|
- m_buf[a + 1] = 0x16; // Page length
|
|
|
- if(pageControl != 1) {
|
|
|
- unsigned cylinders = dev->m_blockcount / (16 * 63);
|
|
|
- m_buf[a + 2] = (byte)(cylinders >> 16); // Cylinders
|
|
|
- m_buf[a + 3] = (byte)(cylinders >> 8);
|
|
|
- m_buf[a + 4] = (byte)cylinders;
|
|
|
- m_buf[a + 5] = 16; //Number of heads
|
|
|
- }
|
|
|
- a += 0x18;
|
|
|
- if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
- case SCSI_SENSE_MODE_FLEXABLE_GEOMETRY:
|
|
|
- m_buf[a + 0] = SCSI_SENSE_MODE_FLEXABLE_GEOMETRY;
|
|
|
- m_buf[a + 1] = 0x1E; // Page length
|
|
|
- if(pageControl != 1) {
|
|
|
- m_buf[a + 2] = 0x03;
|
|
|
- m_buf[a + 3] = 0xE8; // Transfer rate 1 mbit/s
|
|
|
- m_buf[a + 4] = 16; // Number of heads
|
|
|
- m_buf[a + 5] = 18; // Sectors per track
|
|
|
- m_buf[a + 6] = (byte)dev->m_blocksize >> 8;
|
|
|
- m_buf[a + 7] = (byte)dev->m_blocksize & 0xff; // Data bytes per sector
|
|
|
- }
|
|
|
- a += 0x20;
|
|
|
- if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
- case SCSI_SENSE_MODE_CACHING:
|
|
|
- m_buf[a + 0] = SCSI_SENSE_MODE_CACHING;
|
|
|
- m_buf[a + 1] = 0x0A; // Page length
|
|
|
- if(pageControl != 1) {
|
|
|
- m_buf[a + 2] = 0x01; // Disalbe Read Cache so no one asks for Cache Stats page.
|
|
|
- }
|
|
|
- a += 0x08;
|
|
|
- if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
- case SCSI_SENSE_MODE_VENDOR_APPLE:
|
|
|
- {
|
|
|
- const byte page30[0x14] = {0x41, 0x50, 0x50, 0x4C, 0x45, 0x20, 0x43, 0x4F, 0x4D, 0x50, 0x55, 0x54, 0x45, 0x52, 0x2C, 0x20, 0x49, 0x4E, 0x43, 0x20};
|
|
|
- m_buf[a + 0] = SCSI_SENSE_MODE_VENDOR_APPLE; // Page code
|
|
|
- m_buf[a + 1] = sizeof(page30); // Page length
|
|
|
+
|
|
|
+ // HDD supports page codes 0x1 (Read/Write), 0x2, 0x3, 0x4
|
|
|
+ // CDROM supports page codes 0x1 (Read Only), 0x2, 0xD, 0xE, 0x30
|
|
|
+ if(dev->m_type == SCSI_DEVICE_HDD) {
|
|
|
+ switch(pageCode) {
|
|
|
+ case SCSI_SENSE_MODE_ALL:
|
|
|
+ case SCSI_SENSE_MODE_READ_WRITE_ERROR_RECOVERY:
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_READ_WRITE_ERROR_RECOVERY;
|
|
|
+ m_buf[a + 1] = 0x0A;
|
|
|
+ a += 0x0C;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+
|
|
|
+ case SCSI_SENSE_MODE_DISCONNECT_RECONNECT:
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_DISCONNECT_RECONNECT;
|
|
|
+ m_buf[a + 1] = 0x0A;
|
|
|
+ a += 0x0C;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+
|
|
|
+ case SCSI_SENSE_MODE_FORMAT_DEVICE: //Drive parameters
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_FORMAT_DEVICE; //Page code
|
|
|
+ m_buf[a + 1] = 0x16; // Page length
|
|
|
+ if(pageControl != 1) {
|
|
|
+ m_buf[a + 11] = 0x3F;//Number of sectors / track
|
|
|
+ m_buf[a + 12] = (byte)(dev->m_blocksize >> 8);
|
|
|
+ m_buf[a + 13] = (byte)dev->m_blocksize;
|
|
|
+ m_buf[a + 15] = 0x1; // Interleave
|
|
|
+ }
|
|
|
+ a += 0x18;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+
|
|
|
+ case SCSI_SENSE_MODE_DISK_GEOMETRY: //Drive parameters
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_DISK_GEOMETRY; //Page code
|
|
|
+ m_buf[a + 1] = 0x16; // Page length
|
|
|
+ if(pageControl != 1) {
|
|
|
+ unsigned cylinders = dev->m_blockcount / (16 * 63);
|
|
|
+ if(pageControl != 1) {
|
|
|
+ m_buf[a + 2] = (byte)(cylinders >> 16); // Cylinders
|
|
|
+ m_buf[a + 3] = (byte)(cylinders >> 8);
|
|
|
+ m_buf[a + 4] = (byte)cylinders;
|
|
|
+ m_buf[a + 5] = 16; //Number of heads
|
|
|
+ } else {
|
|
|
+ m_buf[a + 2] = 0xFF; // Cylinder length
|
|
|
+ m_buf[a + 3] = 0xFF;
|
|
|
+ m_buf[a + 4] = 0xFF;
|
|
|
+ m_buf[a + 5] = 16; //Number of heads
|
|
|
+ }
|
|
|
+ }
|
|
|
+ a += 0x18;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+ case SCSI_SENSE_MODE_FLEXABLE_GEOMETRY:
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_FLEXABLE_GEOMETRY;
|
|
|
+ m_buf[a + 1] = 0x1E; // Page length
|
|
|
+ if(pageControl != 1) {
|
|
|
+ m_buf[a + 2] = 0x03;
|
|
|
+ m_buf[a + 3] = 0xE8; // Transfer rate 1 mbit/s
|
|
|
+ m_buf[a + 4] = 16; // Number of heads
|
|
|
+ m_buf[a + 5] = 63; // Sectors per track
|
|
|
+ m_buf[a + 6] = (byte)dev->m_blocksize >> 8;
|
|
|
+ m_buf[a + 7] = (byte)dev->m_blocksize & 0xff; // Data bytes per sector
|
|
|
+ }
|
|
|
+ a += 0x20;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+ case SCSI_SENSE_MODE_CACHING:
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_CACHING;
|
|
|
+ m_buf[a + 1] = 0x0A; // Page length
|
|
|
if(pageControl != 1) {
|
|
|
- memcpy(&m_buf[a + 2], page30, sizeof(page30));
|
|
|
+ m_buf[a + 2] = 0x01; // Disalbe Read Cache so no one asks for Cache Stats page.
|
|
|
}
|
|
|
- a += 2 + sizeof(page30);
|
|
|
+ a += 0x0C;
|
|
|
if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+ case SCSI_SENSE_MODE_VENDOR_APPLE:
|
|
|
+ {
|
|
|
+ const byte apple_magic[0x24] = {
|
|
|
+ 0x23,
|
|
|
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
+ 0x00, 0x08, 0x00, 0x30, 0x16, 0x41, 0x50, 0x50,
|
|
|
+ 0x4C, 0x45, 0x20, 0x43, 0x4F, 0x4D, 0x50, 0x55,
|
|
|
+ 0x54, 0x45, 0x52, 0x2C, 0x20, 0x49, 0x4E, 0x43,
|
|
|
+ 0x20, 0x20, 0x20
|
|
|
+ };
|
|
|
+ if(pageControl != 1) {
|
|
|
+ memcpy(&m_buf[0], apple_magic, sizeof(apple_magic));
|
|
|
+ }
|
|
|
+ a = sizeof(apple_magic);
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+ }
|
|
|
+ break; // Don't want SCSI_SENSE_MODE_ALL falling through to error condition
|
|
|
+
|
|
|
+ default:
|
|
|
+ dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST;
|
|
|
+ dev->m_additional_sense_code = SCSI_ASC_INVALID_FIELD_IN_CDB;
|
|
|
+ return SCSI_STATUS_CHECK_CONDITION;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // OPTICAL
|
|
|
+ block_descriptor_length = 0;
|
|
|
+ if(cdb[0] == SCSI_MODE_SENSE6) {
|
|
|
+ m_buf[2] = 1 << 7; // WP bit
|
|
|
+ } else {
|
|
|
+ m_buf[3] = 1 << 7; // WP bit
|
|
|
}
|
|
|
- break; // Don't want SCSI_SENSE_MODE_ALL falling through to error condition
|
|
|
|
|
|
- default:
|
|
|
- dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST;
|
|
|
- dev->m_additional_sense_code = SCSI_ASC_INVALID_FIELD_IN_CDB;
|
|
|
- return SCSI_STATUS_CHECK_CONDITION;
|
|
|
- break;
|
|
|
- }
|
|
|
- if(cdb[0] == SCSI_MODE_SENSE10)
|
|
|
- {
|
|
|
- m_buf[1] = a - 2;
|
|
|
- m_buf[7] = 0x08;
|
|
|
+ switch(pageCode) {
|
|
|
+ case SCSI_SENSE_MODE_ALL:
|
|
|
+ case SCSI_SENSE_MODE_READ_WRITE_ERROR_RECOVERY:
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_READ_WRITE_ERROR_RECOVERY;
|
|
|
+ m_buf[a + 1] = 0x06;
|
|
|
+ a += 0x08;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+
|
|
|
+ case SCSI_SENSE_MODE_DISCONNECT_RECONNECT:
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_DISCONNECT_RECONNECT;
|
|
|
+ m_buf[a + 1] = 0x0A;
|
|
|
+ a += 0x0C;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+
|
|
|
+ case SCSI_SENSE_MODE_CDROM:
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_CDROM;
|
|
|
+ m_buf[a + 1] = 0x06;
|
|
|
+ if(pageControl != 1)
|
|
|
+ {
|
|
|
+ // 2 seconds for inactive timer
|
|
|
+ m_buf[a + 3] = 0x05;
|
|
|
+ // MSF multiples are 60 and 75
|
|
|
+ m_buf[a + 5] = 60;
|
|
|
+ m_buf[a + 7] = 75;
|
|
|
+ }
|
|
|
+ a += 0x8;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+
|
|
|
+ case SCSI_SENSE_MODE_CDROM_AUDIO_CONTROL:
|
|
|
+ m_buf[a + 0] = SCSI_SENSE_MODE_CDROM_AUDIO_CONTROL;
|
|
|
+ m_buf[a + 1] = 0x0E;
|
|
|
+
|
|
|
+ a += 0x10;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+
|
|
|
+ case SCSI_SENSE_MODE_VENDOR_APPLE:
|
|
|
+ {
|
|
|
+ const byte apple_magic[0x24] = {
|
|
|
+ 0x23,
|
|
|
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
+ 0x00, 0x08, 0x00, 0x30, 0x16, 0x41, 0x50, 0x50,
|
|
|
+ 0x4C, 0x45, 0x20, 0x43, 0x4F, 0x4D, 0x50, 0x55,
|
|
|
+ 0x54, 0x45, 0x52, 0x2C, 0x20, 0x49, 0x4E, 0x43,
|
|
|
+ 0x20, 0x20, 0x20
|
|
|
+ };
|
|
|
+ if(pageControl != 1) {
|
|
|
+ memcpy(&m_buf[0], apple_magic, sizeof(apple_magic));
|
|
|
+ }
|
|
|
+ a = sizeof(apple_magic);
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_ALL) break;
|
|
|
+ }
|
|
|
+ break; // Don't want SCSI_SENSE_MODE_ALL falling through to error condition
|
|
|
+
|
|
|
+ default:
|
|
|
+ dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST;
|
|
|
+ dev->m_additional_sense_code = SCSI_ASC_INVALID_FIELD_IN_CDB;
|
|
|
+ return SCSI_STATUS_CHECK_CONDITION;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- m_buf[0] = a - 1;
|
|
|
- m_buf[3] = 0x08;
|
|
|
+ if(pageCode != SCSI_SENSE_MODE_VENDOR_APPLE) {
|
|
|
+ if(cdb[0] == SCSI_MODE_SENSE10)
|
|
|
+ {
|
|
|
+ m_buf[1] = a - 2;
|
|
|
+ m_buf[7] = block_descriptor_length; // block descriptor length
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ m_buf[0] = a - 1;
|
|
|
+ m_buf[3] = block_descriptor_length; // block descriptor length
|
|
|
+ }
|
|
|
}
|
|
|
- writeDataPhase(cdb[4] < a ? cdb[4] : a, m_buf);
|
|
|
+
|
|
|
+ writeDataPhase(length < a ? length : a, m_buf);
|
|
|
return SCSI_STATUS_GOOD;
|
|
|
}
|
|
|
|
|
|
@@ -1522,7 +1741,8 @@ byte onModeSelect(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
unsigned length = 0;
|
|
|
LOGN("onModeSelect");
|
|
|
|
|
|
- if(dev->m_type != SCSI_DEVICE_HDD && (cdb[1] & 0x01))
|
|
|
+ // saving mode pages isn't supported yet
|
|
|
+ if(cdb[1] & 0x01)
|
|
|
{
|
|
|
dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST;
|
|
|
dev->m_additional_sense_code = SCSI_ASC_INVALID_FIELD_IN_CDB;
|
|
|
@@ -1540,6 +1760,7 @@ byte onModeSelect(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
if(length > 0x800) { length = 0x800; }
|
|
|
}
|
|
|
|
|
|
+ memset(m_buf, 0, length);
|
|
|
readDataPhase(length, m_buf);
|
|
|
//Apple HD SC Setup sends:
|
|
|
//0 0 0 8 0 0 0 0 0 0 2 0 0 2 10 0 1 6 24 10 8 0 0 0
|
|
|
@@ -1697,6 +1918,7 @@ byte onReadDefectData(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
return SCSI_STATUS_GOOD;
|
|
|
}
|
|
|
|
|
|
+<<<<<<< HEAD
|
|
|
<<<<<<< HEAD
|
|
|
/*
|
|
|
* MsgIn2.
|
|
|
@@ -1955,3 +2177,108 @@ BusFree:
|
|
|
}
|
|
|
=======
|
|
|
>>>>>>> faed60f (code layout adjustments)
|
|
|
+=======
|
|
|
+static byte onReadTOC(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
+{
|
|
|
+ unsigned lba = 0;
|
|
|
+ uint8_t msf = cdb[1] & 0x02;
|
|
|
+ uint8_t track = cdb[6];
|
|
|
+ unsigned len = ((uint32_t)cdb[7] << 8) | cdb[8];
|
|
|
+ memset(m_buf, 0, len);
|
|
|
+
|
|
|
+ // Doing just the error seemed to make MacOS unhappy
|
|
|
+#if 0
|
|
|
+ dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST;
|
|
|
+ dev->m_additional_sense_code = SCSI_ASC_INVALID_FIELD_IN_CDB;
|
|
|
+ return SCSI_STATUS_CHECK_CONDITION;
|
|
|
+#endif
|
|
|
+
|
|
|
+ if(track > 1 || cdb[2] != 0)
|
|
|
+ {
|
|
|
+ dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST;
|
|
|
+ dev->m_additional_sense_code = SCSI_ASC_INVALID_FIELD_IN_CDB;
|
|
|
+ return SCSI_STATUS_CHECK_CONDITION;
|
|
|
+ }
|
|
|
+
|
|
|
+ m_buf[1] = 18; // TOC length LSB
|
|
|
+ m_buf[2] = 1; // First Track
|
|
|
+ m_buf[3] = 1; // Last Track
|
|
|
+
|
|
|
+ // first track
|
|
|
+ m_buf[5] = 0x14; // data track
|
|
|
+ m_buf[6] = 1;
|
|
|
+
|
|
|
+ // leadout track
|
|
|
+ m_buf[13] = 0x14; // data track
|
|
|
+ m_buf[14] = 0xaa; // leadout track
|
|
|
+ if(msf)
|
|
|
+ {
|
|
|
+ LBAtoMSF(dev->m_blockcount, &m_buf[16]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ m_buf[16] = (byte)(dev->m_blockcount >> 24);
|
|
|
+ m_buf[17] = (byte)(dev->m_blockcount >> 16);
|
|
|
+ m_buf[18] = (byte)(dev->m_blockcount >> 8);
|
|
|
+ m_buf[20] = (byte)(dev->m_blockcount);
|
|
|
+ }
|
|
|
+
|
|
|
+ writeDataPhase(SCSI_TOC_LENGTH > len ? len : SCSI_TOC_LENGTH, m_buf);
|
|
|
+ return SCSI_STATUS_GOOD;
|
|
|
+}
|
|
|
+
|
|
|
+static byte onReadDiscInformation(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
+{
|
|
|
+ writeDataPhase((cdb[7] >> 8) | cdb[8], m_buf);
|
|
|
+ return SCSI_STATUS_GOOD;
|
|
|
+}
|
|
|
+
|
|
|
+static byte onReadDVDStructure(SCSI_DEVICE *dev, const byte *cdb)
|
|
|
+{
|
|
|
+ dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST;
|
|
|
+ dev->m_additional_sense_code = SCSI_ASC_CANNOT_READ_MEDIUM_INCOMPATIBLE_FORMAT;
|
|
|
+ return SCSI_STATUS_CHECK_CONDITION;
|
|
|
+}
|
|
|
+
|
|
|
+// Thanks RaSCSI :D
|
|
|
+// LBA→MSF Conversion
|
|
|
+static inline void LBAtoMSF(const uint32_t lba, byte *msf)
|
|
|
+{
|
|
|
+ uint32_t m, s, f;
|
|
|
+
|
|
|
+ // 75 and 75*60 get the remainder
|
|
|
+ m = lba / (75 * 60);
|
|
|
+ s = lba % (75 * 60);
|
|
|
+ f = s % 75;
|
|
|
+ s /= 75;
|
|
|
+
|
|
|
+ // The base point is M=0, S=2, F=0
|
|
|
+ s += 2;
|
|
|
+ if (s >= 60) {
|
|
|
+ s -= 60;
|
|
|
+ m++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Store
|
|
|
+ msf[0] = 0x00;
|
|
|
+ msf[1] = (byte)m;
|
|
|
+ msf[2] = (byte)s;
|
|
|
+ msf[3] = (byte)f;
|
|
|
+}
|
|
|
+
|
|
|
+static inline uint32_t MSFtoLBA(const byte *msf)
|
|
|
+{
|
|
|
+ uint32_t lba;
|
|
|
+
|
|
|
+ // 1, 75, add up in multiples of 75*60
|
|
|
+ lba = msf[1];
|
|
|
+ lba *= 60;
|
|
|
+ lba += msf[2];
|
|
|
+ lba *= 75;
|
|
|
+ lba += msf[3];
|
|
|
+
|
|
|
+ // Since the base point is M=0, S=2, F=0, subtract 150
|
|
|
+ lba -= 150;
|
|
|
+
|
|
|
+ return lba;
|
|
|
+}
|