ahci: Pushed TRIM support a tiny bit further.
* Now doesn't do anything on SCSI_OP_UNMAP, instead of doing nothing on SCSI_OP_WRITE_SAME_16.
This commit is contained in:
@@ -51,7 +51,7 @@ AHCIPort::AHCIPort(AHCIController *controller, int index)
|
|||||||
fTestUnitReadyActive(false),
|
fTestUnitReadyActive(false),
|
||||||
fResetPort(false),
|
fResetPort(false),
|
||||||
fError(false),
|
fError(false),
|
||||||
fTrim(false)
|
fTrimSupported(false)
|
||||||
{
|
{
|
||||||
B_INITIALIZE_SPINLOCK(&fSpinlock);
|
B_INITIALIZE_SPINLOCK(&fSpinlock);
|
||||||
fRequestSem = create_sem(1, "ahci request");
|
fRequestSem = create_sem(1, "ahci request");
|
||||||
@@ -604,7 +604,7 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
|
|||||||
if (!fIsATAPI) {
|
if (!fIsATAPI) {
|
||||||
fSectorCount = ataData.SectorCount(fUse48BitCommands, true);
|
fSectorCount = ataData.SectorCount(fUse48BitCommands, true);
|
||||||
fSectorSize = ataData.SectorSize();
|
fSectorSize = ataData.SectorSize();
|
||||||
fTrim = ataData.data_set_management_support;
|
fTrimSupported = ataData.data_set_management_support;
|
||||||
TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %" B_PRIu32
|
TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %" B_PRIu32
|
||||||
", sectors48 %" B_PRIu64 ", size %" B_PRIu64 "\n",
|
", sectors48 %" B_PRIu64 ", size %" B_PRIu64 "\n",
|
||||||
ataData.dma_supported != 0, ataData.lba48_supported != 0,
|
ataData.dma_supported != 0, ataData.lba48_supported != 0,
|
||||||
@@ -634,7 +634,7 @@ AHCIPort::ScsiInquiry(scsi_ccb *request)
|
|||||||
TRACE("model number: %s\n", modelNumber);
|
TRACE("model number: %s\n", modelNumber);
|
||||||
TRACE("serial number: %s\n", serialNumber);
|
TRACE("serial number: %s\n", serialNumber);
|
||||||
TRACE("firmware rev.: %s\n", firmwareRev);
|
TRACE("firmware rev.: %s\n", firmwareRev);
|
||||||
TRACE("trim support: %s\n", fTrim ? "yes" : "no");
|
TRACE("trim support: %s\n", fTrimSupported ? "yes" : "no");
|
||||||
|
|
||||||
// There's not enough space to fit all of the data in. ATA has 40 bytes for
|
// There's not enough space to fit all of the data in. ATA has 40 bytes for
|
||||||
// the model number, 20 for the serial number and another 8 for the
|
// the model number, 20 for the serial number and another 8 for the
|
||||||
@@ -786,6 +786,23 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks)
|
||||||
|
{
|
||||||
|
TRACE("%s unimplemented: TRIM call\n", __func__);
|
||||||
|
|
||||||
|
sata_request* sreq = new(std::nothrow) sata_request(request);
|
||||||
|
if (sreq == NULL) {
|
||||||
|
TRACE("out of memory when allocating unmap request\n");
|
||||||
|
request->subsys_status = SCSI_REQ_ABORTED;
|
||||||
|
gSCSI->finished(request, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete sreq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite)
|
AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite)
|
||||||
{
|
{
|
||||||
@@ -1018,12 +1035,11 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCSI_OP_WRITE_SAME_16:
|
case SCSI_OP_UNMAP:
|
||||||
{
|
{
|
||||||
const scsi_cmd_wsame_16 *cmd = (const scsi_cmd_wsame_16 *)request->cdb;
|
const scsi_cmd_unmap* cmd = (const scsi_cmd_unmap*)request->cdb;
|
||||||
|
|
||||||
// SCSI unmap is used for trim, otherwise we don't support it
|
if (!fTrimSupported) {
|
||||||
if (!cmd->unmap) {
|
|
||||||
TRACE("%s port %d: unsupported request opcode 0x%02x\n",
|
TRACE("%s port %d: unsupported request opcode 0x%02x\n",
|
||||||
__func__, fIndex, request->cdb[0]);
|
__func__, fIndex, request->cdb[0]);
|
||||||
request->subsys_status = SCSI_REQ_ABORTED;
|
request->subsys_status = SCSI_REQ_ABORTED;
|
||||||
@@ -1031,16 +1047,19 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fTrim) {
|
scsi_unmap_parameter_list* unmapBlocks
|
||||||
// Drive doesn't support trim (or atapi)
|
= (scsi_unmap_parameter_list*)request->data;
|
||||||
// Just say it was successful and quit
|
if (unmapBlocks == NULL
|
||||||
request->subsys_status = SCSI_REQ_CMP;
|
|| B_BENDIAN_TO_HOST_INT16(cmd->length) != request->data_length
|
||||||
} else {
|
|| B_BENDIAN_TO_HOST_INT16(unmapBlocks->data_length)
|
||||||
TRACE("%s unimplemented: TRIM call\n", __func__);
|
!= request->data_length - 1) {
|
||||||
// TODO: Make Serial ATA (sata_request?) trim call here.
|
TRACE("%s port %d: invalid unmap parameter data length\n",
|
||||||
|
__func__, fIndex);
|
||||||
request->subsys_status = SCSI_REQ_ABORTED;
|
request->subsys_status = SCSI_REQ_ABORTED;
|
||||||
|
gSCSI->finished(request, 1);
|
||||||
|
} else {
|
||||||
|
ScsiUnmap(request, unmapBlocks);
|
||||||
}
|
}
|
||||||
gSCSI->finished(request, 1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ private:
|
|||||||
void ScsiReadCapacity16(scsi_ccb *request);
|
void ScsiReadCapacity16(scsi_ccb *request);
|
||||||
void ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, bool isWrite);
|
void ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, bool isWrite);
|
||||||
void ScsiSynchronizeCache(scsi_ccb *request);
|
void ScsiSynchronizeCache(scsi_ccb *request);
|
||||||
|
void ScsiUnmap(scsi_ccb* request,
|
||||||
|
struct scsi_unmap_parameter_list* unmapBlocks);
|
||||||
|
|
||||||
void ExecuteSataRequest(sata_request *request, bool isWrite = false);
|
void ExecuteSataRequest(sata_request *request, bool isWrite = false);
|
||||||
|
|
||||||
@@ -71,7 +73,7 @@ private:
|
|||||||
bool fTestUnitReadyActive;
|
bool fTestUnitReadyActive;
|
||||||
bool fResetPort;
|
bool fResetPort;
|
||||||
bool fError;
|
bool fError;
|
||||||
bool fTrim;
|
bool fTrimSupported;
|
||||||
|
|
||||||
volatile fis * fFIS;
|
volatile fis * fFIS;
|
||||||
volatile command_list_entry * fCommandList;
|
volatile command_list_entry * fCommandList;
|
||||||
|
|||||||
Reference in New Issue
Block a user