Added SCSI MODE SENSE report to DiscImageChef.Device.Report.

This commit is contained in:
2017-12-16 20:02:16 +00:00
parent 8930336221
commit 1b75ca78f8
5 changed files with 657 additions and 6 deletions

View File

@@ -6,6 +6,7 @@
#include "scsi_report.h"
#include "scsi.h"
#include "inquiry_decode.h"
#include "scsi_mode.h"
void ScsiReport(int fd, xmlTextWriterPtr xmlWriter)
{
@@ -27,7 +28,7 @@ void ScsiReport(int fd, xmlTextWriterPtr xmlWriter)
return;
}
xmlTextWriterStartElement(xmlWriter, BAD_CAST DIC_SCSI_REPORT_ELEMENT);
xmlTextWriterStartElement(xmlWriter, BAD_CAST DIC_SCSI_REPORT_ELEMENT); // <SCSI>
page_len = *(buffer + 4) + 5;
ScsiInquiry *inquiry = malloc(sizeof(ScsiInquiry));
@@ -45,8 +46,8 @@ void ScsiReport(int fd, xmlTextWriterPtr xmlWriter)
removable = (user_response == 'Y' || user_response == 'y');
}
xmlTextWriterStartElement(xmlWriter, BAD_CAST DIC_SCSI_INQUIRY_ELEMENT);
xmlTextWriterStartElement(xmlWriter, BAD_CAST DIC_SCSI_INQUIRY_ELEMENT); // <Inquiry>
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");
@@ -101,7 +102,388 @@ void ScsiReport(int fd, xmlTextWriterPtr xmlWriter)
xmlTextWriterStartElement(xmlWriter, BAD_CAST "Data");
xmlTextWriterWriteBase64(xmlWriter, buffer, 0, page_len);
xmlTextWriterEndElement(xmlWriter);
xmlTextWriterEndElement(xmlWriter); // </Inquiry>
xmlTextWriterEndElement(xmlWriter);
xmlTextWriterEndElement(xmlWriter);
// TODO: EVPDs
if(removable)
{
if(inquiry->PeripheralDeviceType == 0x05) // MultiMediaDevice
{
AllowMediumRemoval(fd, &sense);
EjectTray(fd, &sense);
}
else if(inquiry->PeripheralDeviceType == 0x05) // SequentialAccess
{
SpcAllowMediumRemoval(fd, &sense);
printf("Asking drive to unload tape (can take a few minutes)...\n");
Unload(fd, &sense);
}
printf("Please remove any media from the device and press any key when it is out.\n");
scanf("%c");
}
int supportsMode6 = FALSE;
int supportsMode10 = FALSE;
int supportsModeSubpages = FALSE;
unsigned char* mode6Response = NULL;
unsigned char* mode10Response = NULL;
printf("Querying all mode pages and subpages using SCSI MODE SENSE (10)...\n");
error = ModeSense10(fd, &mode10Response, &sense, FALSE, TRUE, MODE_PAGE_DEFAULT, 0x3F, 0xFF);
if(error)
{
printf("Querying all mode pages using SCSI MODE SENSE (10)...");
error = ModeSense10(fd, &mode10Response, &sense, FALSE, TRUE, MODE_PAGE_DEFAULT, 0x3F, 0x00);
if(!error)
supportsMode10 = TRUE;
}
else
{
supportsMode10 = TRUE;
supportsModeSubpages = TRUE;
}
printf("Querying all mode pages and subpages using SCSI MODE SENSE (6)...\n");
error = ModeSense6(fd, &mode6Response, &sense, FALSE, MODE_PAGE_DEFAULT, 0x3F, 0xFF);
if(error)
{
printf("Querying all mode pages using SCSI MODE SENSE (6)...");
error = ModeSense6(fd, &mode6Response, &sense, FALSE, MODE_PAGE_DEFAULT, 0x3F, 0x00);
if(error)
{
printf("Querying SCSI MODE SENSE (6)...");
error = ModeSense6(fd, &mode6Response, &sense, FALSE, MODE_PAGE_DEFAULT, 0x00, 0x00);
if(!error)
supportsMode6 = TRUE;
}
else
supportsMode6 = TRUE;
}
else
{
supportsMode6 = TRUE;
supportsModeSubpages = TRUE;
}
xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsModeSense6", "%s", supportsMode6 ? "true" : "false");
xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsModeSense10", "%s", supportsMode10 ? "true" : "false");
xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "SupportsModeSubpages", "%s", supportsModeSubpages ? "true" : "false");
if(supportsMode6)
{
xmlTextWriterStartElement(xmlWriter, BAD_CAST "ModeSense6Data");
xmlTextWriterWriteBase64(xmlWriter, mode6Response, 0, *(mode6Response + 0) + 1);
xmlTextWriterEndElement(xmlWriter);
}
if(supportsMode10)
{
xmlTextWriterStartElement(xmlWriter, BAD_CAST "ModeSense10Data");
xmlTextWriterWriteBase64(xmlWriter, mode10Response, 0, (*(mode10Response + 0) << 8) + *(mode10Response + 1) + 2);
xmlTextWriterEndElement(xmlWriter);
}
DecodedMode decMode;
memset(&decMode, 0, sizeof(DecodedMode));
if(supportsMode10)
decMode = DecodeMode10(mode10Response, inquiry->PeripheralDeviceType);
else if(supportsMode6)
decMode = DecodeMode6(mode6Response, inquiry->PeripheralDeviceType);
if(decMode.decoded)
{
int page, subpage;
xmlTextWriterStartElement(xmlWriter, BAD_CAST "ModeSense"); // <ModeSense>
xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BlankCheckEnabled", "%s", decMode.Header.EBC ? "true" : "false");
xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "DPOandFUA", "%s", decMode.Header.DPOFUA ? "true" : "false");
xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "WriteProtected", "%s", decMode.Header.WriteProtected ? "true" : "false");
if(decMode.Header.BufferedMode > 0)
xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "BlankCheckEnabled", "%d", decMode.Header.BufferedMode);
if(decMode.Header.Speed > 0)
xmlTextWriterWriteFormatElement(xmlWriter, BAD_CAST "Speed", "%d", decMode.Header.Speed);
for(page = 0; page < 256; page++)
{
for(subpage = 0; subpage < 256; subpage++)
{
if(decMode.pageSizes[page][subpage] > 0 && decMode.Pages[page][subpage] != NULL)
{
xmlTextWriterStartElement(xmlWriter, BAD_CAST "modePageType");
xmlTextWriterWriteFormatAttribute(xmlWriter, BAD_CAST "page", "%d", page);
xmlTextWriterWriteFormatAttribute(xmlWriter, BAD_CAST "subpage", "%d", subpage);
xmlTextWriterWriteBase64(xmlWriter, decMode.Pages[page][subpage], 0, decMode.pageSizes[page][subpage]);
xmlTextWriterEndElement(xmlWriter);
if(page == 0x2A && subpage == 0x00)
{
// TODO: Decode CD-ROM page
}
}
}
}
xmlTextWriterEndElement(xmlWriter); // </ModeSense>
}
xmlTextWriterEndElement(xmlWriter); // </SCSI>
}
ModeHeader DecodeModeHeader6(unsigned char* modeResponse, uint8_t deviceType)
{
int i;
ModeHeader header;
if(modeResponse[3])
{
header.descriptorsLength = modeResponse[3] / 8;
for(i = 0; i < header.descriptorsLength; i++)
{
header.BlockDescriptors[i].Density = modeResponse[0 + i * 8 + 4];
header.BlockDescriptors[i].Blocks += (uint64_t)(modeResponse[1 + i * 8 + 4] << 16);
header.BlockDescriptors[i].Blocks += (uint64_t)(modeResponse[2 + i * 8 + 4] << 8);
header.BlockDescriptors[i].Blocks += modeResponse[3 + i * 8 + 4];
header.BlockDescriptors[i].BlockLength += (uint32_t)(modeResponse[5 + i * 8 + 4] << 16);
header.BlockDescriptors[i].BlockLength += (uint32_t)(modeResponse[6 + i * 8 + 4] << 8);
header.BlockDescriptors[i].BlockLength += modeResponse[7 + i * 8 + 4];
}
}
if(deviceType == 0x00 || deviceType == 0x05)
{
header.WriteProtected = ((modeResponse[2] & 0x80) == 0x80);
header.DPOFUA = ((modeResponse[2] & 0x10) == 0x10);
}
if(deviceType == 0x01)
{
header.WriteProtected = ((modeResponse[2] & 0x80) == 0x80);
header.Speed = (uint8_t)(modeResponse[2] & 0x0F);
header.BufferedMode = (uint8_t)((modeResponse[2] & 0x70) >> 4);
}
if(deviceType == 0x02)
header.BufferedMode = (uint8_t)((modeResponse[2] & 0x70) >> 4);
if(deviceType == 0x07)
{
header.WriteProtected = ((modeResponse[2] & 0x80) == 0x80);
header.EBC = ((modeResponse[2] & 0x01) == 0x01);
header.DPOFUA = ((modeResponse[2] & 0x10) == 0x10);
}
header.decoded = 1;
return header;
}
ModeHeader DecodeModeHeader10(unsigned char* modeResponse, uint8_t deviceType)
{
uint16_t blockDescLength = (uint16_t)((modeResponse[6] << 8) + modeResponse[7]);
int i;
ModeHeader header;
header.MediumType = modeResponse[2];
int longLBA = (modeResponse[4] & 0x01) == 0x01;
if(blockDescLength > 0)
{
if(longLBA)
{
header.descriptorsLength = blockDescLength / 16;
for(i = 0; i < header.descriptorsLength; i++)
{
header.BlockDescriptors[i].Density = 0x00;
header.BlockDescriptors[i].Blocks = be64toh((uint64_t)(*modeResponse + 0 + i * 16 + 8));
header.BlockDescriptors[i].BlockLength += (uint32_t)(modeResponse[15 + i * 16 + 8] << 24);
header.BlockDescriptors[i].BlockLength += (uint32_t)(modeResponse[14 + i * 16 + 8] << 16);
header.BlockDescriptors[i].BlockLength += (uint32_t)(modeResponse[13 + i * 16 + 8] << 8);
header.BlockDescriptors[i].BlockLength += modeResponse[12 + i * 16 + 8];
}
}
else
{
header.descriptorsLength = blockDescLength / 8;
for(i = 0; i < header.descriptorsLength; i++)
{
if(deviceType != 0x00)
{
header.BlockDescriptors[i].Density = modeResponse[0 + i * 8 + 8];
}
else
{
header.BlockDescriptors[i].Density = 0x00;
header.BlockDescriptors[i].Blocks += (uint64_t)(modeResponse[0 + i * 8 + 8] << 24);
}
header.BlockDescriptors[i].Blocks += (uint64_t)(modeResponse[1 + i * 8 + 8] << 16);
header.BlockDescriptors[i].Blocks += (uint64_t)(modeResponse[2 + i * 8 + 8] << 8);
header.BlockDescriptors[i].Blocks += modeResponse[3 + i * 8 + 8];
header.BlockDescriptors[i].BlockLength += (uint32_t)(modeResponse[5 + i * 8 + 8] << 16);
header.BlockDescriptors[i].BlockLength += (uint32_t)(modeResponse[6 + i * 8 + 8] << 8);
header.BlockDescriptors[i].BlockLength += modeResponse[7 + i * 8 + 8];
}
}
}
if(deviceType == 0x00 || deviceType == 0x05)
{
header.WriteProtected = ((modeResponse[3] & 0x80) == 0x80);
header.DPOFUA = ((modeResponse[3] & 0x10) == 0x10);
}
if(deviceType == 0x01)
{
header.WriteProtected = ((modeResponse[3] & 0x80) == 0x80);
header.Speed = (uint8_t)(modeResponse[3] & 0x0F);
header.BufferedMode = (uint8_t)((modeResponse[3] & 0x70) >> 4);
}
if(deviceType == 0x02)
header.BufferedMode = (uint8_t)((modeResponse[3] & 0x70) >> 4);
if(deviceType == 0x07)
{
header.WriteProtected = ((modeResponse[3] & 0x80) == 0x80);
header.EBC = ((modeResponse[3] & 0x01) == 0x01);
header.DPOFUA = ((modeResponse[3] & 0x10) == 0x10);
}
header.decoded = 1;
return header;
}
DecodedMode DecodeMode6(unsigned char* modeResponse, uint8_t deviceType)
{
DecodedMode decoded;
ModeHeader hdr = DecodeModeHeader6(modeResponse, deviceType);
if(!hdr.decoded)
return decoded;
decoded.Header = hdr;
decoded.decoded = 1;
int offset = 4 + decoded.Header.descriptorsLength * 8;
int length = modeResponse[0] + 1;
while(offset < length)
{
int isSubpage = (modeResponse[offset] & 0x40) == 0x40;
uint8_t pageNo = (uint8_t)(modeResponse[offset] & 0x3F);
int subpage;
if(pageNo == 0)
{
decoded.pageSizes[0][0] = (size_t)(length - offset);
decoded.Pages[0][0] = malloc(decoded.pageSizes[0][0]);
memset(decoded.Pages[0][0], 0, decoded.pageSizes[0][0]);
memcpy(decoded.Pages[0][0], modeResponse + offset, decoded.pageSizes[0][0]);
offset += decoded.pageSizes[0][0];
}
else
{
if(isSubpage)
{
if(offset + 3 >= length)
break;
pageNo = (uint8_t)(modeResponse[offset] & 0x3F);
subpage = modeResponse[offset + 1];
decoded.pageSizes[pageNo][subpage] = (size_t)((modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4);
decoded.Pages[pageNo][subpage] = malloc(decoded.pageSizes[pageNo][subpage]);
memset(decoded.Pages[pageNo][subpage], 0, decoded.pageSizes[pageNo][subpage]);
memcpy(decoded.Pages[pageNo][subpage], modeResponse + offset, decoded.pageSizes[pageNo][subpage]);
offset += decoded.pageSizes[pageNo][subpage];
}
else
{
if(offset + 1 >= length)
break;
pageNo = (uint8_t)(modeResponse[offset] & 0x3F);
decoded.pageSizes[pageNo][0] = (size_t)(modeResponse[offset + 1] + 2);
decoded.Pages[pageNo][0] = malloc(decoded.pageSizes[pageNo][0]);
memset(decoded.Pages[pageNo][0], 0, decoded.pageSizes[pageNo][0]);
memcpy(decoded.Pages[pageNo][0], modeResponse + offset, decoded.pageSizes[pageNo][0]);
offset += decoded.pageSizes[pageNo][0];
}
}
}
return decoded;
}
DecodedMode DecodeMode10(unsigned char* modeResponse, uint8_t deviceType)
{
DecodedMode decodedMode;
decodedMode.Header = DecodeModeHeader10(modeResponse, deviceType);
if(!decodedMode.Header.decoded)
return decodedMode;
decodedMode.decoded = 1;
int longlba = (modeResponse[4] & 0x01) == 0x01;
int offset;
if(longlba)
offset = 8 + decodedMode.Header.descriptorsLength * 16;
else
offset = 8 + decodedMode.Header.descriptorsLength * 8;
int length = (modeResponse[0] << 8);
length += modeResponse[1];
length += 2;
while(offset < length)
{
int isSubpage = (modeResponse[offset] & 0x40) == 0x40;
uint8_t pageNo = (uint8_t)(modeResponse[offset] & 0x3F);
int subpage;
if(pageNo == 0)
{
decodedMode.pageSizes[0][0] = (size_t)(length - offset);
decodedMode.Pages[0][0] = malloc(decodedMode.pageSizes[0][0]);
memset(decodedMode.Pages[0][0], 0, decodedMode.pageSizes[0][0]);
memcpy(decodedMode.Pages[0][0], modeResponse + offset, decodedMode.pageSizes[0][0]);
offset += decodedMode.pageSizes[0][0];
}
else
{
if(isSubpage)
{
if(offset + 3 >= length)
break;
pageNo = (uint8_t)(modeResponse[offset] & 0x3F);
subpage = modeResponse[offset + 1];
decodedMode.pageSizes[pageNo][subpage] = (size_t)((modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4);
decodedMode.Pages[pageNo][subpage] = malloc(decodedMode.pageSizes[pageNo][subpage]);
memset(decodedMode.Pages[pageNo][subpage], 0, decodedMode.pageSizes[pageNo][subpage]);
memcpy(decodedMode.Pages[pageNo][subpage], modeResponse + offset, decodedMode.pageSizes[pageNo][subpage]);
offset += decodedMode.pageSizes[pageNo][subpage];
}
else
{
if(offset + 1 >= length)
break;
pageNo = (uint8_t)(modeResponse[offset] & 0x3F);
decodedMode.pageSizes[pageNo][0] = (size_t)(modeResponse[offset + 1] + 2);
decodedMode.Pages[pageNo][0] = malloc(decodedMode.pageSizes[pageNo][0]);
memset(decodedMode.Pages[pageNo][0], 0, decodedMode.pageSizes[pageNo][0]);
memcpy(decodedMode.Pages[pageNo][0], modeResponse + offset, decodedMode.pageSizes[pageNo][0]);
offset += decodedMode.pageSizes[pageNo][0];
}
}
}
return decodedMode;
}