diff --git a/DiscImageChef.Device.Report/scsi.c b/DiscImageChef.Device.Report/scsi.c index 14dfeca6..a5df20ed 100644 --- a/DiscImageChef.Device.Report/scsi.c +++ b/DiscImageChef.Device.Report/scsi.c @@ -528,3 +528,14 @@ int Seek10(int fd, unsigned char **senseBuffer, uint32_t lba) return error; } + +int TestUnitReady(int fd, unsigned char **senseBuffer) +{ + unsigned char cmd_len = 6; + char cdb[] = {SCSI_TEST_UNIT_READY, 0, 0, 0, 0, 0}; + unsigned char *buffer = malloc(0); + + int error = SendScsiCommand(fd, &cdb, cmd_len, buffer, 0, senseBuffer, SG_DXFER_NONE); + + return error; +} diff --git a/DiscImageChef.Device.Report/scsi.h b/DiscImageChef.Device.Report/scsi.h index 53539b1e..241d20b2 100644 --- a/DiscImageChef.Device.Report/scsi.h +++ b/DiscImageChef.Device.Report/scsi.h @@ -35,6 +35,7 @@ int ReadLong10(int fd, unsigned char **buffer, unsigned char **senseBuffer, int int ReadLong16(int fd, unsigned char **buffer, unsigned char **senseBuffer, int correct, uint64_t lba, uint32_t transferBytes); int Seek6(int fd, unsigned char **senseBuffer, uint32_t lba); int Seek10(int fd, unsigned char **senseBuffer, uint32_t lba); +int TestUnitReady(int fd, unsigned char **senseBuffer); typedef enum { diff --git a/DiscImageChef.Device.Report/scsi_report.c b/DiscImageChef.Device.Report/scsi_report.c index d0aefa95..a8190bd3 100644 --- a/DiscImageChef.Device.Report/scsi_report.c +++ b/DiscImageChef.Device.Report/scsi_report.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "scsi_report.h" #include "scsi.h" #include "inquiry_decode.h" @@ -254,7 +255,279 @@ void ScsiReport(int fd, xmlTextWriterPtr xmlWriter) { if(removable) { - // TODO: Removable + user_response = ' '; + int anyMedia = FALSE; + + while(user_response != 'N' && user_response != 'n') + { + do + { + printf("Do you have media that you can insert in the drive? (Y/N): "); + scanf("%c", &user_response); + printf("\n"); + } while(user_response != 'Y' && user_response != 'y' && user_response != 'N' && user_response != 'n'); + + if(user_response == 'Y' || user_response == 'y') + { + printf("Please insert it in the drive and press any key when it is ready.\n"); + scanf("%c"); + + char mediaManufacturer[256], mediaName[256], mediaModel[256]; + printf("Please write a description of the media type and press enter: "); + gets(mediaName); + printf("Please write the media manufacturer and press enter: "); + gets(mediaManufacturer); + printf("Please write the media model and press enter: "); + gets(mediaModel); + + error = TestUnitReady(fd, &sense); + int mediaRecognized = TRUE; + int leftRetries = 20; + + if(error) + { + if((sense[0] == 0x70 || sense[0] == 0x71) && (sense[2] & 0x0F) != 0x00) + { + if(sense[12] == 0x3A || (sense[12] == 0x04 && sense[13] == 0x01)) + { + while(leftRetries > 0) + { + printf("\rWating for drive to become ready"); + sleep(2); + error = TestUnitReady(fd, &sense); + if(!error) + break; + + leftRetries--; + } + + printf("\n"); + mediaRecognized = !error; + } + else + mediaRecognized = FALSE; + } + else + mediaRecognized = FALSE; + } + + if(!anyMedia) + xmlTextWriterStartElement(xmlWriter, BAD_CAST "RemovableMedias"); // + + xmlTextWriterStartElement(xmlWriter, BAD_CAST "testedMediaType"); // + + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MediaIsRecognized", "%s", mediaRecognized ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Manufacturer", "%s", mediaManufacturer); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MediumTypeName", "%s",mediaName); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Model", "%s", mediaModel); + + if(mediaRecognized) + { + uint64_t blocks = 0; + uint32_t blockSize = 0; + + printf("Querying SCSI READ CAPACITY...\n"); + error = ReadCapacity(fd, &buffer, &sense, FALSE, 0, FALSE); + if(!error) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCapacity", "%s", "true"); + blocks = (uint64_t)(buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + (buffer[3]) + 1; + blockSize = (uint32_t)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + (buffer[7])); + } + + printf("Querying SCSI READ CAPACITY (16)...\n"); + error = ReadCapacity16(fd, &buffer, &sense, FALSE, 0); + if(!error) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadCapacity16", "%s", "true"); + blocks = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + (buffer[3]); + blocks <<= 32; + blocks += (buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + (buffer[7]); + blocks++; + blockSize = (uint32_t)((buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + (buffer[11])); + } + + if(blocks != 0) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Blocks", "%llu", blocks); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BlockSize", "%lu", blockSize); + } + + if(decMode != NULL) + decMode->decoded = 0; + + printf("Querying SCSI MODE SENSE (10)...\n"); + error = ModeSense10(fd, &mode10Response, &sense, FALSE, TRUE, MODE_PAGE_DEFAULT, 0x3F, 0x00); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsModeSense10", "%s", !error ? "true" : "false"); + if(!error) + { + xmlTextWriterStartElement(xmlWriter, BAD_CAST "ModeSense10Data"); + xmlTextWriterWriteBase64(xmlWriter, mode10Response, 0, (*(mode10Response + 0) << 8) + *(mode10Response + 1) + 2); + xmlTextWriterEndElement(xmlWriter); + decMode = DecodeMode10(mode10Response, inquiry->PeripheralDeviceType); + } + + printf("Querying SCSI MODE SENSE (6)...\n"); + error = ModeSense6(fd, &mode6Response, &sense, FALSE, MODE_PAGE_DEFAULT, 0x00, 0x00); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsModeSense6", "%s", !error ? "true" : "false"); + if(!error) + { + xmlTextWriterStartElement(xmlWriter, BAD_CAST "ModeSense6Data"); + xmlTextWriterWriteBase64(xmlWriter, mode6Response, 0, *(mode6Response + 0) + 1); + xmlTextWriterEndElement(xmlWriter); + if(!decMode->decoded) + decMode = DecodeMode6(mode6Response, inquiry->PeripheralDeviceType); + } + + if(decMode->decoded) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MediumType", "%d", decMode->Header.MediumType); + if(decMode->Header.descriptorsLength > 0) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Density", "%d", decMode->Header.BlockDescriptors[0].Density); + } + + printf("Trying SCSI READ (6)...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsRead", "%s", !Read6(fd, &buffer, &sense, 0, blockSize, 1) ? "true" : "false"); + + printf("Trying SCSI READ (10)...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsRead10", "%s", !Read10(fd, &buffer, &sense, 0, FALSE, TRUE, FALSE, FALSE, 0, blockSize, 0, 1) ? "true" : "false"); + + printf("Trying SCSI READ (12)...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsRead12", "%s", !Read12(fd, &buffer, &sense, 0, FALSE, TRUE, FALSE, FALSE, 0, blockSize, 0, 1, FALSE) ? "true" : "false"); + + printf("Trying SCSI READ (16)...\n"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsRead16", "%s", !Read16(fd, &buffer, &sense, 0, FALSE, TRUE, FALSE, 0, blockSize, 0, 1, FALSE) ? "true" : "false"); + + uint32_t longBlockSize = blockSize; + + int supportsReadLong10 = FALSE; + + printf("Trying SCSI READ LONG (10)...\n"); + ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, 0xFFFF); + if((sense[0] == 0x70 || sense[0] == 0x71) && (sense[2] & 0x0F) == 0x05 && sense[12] == 0x24 && sense[13] == 0x00) + { + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadLong", "%s", "true"); + supportsReadLong10 = TRUE; + if(sense[0] & 0x80 && sense[2] & 0x20) + { + uint32_t information = (sense[3] << 24) + (sense[4] << 16) + (sense[5] << 8) + sense[6]; + longBlockSize = 0xFFFF - (information & 0xFFFF); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LongBlockSize", "%d", longBlockSize); + } + } + + printf("Trying SCSI READ LONG (10)...\n"); + ReadLong16(fd, &buffer, &sense, FALSE, 0, 0xFFFF); + if((sense[0] == 0x70 || sense[0] == 0x71) && (sense[2] & 0x0F) == 0x05 && sense[12] == 0x24 && sense[13] == 0x00) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsReadLong16", "%s", "true"); + + int i; + + if(supportsReadLong10 && blockSize == longBlockSize) + { + if(blockSize == 512) + { + for(i = 0; i < sizeof(testSize512) / sizeof(int); i++) + { + error = ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, testSize512[i]); + if(!error) + { + longBlockSize = testSize512[i]; + break; + } + } + } + else if(blockSize == 1024) + { + for(i = 0; i < sizeof(testSize1024) / sizeof(int); i++) + { + error = ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, testSize1024[i]); + if(!error) + { + longBlockSize = testSize1024[i]; + break; + } + } + } + else if(blockSize == 2048) + { + for(i = 0; i < sizeof(testSize2048) / sizeof(int); i++) + { + error = ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, testSize2048[i]); + if(!error) + { + longBlockSize = testSize2048[i]; + break; + } + } + } + else if(blockSize == 4096) + { + for(i = 0; i < sizeof(testSize4096) / sizeof(int); i++) + { + error = ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, testSize4096[i]); + if(!error) + { + longBlockSize = testSize4096[i]; + break; + } + } + } + else if(blockSize == 8192) + { + for(i = 0; i < sizeof(testSize8192) / sizeof(int); i++) + { + error = ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, testSize8192[i]); + if(!error) + { + longBlockSize = testSize8192[i]; + break; + } + } + } + } + + if(supportsReadLong10 && blockSize == longBlockSize) + { + user_response = ' '; + do + { + printf("Drive supports SCSI READ LONG but I cannot find the correct size. Do you want me to try? (This can take hours) (Y/N): "); + scanf("%c", &user_response); + printf("\n"); + } while(user_response != 'Y' && user_response != 'y' && user_response != 'N' && user_response != 'n'); + + if(user_response == 'Y' || user_response == 'y') + { + for(i = blockSize; i <= 65536; i++) + { + printf("\rTrying to READ LONG with a size of %d bytes", i); + error = ReadLong10(fd, &buffer, &sense, FALSE, FALSE, 0, i); + if(!error) + { + longBlockSize = i; + break; + } + } + printf("\n"); + } + + user_response = ' '; + } + + if(supportsReadLong10 && blockSize != longBlockSize) + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LongBlockSize", "%d", longBlockSize); + } + + xmlTextWriterEndElement(xmlWriter); // + + if(!anyMedia) + { + xmlTextWriterEndElement(xmlWriter); // + anyMedia = TRUE; + } + } + } } else {