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:
Axel Dörfler
2013-11-07 19:03:55 +01:00
parent 99086aa323
commit 33945c5c89
2 changed files with 37 additions and 16 deletions
@@ -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); gSCSI->finished(request, 1);
} else {
ScsiUnmap(request, unmapBlocks);
}
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;