From a2a169feab7494700b4595eaa6f144c5fefaa2f2 Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Sun, 30 Sep 2007 15:12:39 +0000 Subject: [PATCH] Improved interrupt handling Removed DBC_I interrupt Reduce debug output git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22386 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/busses/scsi/ahci/ahci_port.cpp | 114 ++++++++++++------ .../kernel/busses/scsi/ahci/ahci_port.h | 9 +- .../kernel/busses/scsi/ahci/ahci_sim.cpp | 7 +- 3 files changed, 84 insertions(+), 46 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 da701318d1..f6f841939f 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -23,16 +23,17 @@ AHCIPort::AHCIPort(AHCIController *controller, int index) : fIndex(index) , fRegs(&controller->fRegs->port[index]) , fArea(-1) + , fSpinlock(0) + , fCommandsActive(0) , fRequestSem(-1) , fResponseSem(-1) - , fCommandActive(false) , fDevicePresent(false) , fUse48BitCommands(false) , fSectorSize(0) , fSectorCount(0) { fRequestSem = create_sem(1, "ahci request"); - fResponseSem = create_sem(1, "ahci response"); + fResponseSem = create_sem(0, "ahci response"); } @@ -269,18 +270,30 @@ void AHCIPort::Interrupt() { uint32 is = fRegs->is; - TRACE("AHCIPort::Interrupt port %d, status %#08lx\n", fIndex, is); + uint32 ci = fRegs->ci; + fRegs->is = is; // clear interrupts - if (fCommandActive) + FLOW("AHCIPort::Interrupt port %d, fCommandsActive 0x%08lx, is 0x%08lx, ci 0x%08lx\n", fIndex, fCommandsActive, is, ci); + + int release = 0; + + acquire_spinlock(&fSpinlock); + if ((fCommandsActive & 1) && !(ci & 1)) { + release = 1; + fCommandsActive &= ~1; + } + release_spinlock(&fSpinlock); + + if (is & PORT_INT_FATAL) + panic("ahci fatal error, is 0x%08lx", is); + + if (release) release_sem_etc(fResponseSem, 1, B_RELEASE_IF_WAITING_ONLY | B_DO_NOT_RESCHEDULE); - - // clear interrupts - fRegs->is = is; } status_t -AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize, bool ioc) +AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize) { int peMax = prdMax + 1; physical_entry pe[peMax]; @@ -291,12 +304,12 @@ AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const int peUsed; for (peUsed = 0; pe[peUsed].size; peUsed++) ; - return FillPrdTable(prdTable, prdCount, prdMax, pe, peUsed, dataSize, ioc); + return FillPrdTable(prdTable, prdCount, prdMax, pe, peUsed, dataSize); } status_t -AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize, bool ioc) +AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize) { *prdCount = 0; while (sgCount > 0 && dataSize > 0) { @@ -335,8 +348,6 @@ AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const TRACE("AHCIPort::FillPrdTable: sg table %ld bytes too small\n", dataSize); return B_ERROR; } - if (ioc) - (prdTable - 1)->dbc |= DBC_I; return B_OK; } @@ -345,18 +356,19 @@ void AHCIPort::StartTransfer() { acquire_sem(fRequestSem); - fCommandActive = true; } status_t -AHCIPort::WaitForTransfer(int *status, bigtime_t timeout) +AHCIPort::WaitForTransfer(int *tfd, bigtime_t timeout) { status_t result = B_OK; if (acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT, timeout) < B_OK) { + fCommandsActive &= ~1; result = B_TIMED_OUT; + } else { + *tfd = fRegs->tfd; } - fCommandActive = false; return result; } @@ -398,10 +410,10 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) StartTransfer(); int prdEntrys; - FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, &ataData, sizeof(ataData), true); + FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, &ataData, sizeof(ataData)); - TRACE("prdEntrys %d\n", prdEntrys); + FLOW("prdEntrys %d\n", prdEntrys); memset((void *)fCommandTable->cfis, 0, 5 * 4); fCommandTable->cfis[0] = 0x27; @@ -421,16 +433,22 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) gSCSI->finished(request, 1); return; } + + cpu_status cpu = disable_interrupts(); + acquire_spinlock(&fSpinlock); fRegs->ci |= 1; FlushPostedWrites(); + fCommandsActive |= 1; + release_spinlock(&fSpinlock); + restore_interrupts(cpu); int status; WaitForTransfer(&status, 100000); - TRACE("prdbc %ld\n", fCommandList->prdbc); - TRACE("ci 0x%08lx\n", fRegs->ci); - TRACE("is 0x%08lx\n", fRegs->is); - TRACE("serr 0x%08lx\n", fRegs->serr); + FLOW("prdbc %ld\n", fCommandList->prdbc); + FLOW("ci 0x%08lx\n", fRegs->ci); + FLOW("is 0x%08lx\n", fRegs->is); + FLOW("serr 0x%08lx\n", fRegs->serr); /* TRACE("ci 0x%08lx\n", fRegs->ci); @@ -484,13 +502,21 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) } #endif - swap_words(ataData.model_number, sizeof(ataData.model_number)); - swap_words(ataData.serial_number, sizeof(ataData.serial_number)); - swap_words(ataData.firmware_revision, sizeof(ataData.firmware_revision)); + char modelNumber[sizeof(ataData.model_number) + 1]; + char serialNumber[sizeof(ataData.serial_number) + 1]; + char firmwareRev[sizeof(ataData.firmware_revision) + 1]; - TRACE("model_number: %40s\n", ataData.model_number); - TRACE("serial_number: %20s\n", ataData.serial_number); - TRACE("firmware_revision: %8s\n", ataData.firmware_revision); + strlcpy(modelNumber, ataData.model_number, sizeof(modelNumber)); + strlcpy(serialNumber, ataData.serial_number, sizeof(serialNumber)); + strlcpy(firmwareRev, ataData.firmware_revision, sizeof(firmwareRev)); + + swap_words(modelNumber, sizeof(modelNumber) - 1); + swap_words(serialNumber, sizeof(serialNumber) - 1); + swap_words(firmwareRev, sizeof(firmwareRev) - 1); + + TRACE("model number: %s\n", modelNumber); + TRACE("serial number: %s\n", serialNumber); + TRACE("firmware rev.: %s\n", firmwareRev); TRACE("lba %d, lba48 %d, fUse48BitCommands %d, sectors %lu, sectors48 %llu, size %llu\n", lba, lba48, fUse48BitCommands, sectors, sectors48, fSectorCount * fSectorSize); @@ -502,7 +528,6 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) request->data_length = sizeof(scsiData); // ??? } - fRegs->ci &= ~1; FinishTransfer(); gSCSI->finished(request, 1); @@ -544,7 +569,9 @@ AHCIPort::ScsiReadCapacity(scsi_ccb *request) void AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool isWrite) { - TRACE("ScsiReadWrite: pos %llu, size %lu, isWrite %d\n", position, length, isWrite); + uint32 bytecount = length * 512; + + TRACE("ScsiReadWrite: position %llu, size %lu, isWrite %d\n", position * 512, bytecount, isWrite); #if 1 if (isWrite) { @@ -559,7 +586,7 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool StartTransfer(); int prdEntrys; - FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->sg_list, request->sg_count, length * 512, true); + FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->sg_list, request->sg_count, bytecount); FLOW("prdEntrys %d\n", prdEntrys); @@ -605,22 +632,31 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool gSCSI->finished(request, 1); return; } + cpu_status cpu = disable_interrupts(); + acquire_spinlock(&fSpinlock); fRegs->ci |= 1; FlushPostedWrites(); + fCommandsActive |= 1; + release_spinlock(&fSpinlock); + restore_interrupts(cpu); - int status; - WaitForTransfer(&status, 100000); + int tfd; + status_t status = WaitForTransfer(&tfd, 4000000); - TRACE("prdbc %ld\n", fCommandList->prdbc); - TRACE("ci 0x%08lx\n", fRegs->ci); - TRACE("is 0x%08lx\n", fRegs->is); - TRACE("serr 0x%08lx\n", fRegs->serr); + FLOW("prdbc %ld\n", fCommandList->prdbc); - request->subsys_status = SCSI_REQ_CMP; + if (status < B_OK || (tfd & ATA_ERR)) { + TRACE("device error\n"); + request->subsys_status = SCSI_REQ_ABORTED; + } else if (fCommandList->prdbc != bytecount) { + TRACE("should never happen\n"); + request->subsys_status = SCSI_REQ_CMP_ERR; + } else { + request->subsys_status = SCSI_REQ_CMP; + } request->data_resid = request->data_length - fCommandList->prdbc;// ??? request->data_length = fCommandList->prdbc; // ??? - fRegs->ci &= ~1; FinishTransfer(); gSCSI->finished(request, 1); @@ -631,7 +667,7 @@ void AHCIPort::ScsiExecuteRequest(scsi_ccb *request) { - TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); +// TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) { panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n"); 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 e1f2ba155c..300f06ed92 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h @@ -38,21 +38,22 @@ private: void DumpD2HFis(); void StartTransfer(); - status_t WaitForTransfer(int *status, bigtime_t timeout); + status_t WaitForTransfer(int *tfd, bigtime_t timeout); void FinishTransfer(); // uint8 * SetCommandFis(volatile command_list_entry *cmd, volatile fis *fis, const void *data, size_t dataSize); - status_t FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize, bool ioc = false); - status_t FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize, bool ioc = false); + status_t FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize); + status_t FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const physical_entry *sgTable, int sgCount, size_t dataSize); private: int fIndex; volatile ahci_port * fRegs; area_id fArea; + spinlock fSpinlock; + volatile uint32 fCommandsActive; sem_id fRequestSem; sem_id fResponseSem; - volatile bool fCommandActive; bool fDevicePresent; bool fUse48BitCommands; uint32 fSectorSize; diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp index e3b1e55baf..2998c4525a 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp @@ -10,7 +10,8 @@ #include #define TRACE(a...) dprintf("\33[34mahci:\33[0m " a) -#define FLOW(a...) dprintf("ahci: " a) +//#define FLOW(a...) dprintf("ahci: " a) +#define FLOW(a...) pci_device_module_info *gPCI; @@ -24,7 +25,7 @@ scsi_for_sim_interface *gSCSI; static void ahci_scsi_io(scsi_sim_cookie cookie, scsi_ccb *request) { - TRACE("ahci_scsi_io, cookie %p, path_id %u, target_id %u, target_lun %u\n", + FLOW("ahci_scsi_io, cookie %p, path_id %u, target_id %u, target_lun %u\n", cookie, request->path_id, request->target_id, request->target_lun); static_cast(cookie)->ExecuteRequest(request); } @@ -105,7 +106,7 @@ ahci_get_restrictions(scsi_sim_cookie cookie, uchar targetID, bool *isATAPI, *isATAPI = false; *noAutoSense = false; - *maxBlocks = 255; + *maxBlocks = 256; }