From 33945c5c8993bedfe46a43a12f27e8178c249dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 15 Aug 2013 01:40:12 +0200 Subject: [PATCH] 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. --- .../kernel/busses/scsi/ahci/ahci_port.cpp | 49 +++++++++++++------ .../kernel/busses/scsi/ahci/ahci_port.h | 4 +- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp index ecc84d00eb..f3de1bb849 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -51,7 +51,7 @@ AHCIPort::AHCIPort(AHCIController *controller, int index) fTestUnitReadyActive(false), fResetPort(false), fError(false), - fTrim(false) + fTrimSupported(false) { B_INITIALIZE_SPINLOCK(&fSpinlock); fRequestSem = create_sem(1, "ahci request"); @@ -604,7 +604,7 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) if (!fIsATAPI) { fSectorCount = ataData.SectorCount(fUse48BitCommands, true); 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 ", sectors48 %" B_PRIu64 ", size %" B_PRIu64 "\n", ataData.dma_supported != 0, ataData.lba48_supported != 0, @@ -634,7 +634,7 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) TRACE("model number: %s\n", modelNumber); TRACE("serial number: %s\n", serialNumber); 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 // 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 AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) { @@ -1018,12 +1035,11 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) } 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 (!cmd->unmap) { + if (!fTrimSupported) { TRACE("%s port %d: unsupported request opcode 0x%02x\n", __func__, fIndex, request->cdb[0]); request->subsys_status = SCSI_REQ_ABORTED; @@ -1031,16 +1047,19 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) break; } - if (!fTrim) { - // Drive doesn't support trim (or atapi) - // Just say it was successful and quit - request->subsys_status = SCSI_REQ_CMP; - } else { - TRACE("%s unimplemented: TRIM call\n", __func__); - // TODO: Make Serial ATA (sata_request?) trim call here. + scsi_unmap_parameter_list* unmapBlocks + = (scsi_unmap_parameter_list*)request->data; + if (unmapBlocks == NULL + || B_BENDIAN_TO_HOST_INT16(cmd->length) != request->data_length + || B_BENDIAN_TO_HOST_INT16(unmapBlocks->data_length) + != request->data_length - 1) { + TRACE("%s port %d: invalid unmap parameter data length\n", + __func__, fIndex); request->subsys_status = SCSI_REQ_ABORTED; + gSCSI->finished(request, 1); + } else { + ScsiUnmap(request, unmapBlocks); } - gSCSI->finished(request, 1); break; } default: diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h index 962e5f7c4b..f89a62246e 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h @@ -36,6 +36,8 @@ private: void ScsiReadCapacity16(scsi_ccb *request); void ScsiReadWrite(scsi_ccb *request, uint64 lba, size_t sectorCount, bool isWrite); void ScsiSynchronizeCache(scsi_ccb *request); + void ScsiUnmap(scsi_ccb* request, + struct scsi_unmap_parameter_list* unmapBlocks); void ExecuteSataRequest(sata_request *request, bool isWrite = false); @@ -71,7 +73,7 @@ private: bool fTestUnitReadyActive; bool fResetPort; bool fError; - bool fTrim; + bool fTrimSupported; volatile fis * fFIS; volatile command_list_entry * fCommandList;