status_t AHCIPort::FillPrdTable(volatile prd *prdTable, int *prdCount, int prdMax, const void *data, size_t dataSize) { int peMax = prdMax + 1; physical_entry pe[peMax]; if (get_memory_map(data, dataSize, pe, peMax ) < B_OK) { TRACE("AHCIPort::FillPrdTable get_memory_map failed\n"); return B_ERROR; } int peUsed; for (peUsed = 0; pe[peUsed].size; peUsed++) ; return FillPrdTable(prdTable, prdCount, prdMax, pe, peUsed, dataSize); }
status_t AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax, const void* data, size_t dataSize) { int maxEntries = prdMax + 1; physical_entry entries[maxEntries]; uint32 entriesUsed = maxEntries; status_t status = get_memory_map_etc(B_CURRENT_TEAM, data, dataSize, entries, &entriesUsed); if (status != B_OK) { TRACE("AHCIPort::FillPrdTable get_memory_map() failed: %s\n", strerror(status)); return B_ERROR; } return FillPrdTable(prdTable, prdCount, prdMax, entries, entriesUsed, dataSize); }
void AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) { FLOW("ExecuteAtaRequest port %d\n", fIndex); StartTransfer(); int prdEntrys; if (request->ccb() && request->ccb()->data_length) { FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->ccb()->sg_list, request->ccb()->sg_count, request->ccb()->data_length); } else if (request->data() && request->size()) { FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->data(), request->size()); } else prdEntrys = 0; FLOW("prdEntrys %d\n", prdEntrys); fCommandList->prdtl_flags_cfl = 0; fCommandList->cfl = 5; // 20 bytes, length in DWORDS memcpy((char *)fCommandTable->cfis, request->fis(), 20); fTestUnitReadyActive = request->is_test_unit_ready(); if (request->is_atapi()) { // ATAPI PACKET is a 12 or 16 byte SCSI command memset((char *)fCommandTable->acmd, 0, 32); memcpy((char *)fCommandTable->acmd, request->ccb()->cdb, request->ccb()->cdb_length); fCommandList->a = 1; } if (isWrite) fCommandList->w = 1; fCommandList->prdtl = prdEntrys; fCommandList->prdbc = 0; if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 1000000) < B_OK) { TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex); ResetPort(); FinishTransfer(); request->abort(); return; } cpu_status cpu = disable_interrupts(); acquire_spinlock(&fSpinlock); fCommandsActive |= 1; fRegs->ci = 1; FlushPostedWrites(); release_spinlock(&fSpinlock); restore_interrupts(cpu); int tfd; status_t status = WaitForTransfer(&tfd, 20000000); FLOW("tfd %#x\n", tfd); FLOW("prdbc %ld\n", fCommandList->prdbc); FLOW("ci 0x%08" B_PRIx32 "\n", fRegs->ci); FLOW("is 0x%08" B_PRIx32 "\n", fRegs->is); FLOW("serr 0x%08" B_PRIx32 "\n", fRegs->serr); /* TRACE("ci 0x%08" B_PRIx32 "\n", fRegs->ci); TRACE("ie 0x%08" B_PRIx32 "\n", fRegs->ie); TRACE("is 0x%08" B_PRIx32 "\n", fRegs->is); TRACE("cmd 0x%08" B_PRIx32 "\n", fRegs->cmd); TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts); TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl); TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr); TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact); TRACE("tfd 0x%08" B_PRIx32 "\n", fRegs->tfd); */ if (fResetPort || status == B_TIMED_OUT) { fResetPort = false; ResetPort(); } size_t bytesTransfered = fCommandList->prdbc; FinishTransfer(); if (status == B_TIMED_OUT) { TRACE("ExecuteAtaRequest port %d: device timeout\n", fIndex); request->abort(); } else { request->finish(tfd, bytesTransfered); } }