AHCI: Begin simulating SCSI Inquiry with VPD data

* Needed for SCSI level access to trim maximum block sizes.
This commit is contained in:
Alexander von Gluck IV
2015-09-04 19:30:34 -05:00
parent a1e25f862c
commit 8248d96a06
2 changed files with 86 additions and 29 deletions
@@ -557,6 +557,69 @@ AHCIPort::ScsiTestUnitReady(scsi_ccb* request)
}
void
AHCIPort::ScsiVPDInquiry(scsi_ccb* request, ata_device_infoblock* ataData)
{
TRACE("AHCIPort::ScsiVPDInquiry port %d\n", fIndex);
const scsi_cmd_inquiry* cmd = (const scsi_cmd_inquiry*)request->cdb;
size_t vpdDataLength = 0;
status_t transactionResult = B_ERROR;
switch (cmd->page_code) {
case SCSI_PAGE_SUPPORTED_VPD:
{
scsi_page_list vpdPageData;
vpdDataLength = sizeof(vpdPageData);
vpdPageData.page_code = cmd->page_code;
// Our supported pages
vpdPageData.page_length = 1;
vpdPageData.pages[0] = SCSI_PAGE_BLOCK_LIMITS;
transactionResult = sg_memcpy(request->sg_list, request->sg_count,
&vpdPageData, vpdDataLength);
break;
}
case SCSI_PAGE_BLOCK_LIMITS:
{
scsi_page_block_limits vpdPageData;
vpdDataLength = sizeof(vpdPageData);
vpdPageData.page_code = cmd->page_code;
vpdPageData.max_unmap_lba_count
= ataData->max_data_set_management_lba_range_blocks;
transactionResult = sg_memcpy(request->sg_list, request->sg_count,
&vpdPageData, vpdDataLength);
break;
}
case SCSI_PAGE_USN:
case SCSI_PAGE_BLOCK_DEVICE_CHARS:
case SCSI_PAGE_LB_PROVISIONING:
case SCSI_PAGE_REFERRALS:
ERROR("VPD AHCI page %d not yet implemented!\n",
cmd->page_code);
//request->subsys_status = SCSI_REQ_CMP;
request->subsys_status = SCSI_REQ_ABORTED;
return;
default:
ERROR("unknown VPD page code!\n");
request->subsys_status = SCSI_REQ_ABORTED;
return;
}
if (transactionResult < B_OK) {
request->subsys_status = SCSI_DATA_RUN_ERR;
} else {
request->subsys_status = SCSI_REQ_CMP;
request->data_resid = request->data_length
- vpdDataLength;
}
}
void
AHCIPort::ScsiInquiry(scsi_ccb* request)
{
@@ -568,11 +631,17 @@ AHCIPort::ScsiInquiry(scsi_ccb* request)
ASSERT(sizeof(ataData) == 512);
if (cmd->evpd)
TRACE("VPD inquiry page %d\n", cmd->page_code);
else if (cmd->page_code) {
if (cmd->evpd) {
TRACE("VPD inquiry page 0x%X\n", cmd->page_code);
if (!request->data || request->data_length == 0) {
ERROR("invalid VPD request\n");
request->subsys_status = SCSI_REQ_ABORTED;
gSCSI->finished(request, 1);
return;
}
} else if (cmd->page_code) {
// page_code without evpd is invalid per SCSI spec
ERROR("page code %d on non-VPD request\n", cmd->page_code);
ERROR("page code 0x%X on non-VPD request\n", cmd->page_code);
request->subsys_status = SCSI_REQ_ABORTED;
request->device_status = SCSI_STATUS_CHECK_CONDITION;
// TODO: Sense ILLEGAL REQUEST + INVALID FIELD IN CDB?
@@ -599,6 +668,13 @@ AHCIPort::ScsiInquiry(scsi_ccb* request)
return;
}
if (cmd->evpd) {
// Simulate SCSI VPD data.
ScsiVPDInquiry(request, &ataData);
gSCSI->finished(request, 1);
return;
}
/*
uint8* data = (uint8*)&ataData;
for (int i = 0; i < 512; i += 8) {
@@ -650,31 +726,6 @@ AHCIPort::ScsiInquiry(scsi_ccb* request)
}
}
if (cmd->evpd) {
switch (cmd->page_code) {
case SCSI_PAGE_SUPPORTED_VPD:
case SCSI_PAGE_USN:
case SCSI_PAGE_BLOCK_LIMITS:
//max_unmap_lba_count
// = ataData.max_data_set_management_lba_range_blocks;
//max_unmap_blk_count =
// = ataData.max_data_set_management_lba_range_blocks;
case SCSI_PAGE_BLOCK_DEVICE_CHARS:
case SCSI_PAGE_LB_PROVISIONING:
case SCSI_PAGE_REFERRALS:
ERROR("VPD AHCI page %d not yet implemented!\n",
cmd->page_code);
//request->subsys_status = SCSI_REQ_CMP;
request->subsys_status = SCSI_REQ_ABORTED;
gSCSI->finished(request, 1);
return;
}
ERROR("unknown VPD page code!\n");
request->subsys_status = SCSI_REQ_ABORTED;
gSCSI->finished(request, 1);
return;
}
#if 0
if (fSectorCount < 0x0fffffff) {
TRACE("disabling 48 bit commands\n");
@@ -5,8 +5,12 @@
#ifndef _AHCI_PORT_H
#define _AHCI_PORT_H
#include <ATAInfoBlock.h>
#include "ahci_defs.h"
class AHCIController;
class sata_request;
@@ -32,6 +36,8 @@ public:
private:
void ScsiTestUnitReady(scsi_ccb *request);
void ScsiInquiry(scsi_ccb *request);
void ScsiVPDInquiry(scsi_ccb* request, ata_device_infoblock* ataData);
void ScsiReadCapacity(scsi_ccb *request);
void ScsiReadCapacity16(scsi_ccb *request);
void ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, bool isWrite);