diff --git a/src/add-ons/kernel/busses/scsi/ahci/Jamfile b/src/add-ons/kernel/busses/scsi/ahci/Jamfile index bb1822a019..57bd0a805a 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/Jamfile +++ b/src/add-ons/kernel/busses/scsi/ahci/Jamfile @@ -8,5 +8,6 @@ KernelAddon ahci : ahci_controller.cpp ahci_port.cpp ahci_sim.cpp + sata_request.cpp util.c ; diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci.c b/src/add-ons/kernel/busses/scsi/ahci/ahci.c index 68bc32552f..a85393d0f9 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci.c +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci.c @@ -17,8 +17,6 @@ #define AHCI_ID_GENERATOR "ahci/id" #define AHCI_ID_ITEM "ahci/id" -device_manager_info *gDeviceManager; - const device_info kSupportedDevices[] = { { 0x1002, 0x4380, "ATI SB600" }, @@ -372,12 +370,15 @@ driver_module_info sAHCIDevice = { ahci_get_supported_paths, }; + module_dependency module_dependencies[] = { { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager }, +// { B_PCI_MODULE_NAME, (module_info **)&gPCI }, { SCSI_FOR_SIM_MODULE_NAME, (module_info **)&gSCSI }, {} }; + module_info *modules[] = { (module_info *)&sAHCIDevice, (module_info *)&gAHCISimInterface, 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 36c7e6d6b4..c08cd25f2c 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -8,6 +8,7 @@ #include "util.h" #include "ata_cmds.h" #include "scsi_cmds.h" +#include "sata_request.h" #include #include @@ -15,9 +16,9 @@ #include #define TRACE(a...) dprintf("\33[34mahci:\33[0m " a) -// #define FLOW(a...) dprintf("ahci: " a) -#define FLOW(a...) +//#define FLOW(a...) dprintf("ahci: " a) //#define RWTRACE(a...) dprintf("\33[34mahci:\33[0m " a) +#define FLOW(a...) #define RWTRACE(a...) @@ -400,9 +401,10 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) TRACE("AHCIPort::ScsiInquiry port %d\n", fIndex); scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)request->cdb; - scsi_res_inquiry scsiData; ata_res_identify_device ataData; + ASSERT(sizeof(ataData) == 512); + if (cmd->evpd || cmd->page_code) { TRACE("invalid request\n"); request->subsys_status = SCSI_REQ_ABORTED; @@ -410,67 +412,27 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) return; } - memset(&ataData, 0, sizeof(ataData)); + sata_request sreq; + sreq.set_data(&ataData, sizeof(ataData)); + sreq.set_ata_cmd(0xec); // Identify Device + ExecuteSataRequest(&sreq); + sreq.wait_for_completition(); - StartTransfer(); - - int prdEntrys; - FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, &ataData, sizeof(ataData)); - - - FLOW("prdEntrys %d\n", prdEntrys); - - memset((void *)fCommandTable->cfis, 0, 5 * 4); - fCommandTable->cfis[0] = 0x27; - fCommandTable->cfis[1] = 0x80; - fCommandTable->cfis[2] = 0xec; - - - fCommandList->prdtl_flags_cfl = 0; - fCommandList->prdtl = prdEntrys; - fCommandList->cfl = 5; - fCommandList->prdbc = 0; - - if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 4000000) < B_OK) { - TRACE("device is busy\n"); - FinishTransfer(); - request->subsys_status = SCSI_REQ_ABORTED; + if (sreq.completition_status() & ATA_ERR) { + TRACE("identify device failed\n"); + request->subsys_status = SCSI_REQ_CMP_ERR; 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); - - 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); - TRACE("ie 0x%08lx\n", fRegs->ie); - TRACE("is 0x%08lx\n", fRegs->is); - TRACE("cmd 0x%08lx\n", fRegs->cmd); - TRACE("ssts 0x%08lx\n", fRegs->ssts); - TRACE("sctl 0x%08lx\n", fRegs->sctl); - TRACE("serr 0x%08lx\n", fRegs->serr); - TRACE("sact 0x%08lx\n", fRegs->sact); - TRACE("tfd 0x%08lx\n", fRegs->tfd); - uint8 *data = (uint8*) &ataData; for (int i = 0; i < 512; i += 8) { TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); } */ + + scsi_res_inquiry scsiData; scsiData.device_type = scsi_dev_direct_access; scsiData.device_qualifier = scsi_periph_qual_connected; scsiData.device_type_modifier = 0; @@ -532,13 +494,21 @@ AHCIPort::ScsiInquiry(scsi_ccb *request) request->data_resid = request->data_length - sizeof(scsiData);// ??? request->data_length = sizeof(scsiData); // ??? } - - FinishTransfer(); - gSCSI->finished(request, 1); } +void +AHCIPort::ScsiSynchronizeCache(scsi_ccb *request) +{ + TRACE("AHCIPort::ScsiSynchronizeCache port %d\n", fIndex); + + sata_request *sreq = new sata_request(request); + sreq->set_ata_cmd(fUse48BitCommands ? 0xea : 0xe7); // Flush Cache + ExecuteSataRequest(sreq); +} + + void AHCIPort::ScsiReadCapacity(scsi_ccb *request) { @@ -575,7 +545,6 @@ void AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool isWrite) { uint32 bytecount = length * 512; - RWTRACE("ScsiReadWrite: position %llu, size %lu, isWrite %d\n", position * 512, bytecount, isWrite); #if 0 @@ -587,60 +556,61 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool return; } #endif - - StartTransfer(); - - int prdEntrys; - FillPrdTable(fPRDTable, &prdEntrys, PRD_TABLE_ENTRY_COUNT, request->sg_list, request->sg_count, bytecount); - - FLOW("prdEntrys %d\n", prdEntrys); - memset((void *)fCommandTable->cfis, 0, 5 * 4); + request->data_length = bytecount; // XXX really? + sata_request *sreq = new sata_request(request); if (fUse48BitCommands) { if (length > 65536) panic("ahci: ScsiReadWrite length too large, %lu sectors", length); - fCommandTable->cfis[0] = 0x27; - fCommandTable->cfis[1] = 0x80; - fCommandTable->cfis[2] = isWrite ? 0x35 : 0x25; - fCommandTable->cfis[4] = position & 0xff; - fCommandTable->cfis[5] = (position >> 8) & 0xff; - fCommandTable->cfis[6] = (position >> 16) & 0xff; - fCommandTable->cfis[7] = 0x40; - fCommandTable->cfis[8] = (position >> 24) & 0xff; - fCommandTable->cfis[9] = (position >> 32) & 0xff; - fCommandTable->cfis[10] = (position >> 40) & 0xff; - fCommandTable->cfis[12] = length & 0xff; - fCommandTable->cfis[13] = (length >> 8) & 0xff; + if (position > MAX_SECTOR_LBA_48) + panic("achi: ScsiReadWrite position too large for 48-bit LBA\n"); + sreq->set_ata48_cmd(isWrite ? 0x35 : 0x25, position, length); } else { if (length > 256) panic("ahci: ScsiReadWrite length too large, %lu sectors", length); - if (position > 0x0fffffff) - panic("achi: ScsiReadWrite position too large for non-48-bit LBA\n"); - fCommandTable->cfis[0] = 0x27; - fCommandTable->cfis[1] = 0x80; - fCommandTable->cfis[2] = isWrite ? 0xca : 0xc8; - fCommandTable->cfis[4] = position & 0xff; - fCommandTable->cfis[5] = (position >> 8) & 0xff; - fCommandTable->cfis[6] = (position >> 16) & 0xff; - fCommandTable->cfis[7] = 0x40 | ((position >> 24) & 0x0f); - fCommandTable->cfis[12] = length & 0xff; + if (position > MAX_SECTOR_LBA_28) + panic("achi: ScsiReadWrite position too large for normal LBA\n"); + sreq->set_ata28_cmd(isWrite ? 0xca : 0xc8, position, length); } + ExecuteSataRequest(sreq, isWrite); +} + + +void +AHCIPort::ExecuteSataRequest(sata_request *request, bool isWrite) +{ + FLOW("ExecuteAtaRequest port %d\n", fIndex); + + StartTransfer(); + + int prdEntrys; + + if (request->ccb()) + 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); + + memcpy((char *)fCommandTable->cfis, request->fis(), 20); fCommandList->prdtl_flags_cfl = 0; - fCommandList->prdtl = prdEntrys; - fCommandList->cfl = 5; + fCommandList->cfl = 5; // length is 20 bytes, in DWORDS if (isWrite) fCommandList->w = 1; + fCommandList->prdtl = prdEntrys; fCommandList->prdbc = 0; - if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 4000000) < B_OK) { - TRACE("device is busy\n"); + if (wait_until_clear(&fRegs->tfd, ATA_BSY | ATA_DRQ, 1000000) < B_OK) { + TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex); FinishTransfer(); - request->subsys_status = SCSI_REQ_ABORTED; - gSCSI->finished(request, 1); + request->abort(); return; } + cpu_status cpu = disable_interrupts(); acquire_spinlock(&fSpinlock); fRegs->ci |= 1; @@ -650,28 +620,35 @@ AHCIPort::ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool restore_interrupts(cpu); int tfd; - status_t status = WaitForTransfer(&tfd, 4000000); + status_t status = WaitForTransfer(&tfd, 5000000); + FLOW("tfd %#x\n", tfd); 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); - if (status < B_OK) { - TRACE("ScsiReadWrite port %d: device timeout\n", fIndex); - request->subsys_status = SCSI_REQ_ABORTED; - } else if (tfd & ATA_ERR) { - TRACE("ScsiReadWrite port %d: device error\n", fIndex); - request->subsys_status = SCSI_REQ_ABORTED; - } else if (fCommandList->prdbc != bytecount) { - TRACE("ScsiReadWrite port %d: should never happen\n", fIndex); - 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; // ??? +/* + TRACE("ci 0x%08lx\n", fRegs->ci); + TRACE("ie 0x%08lx\n", fRegs->ie); + TRACE("is 0x%08lx\n", fRegs->is); + TRACE("cmd 0x%08lx\n", fRegs->cmd); + TRACE("ssts 0x%08lx\n", fRegs->ssts); + TRACE("sctl 0x%08lx\n", fRegs->sctl); + TRACE("serr 0x%08lx\n", fRegs->serr); + TRACE("sact 0x%08lx\n", fRegs->sact); + TRACE("tfd 0x%08lx\n", fRegs->tfd); +*/ + + size_t bytesTransfered = fCommandList->prdbc; FinishTransfer(); - gSCSI->finished(request, 1); + if (status < B_OK) { + TRACE("ExecuteAtaRequest port %d: device transfer timeout\n", fIndex); + request->abort(); + } else + request->finish(tfd, bytesTransfered); } @@ -687,7 +664,7 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) } if (!fDevicePresent) { - TRACE("no such device!\n"); + TRACE("no device present on port %d\n", fIndex); request->subsys_status = SCSI_DEV_NOT_THERE; gSCSI->finished(request, 1); return; @@ -705,6 +682,9 @@ AHCIPort::ScsiExecuteRequest(scsi_ccb *request) case SCSI_OP_READ_CAPACITY: ScsiReadCapacity(request); break; + case SCSI_OP_SYNCHRONIZE_CACHE: + ScsiSynchronizeCache(request); + break; case SCSI_OP_READ_6: case SCSI_OP_WRITE_6: { 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 cf7eb551d0..0bca6a6d69 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h @@ -8,6 +8,7 @@ #include "ahci_defs.h" class AHCIController; +class sata_request; class AHCIPort { public: @@ -32,6 +33,9 @@ private: void ScsiInquiry(scsi_ccb *request); void ScsiReadCapacity(scsi_ccb *request); void ScsiReadWrite(scsi_ccb *request, uint64 position, size_t length, bool isWrite); + void ScsiSynchronizeCache(scsi_ccb *request); + + void ExecuteSataRequest(sata_request *request, bool isWrite = false); status_t ResetDevice(); status_t PostResetDevice(); 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 f236454556..9bf2ad76be 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp @@ -15,6 +15,7 @@ pci_device_module_info *gPCI; +device_manager_info *gDeviceManager; scsi_for_sim_interface *gSCSI;