diff --git a/DiscImageChef.Device.Report/CMakeLists.txt b/DiscImageChef.Device.Report/CMakeLists.txt index 1290bfe6..b385d9ee 100644 --- a/DiscImageChef.Device.Report/CMakeLists.txt +++ b/DiscImageChef.Device.Report/CMakeLists.txt @@ -7,5 +7,5 @@ find_package(LibXml2) include_directories(${LIBXML2_INCLUDE_DIR}) -add_executable(DiscImageChef_Device_Report main.c scsi.c scsi.h main.h ata.h ata.c atapi.c atapi.h atapi_report.c atapi_report.h identify_decode.c identify_decode.h) +add_executable(DiscImageChef_Device_Report main.c scsi.c scsi.h main.h ata.h ata.c atapi.c atapi.h atapi_report.c atapi_report.h identify_decode.c identify_decode.h scsi_report.c scsi_report.h inquiry_decode.c inquiry_decode.h) target_link_libraries(DiscImageChef_Device_Report ${LIBXML2_LIBRARIES}) \ No newline at end of file diff --git a/DiscImageChef.Device.Report/atapi_report.c b/DiscImageChef.Device.Report/atapi_report.c index 8c2db8e3..59c571ee 100644 --- a/DiscImageChef.Device.Report/atapi_report.c +++ b/DiscImageChef.Device.Report/atapi_report.c @@ -9,14 +9,14 @@ #include "atapi.h" #include "identify_decode.h" -#define DIC_ATAPI_REPORT_ELEMENT "ATAPI" - void AtapiReport(int fd, xmlTextWriterPtr xmlWriter) { unsigned char *atapi_ident = NULL; AtaErrorRegistersCHS *ata_error_chs; int error; + printf("Querying ATAPI IDENTIFY...\n"); + error = IdentifyPacket(fd, &atapi_ident, &ata_error_chs); if(error) diff --git a/DiscImageChef.Device.Report/atapi_report.h b/DiscImageChef.Device.Report/atapi_report.h index 766e9098..4c668fb6 100644 --- a/DiscImageChef.Device.Report/atapi_report.h +++ b/DiscImageChef.Device.Report/atapi_report.h @@ -6,6 +6,7 @@ #define DISCIMAGECHEF_DEVICE_REPORT_ATAPI_REPORT_H #include +#define DIC_ATAPI_REPORT_ELEMENT "ATAPI" void AtapiReport(int fd, xmlTextWriterPtr xmlWriter); #endif //DISCIMAGECHEF_DEVICE_REPORT_ATAPI_REPORT_H diff --git a/DiscImageChef.Device.Report/inquiry_decode.c b/DiscImageChef.Device.Report/inquiry_decode.c new file mode 100644 index 00000000..ca0fae78 --- /dev/null +++ b/DiscImageChef.Device.Report/inquiry_decode.c @@ -0,0 +1,113 @@ +// +// Created by claunia on 15/12/17. +// + +#include +#include +#include "inquiry_decode.h" + +char *DecodeTPGSValues(uint8_t capabilities) +{ + switch(capabilities) + { + case 0: + return "NotSupported"; + case 1: + return "OnlyImplicit"; + case 2: + return "OnlyExplicit"; + case 3: + return "Both"; + default: + return NULL; + } +} + +char *DecodePeripheralDeviceType(uint8_t type) +{ + switch(type) + { + case 0x00: + return "DirectAccess"; + case 0x01: + return "SequentialAccess"; + case 0x02: + return "PrinterDevice"; + case 0x03: + return "ProcessorDevice"; + case 0x04: + return "WriteOnceDevice"; + case 0x05: + return "MultiMediaDevice"; + case 0x06: + return "ScannerDevice"; + case 0x07: + return "OpticalDevice"; + case 0x08: + return "MediumChangerDevice"; + case 0x09: + return "CommsDevice"; + case 0x0A: + return "PrePressDevice1"; + case 0x0B: + return "PrePressDevice2"; + case 0x0C: + return "ArrayControllerDevice"; + case 0x0D: + return "EnclosureServiceDevice"; + case 0x0E: + return "SimplifiedDevice"; + case 0x0F: + return "OCRWDevice"; + case 0x10: + return "BridgingExpander"; + case 0x11: + return "ObjectDevice"; + case 0x12: + return "ADCDevice"; + case 0x13: + return "SCSISecurityManagerDevice"; + case 0x14: + return "SCSIZonedBlockDevice"; + case 0x1E: + return "WellKnownDevice"; + case 0x1F: + return "UnknownDevice"; + default: + return NULL; + } +} + +char *DecodePeripheralQualifier(uint8_t qualifier) +{ + switch(qualifier) + { + case 0: + return "Supported"; + case 1: + return "Unconnected"; + case 2: + return "Reserved"; + case 3: + return "Unsupported"; + default: + return NULL; + } +} + +char *DecodeSPIClocking(uint8_t qualifier) +{ + switch(qualifier) + { + case 0: + return "ST"; + case 1: + return "DT"; + case 2: + return "Reserved"; + case 3: + return "StandDT"; + default: + return NULL; + } +} \ No newline at end of file diff --git a/DiscImageChef.Device.Report/inquiry_decode.h b/DiscImageChef.Device.Report/inquiry_decode.h new file mode 100644 index 00000000..8f84e1be --- /dev/null +++ b/DiscImageChef.Device.Report/inquiry_decode.h @@ -0,0 +1,14 @@ +// +// Created by claunia on 15/12/17. +// + +#ifndef DISCIMAGECHEF_DEVICE_REPORT_INQUIRY_DECODE_H +#define DISCIMAGECHEF_DEVICE_REPORT_INQUIRY_DECODE_H + +#include + +char *DecodeTPGSValues(uint8_t capabilities); +char *DecodePeripheralDeviceType(uint8_t capabilities); +char *DecodePeripheralQualifier(uint8_t capabilities); +char *DecodeSPIClocking(uint8_t capabilities); +#endif //DISCIMAGECHEF_DEVICE_REPORT_INQUIRY_DECODE_H diff --git a/DiscImageChef.Device.Report/main.c b/DiscImageChef.Device.Report/main.c index d0feab92..9a23de2f 100644 --- a/DiscImageChef.Device.Report/main.c +++ b/DiscImageChef.Device.Report/main.c @@ -9,6 +9,7 @@ #include "main.h" #include "atapi.h" #include "atapi_report.h" +#include "scsi_report.h" #include #define DIC_VERSION "3.99.6.0" @@ -136,6 +137,9 @@ int main(int argc, void *argv[]) if(deviceType == DEVICE_TYPE_ATAPI) AtapiReport(fd, xmlWriter); + if(deviceType == DEVICE_TYPE_ATAPI || deviceType == DEVICE_TYPE_SCSI) + ScsiReport(fd, xmlWriter); + rc = xmlTextWriterEndDocument(xmlWriter); if (rc < 0) { printf("Could not close XML report file.\n"); diff --git a/DiscImageChef.Device.Report/scsi.h b/DiscImageChef.Device.Report/scsi.h index 0247ade8..7bf2dd3a 100644 --- a/DiscImageChef.Device.Report/scsi.h +++ b/DiscImageChef.Device.Report/scsi.h @@ -5,13 +5,256 @@ #ifndef DISCIMAGECHEF_DEVICE_REPORT_SCSI_H #define DISCIMAGECHEF_DEVICE_REPORT_SCSI_H +#include + int SendScsiCommand(int fd, void *cdb, unsigned char cdb_len, unsigned char *buffer, unsigned int buffer_len, unsigned char **senseBuffer, int direction); int Inquiry(int fd, unsigned char **buffer, unsigned char **senseBuffer); + typedef enum { SCSI_INQUIRY = 0x12, SCSI_ATA_PASSTHROUGH_16 = 0x85 } ScsiCommands; +// SCSI INQUIRY command response +#pragma pack(1) +typedef struct +{ + /// + /// Peripheral device type + /// Byte 0, bits 4 to 0 + /// + uint8_t PeripheralDeviceType : 5; + /// + /// Peripheral qualifier + /// Byte 0, bits 7 to 5 + /// + uint8_t PeripheralQualifier : 3; + /// + /// SCSI-1 vendor-specific qualification codes + /// Byte 1, bits 6 to 0 + /// + uint8_t DeviceTypeModifier : 7; + /// + /// Removable device + /// Byte 1, bit 7 + /// + uint8_t RMB : 1; + /// + /// ANSI SCSI Standard Version + /// Byte 2, bits 2 to 0, mask = 0x07 + /// + uint8_t ANSIVersion : 3; + /// + /// ECMA SCSI Standard Version + /// Byte 2, bits 5 to 3, mask = 0x38, >> 3 + /// + uint8_t ECMAVersion : 3; + /// + /// ISO/IEC SCSI Standard Version + /// Byte 2, bits 7 to 6, mask = 0xC0, >> 6 + /// + uint8_t ISOVersion : 2; + /// + /// Responde data format + /// Byte 3, bit 3 to 0 + /// + uint8_t ResponseDataFormat : 4; + /// + /// Supports LUN hierarchical addressing + /// Byte 3, bit 4 + /// + uint8_t HiSup : 1; + /// + /// Supports setting Normal ACA + /// Byte 3, bit 5 + /// + uint8_t NormACA : 1; + /// + /// Device supports TERMINATE TASK command + /// Byte 3, bit 6 + /// + uint8_t TrmTsk : 1; + /// + /// Asynchronous Event Reporting Capability supported + /// Byte 3, bit 7 + /// + uint8_t AERC : 1; + /// + /// Lenght of total INQUIRY response minus 4 + /// Byte 4 + /// + uint8_t AdditionalLength; + /// + /// Supports protection information + /// Byte 5, bit 0 + /// + uint8_t Protect : 1; + /// + /// Reserved + /// Byte 5, bits 2 to 1 + /// + uint8_t Reserved2 : 2; + /// + /// Supports third-party copy commands + /// Byte 5, bit 3 + /// + uint8_t ThreePC : 1; + /// + /// Supports asymetrical logical unit access + /// Byte 5, bits 5 to 4 + /// + uint8_t TPGS : 2; + /// + /// Device contains an Access Control Coordinator + /// Byte 5, bit 6 + /// + uint8_t ACC : 1; + /// + /// Device contains an embedded storage array controller + /// Byte 5, bit 7 + /// + uint8_t SCCS : 1; + /// + /// Supports 16-bit wide SCSI addresses + /// Byte 6, bit 0 + /// + uint8_t Addr16 : 1; + /// + /// Supports 32-bit wide SCSI addresses + /// Byte 6, bit 1 + /// + uint8_t Addr32 : 1; + /// + /// Device supports request and acknowledge handshakes + /// Byte 6, bit 2 + /// + uint8_t ACKREQQ : 1; + /// + /// Device contains or is attached to a medium changer + /// Byte 6, bit 3 + /// + uint8_t MChngr : 1; + /// + /// Multi-port device + /// Byte 6, bit 4 + /// + uint8_t MultiP : 1; + /// + /// Vendor-specific + /// Byte 6, bit 5 + /// + uint8_t VS1 : 1; + /// + /// Device contains an embedded enclosure services component + /// Byte 6, bit 6 + /// + uint8_t EncServ : 1; + /// + /// Supports basic queueing + /// Byte 6, bit 7 + /// + uint8_t BQue : 1; + /// + /// Indicates that the devices responds to RESET with soft reset + /// Byte 7, bit 0 + /// + uint8_t SftRe : 1; + /// + /// Supports TCQ queue + /// Byte 7, bit 1 + /// + uint8_t CmdQue : 1; + /// + /// Supports CONTINUE TASK and TARGET TRANSFER DISABLE commands + /// Byte 7, bit 2 + /// + uint8_t TranDis : 1; + /// + /// Supports linked commands + /// Byte 7, bit 3 + /// + uint8_t Linked : 1; + /// + /// Supports synchronous data transfer + /// Byte 7, bit 4 + /// + uint8_t Sync : 1; + /// + /// Supports 16-bit wide data transfers + /// Byte 7, bit 5 + /// + uint8_t WBus16 : 1; + /// + /// Supports 32-bit wide data transfers + /// Byte 7, bit 6 + /// + uint8_t WBus32 : 1; + /// + /// Device supports relative addressing + /// Byte 7, bit 7 + /// + uint8_t RelAddr : 1; + /// + /// Vendor identification + /// Bytes 8 to 15 + /// + uint8_t VendorIdentification[8]; + /// + /// Product identification + /// Bytes 16 to 31 + /// + uint8_t ProductIdentification[16]; + /// + /// Product revision level + /// Bytes 32 to 35 + /// + uint8_t ProductRevisionLevel[4]; + /// + /// Vendor-specific data + /// Bytes 36 to 55 + /// + uint8_t VendorSpecific[20]; + /// + /// Supports information unit transfers + /// Byte 56, bit 0 + /// + uint8_t IUS : 1; + /// + /// Device supports Quick Arbitration and Selection + /// Byte 56, bit 1 + /// + uint8_t QAS : 1; + /// + /// Supported SPI clocking + /// Byte 56, bits 3 to 2 + /// + uint8_t Clocking : 2; + /// + /// Byte 56, bits 7 to 4 + /// + uint8_t Reserved3 : 4; + /// + /// Reserved + /// Byte 57 + /// + uint8_t Reserved4; + /// + /// Array of version descriptors + /// Bytes 58 to 73 + /// + uint16_t VersionDescriptors[8]; + /// + /// Reserved + /// Bytes 74 to 95 + /// + uint8_t Reserved5[22]; + /// + /// Reserved + /// Bytes 96 to end + /// + uint8_t VendorSpecific2; +} ScsiInquiry; + #endif //DISCIMAGECHEF_DEVICE_REPORT_SCSI_H diff --git a/DiscImageChef.Device.Report/scsi_report.c b/DiscImageChef.Device.Report/scsi_report.c new file mode 100644 index 00000000..a71ea641 --- /dev/null +++ b/DiscImageChef.Device.Report/scsi_report.c @@ -0,0 +1,107 @@ +// +// Created by claunia on 14/12/17. +// +#include +#include +#include "scsi_report.h" +#include "scsi.h" +#include "inquiry_decode.h" + +void ScsiReport(int fd, xmlTextWriterPtr xmlWriter) +{ + unsigned char *sense = NULL; + unsigned char *buffer = NULL; + int error; + int page_len; + int removable = FALSE; + char user_response = ' '; + unsigned char* tmpString; + + printf("Querying SCSI INQUIRY...\n"); + + error = Inquiry(fd, &buffer, &sense); + + if(error) + { + fprintf(stderr, "Error {0} requesting INQUIRY", error); + return; + } + + xmlTextWriterStartElement(xmlWriter, BAD_CAST DIC_SCSI_REPORT_ELEMENT); + page_len = *(buffer + 4) + 5; + + ScsiInquiry *inquiry = malloc(sizeof(ScsiInquiry)); + memset(inquiry, 0, sizeof(ScsiInquiry)); + memcpy(inquiry, buffer, page_len > sizeof(ScsiInquiry) ? sizeof(ScsiInquiry) : page_len); + + if(inquiry->RMB) + { + do + { + printf("Is the media removable from the reading/writing elements (flash memories ARE NOT removable)? (Y/N): "); + scanf("%c", &user_response); + printf("\n"); + } while(user_response != 'Y' && user_response != 'y' && user_response != 'N' && user_response != 'n'); + + removable = (user_response == 'Y' || user_response == 'y'); + } + xmlTextWriterStartElement(xmlWriter, BAD_CAST DIC_SCSI_INQUIRY_ELEMENT); + + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "AccessControlCoordinator", "%s", inquiry->ACC ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ACKRequests", "%s", inquiry->ACKREQQ ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Address16", "%s", inquiry->Addr16 ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Address32", "%s", inquiry->Addr32 ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "AERCSupported", "%s", inquiry->AERC ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ANSIVersion", "%d", inquiry->ANSIVersion); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "AsymmetricalLUNAccess", "%s", DecodeTPGSValues(inquiry->TPGS)); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BasicQueueing", "%s", inquiry->BQue ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "DeviceTypeModifier", "%d", inquiry->DeviceTypeModifier); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ECMAVersion", "%d", inquiry->ECMAVersion); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "EnclosureServices", "%s", inquiry->EncServ ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "HierarchicalLUN", "%s", inquiry->HiSup ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ISOVersion", "%d", inquiry->ISOVersion); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "IUS", "%s", inquiry->IUS ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "LinkedCommands", "%s", inquiry->Linked ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MediumChanger", "%s", inquiry->MChngr ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "MultiPortDevice", "%s", inquiry->MultiP ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "NormalACA", "%s", inquiry->NormACA ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PeripheralDeviceType", "%s", DecodePeripheralDeviceType(inquiry->PeripheralDeviceType)); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "PeripheralQualifier", "%s", DecodePeripheralQualifier(inquiry->PeripheralQualifier)); + tmpString = malloc(17); + memset(tmpString, 0, 17); + memcpy(tmpString, inquiry->ProductIdentification, 16); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ProductIdentification", "%s", tmpString); + free(tmpString); + tmpString = malloc(5); + memset(tmpString, 0, 5); + memcpy(tmpString, inquiry->ProductRevisionLevel, 4); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ProductRevisionLevel", "%s", tmpString); + free(tmpString); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Protection", "%s", inquiry->Protect ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "QAS", "%s", inquiry->QAS ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "RelativeAddressing", "%s", inquiry->RelAddr ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Removable", "%s", inquiry->RMB ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ResponseDataFormat", "%d", inquiry->ResponseDataFormat); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SoftReset", "%s", inquiry->SftRe ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SPIClocking", "%s", DecodeSPIClocking(inquiry->Clocking)); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "StorageArrayController", "%s", inquiry->SCCS ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SyncTransfer", "%s", inquiry->Sync ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "TaggedCommandQueue", "%s", inquiry->CmdQue ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "TerminateTaskSupported", "%s", inquiry->TrmTsk ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "ThirdPartyCopy", "%s", inquiry->ThreePC ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "TranferDisable", "%s", inquiry->TranDis ? "true" : "false"); + tmpString = malloc(9); + memset(tmpString, 0, 9); + memcpy(tmpString, inquiry->VendorIdentification, 8); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "VendorIdentification", "%8s", tmpString); + free(tmpString); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "WideBus16", "%s", inquiry->WBus16 ? "true" : "false"); + xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "WideBus32", "%s", inquiry->WBus32 ? "true" : "false"); + + xmlTextWriterStartElement(xmlWriter, BAD_CAST "Data"); + xmlTextWriterWriteBase64(xmlWriter, buffer, 0, page_len); + xmlTextWriterEndElement(xmlWriter); + + xmlTextWriterEndElement(xmlWriter); + xmlTextWriterEndElement(xmlWriter); +} \ No newline at end of file diff --git a/DiscImageChef.Device.Report/scsi_report.h b/DiscImageChef.Device.Report/scsi_report.h new file mode 100644 index 00000000..c5069fbd --- /dev/null +++ b/DiscImageChef.Device.Report/scsi_report.h @@ -0,0 +1,11 @@ +// +// Created by claunia on 14/12/17. +// + +#ifndef DISCIMAGECHEF_DEVICE_REPORT_SCSI_REPORT_H +#define DISCIMAGECHEF_DEVICE_REPORT_SCSI_REPORT_H +#define DIC_SCSI_REPORT_ELEMENT "SCSI" +#define DIC_SCSI_INQUIRY_ELEMENT "Inquiry" + +void ScsiReport(int fd, xmlTextWriterPtr xmlWriter); +#endif //DISCIMAGECHEF_DEVICE_REPORT_SCSI_REPORT_H