From 9382f576917776521166203d7a1ecde8aaab8341 Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Tue, 11 Sep 2007 22:09:13 +0000 Subject: [PATCH] correct port number handling allocate memory for command list and fis git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22221 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../busses/scsi/ahci/ahci_controller.cpp | 22 ++++----- .../kernel/busses/scsi/ahci/ahci_controller.h | 4 +- .../kernel/busses/scsi/ahci/ahci_defs.h | 49 ++++++++++++++++++- .../kernel/busses/scsi/ahci/ahci_port.cpp | 39 +++++++++++++++ .../kernel/busses/scsi/ahci/ahci_port.h | 2 + 5 files changed, 100 insertions(+), 16 deletions(-) diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp index 4fa28187c7..8041a8cbec 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp @@ -21,8 +21,8 @@ AHCIController::AHCIController(device_node_handle node, pci_device_info *device) , fPCIVendorID(0xffff) , fPCIDeviceID(0xffff) , fCommandSlotCount(0) - , fPortCount(0) - , fPortMax(0) + , fPortCountMax(0) + , fPortCountAvail(0) , fIRQ(0) , fInstanceCheck(-1) { @@ -90,15 +90,13 @@ AHCIController::Init() } fCommandSlotCount = 1 + ((fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); - fPortCount = 1 + ((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); + fPortCountMax = 1 + ((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); + fPortCountAvail = count_bits_set(fRegs->pi); if (fRegs->pi == 0) { TRACE("controller doesn't implement any ports\n"); goto err; } - fPortMax = 31; - while ((fRegs->pi & (1 << fPortMax)) == 0) - fPortMax--; fIRQ = gPCI->read_pci_config(fPCIDevice, PCI_interrupt_line, 1); if (fIRQ == 0 || fIRQ == 0xff) { @@ -108,7 +106,7 @@ AHCIController::Init() TRACE("cap: Interface Speed Support: generation %lu\n", (fRegs->cap >> CAP_ISS_SHIFT) & CAP_ISS_MASK); TRACE("cap: Number of Command Slots: %d (raw %#lx)\n", fCommandSlotCount, (fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); - TRACE("cap: Number of Ports: %d (raw %#lx)\n", fPortCount, (fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); + TRACE("cap: Number of Ports: %d (raw %#lx)\n", fPortCountMax, (fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); TRACE("cap: Supports Port Multiplier: %s\n", (fRegs->cap & CAP_SPM) ? "yes" : "no"); TRACE("cap: Supports External SATA: %s\n", (fRegs->cap & CAP_SXS) ? "yes" : "no"); TRACE("cap: Enclosure Management Supported: %s\n", (fRegs->cap & CAP_EMS) ? "yes" : "no"); @@ -121,8 +119,8 @@ AHCIController::Init() TRACE("cap: Supports AHCI mode only: %s\n", (fRegs->cap & CAP_SAM) ? "yes" : "no"); TRACE("ghc: AHCI Enable: %s\n", (fRegs->ghc & GHC_AE) ? "yes" : "no"); - TRACE("Ports Implemented: %08lx\n", fRegs->pi); - TRACE("Highest port Number: %d\n", fPortMax); + TRACE("Ports Implemented Mask: %#08lx\n", fRegs->pi); + TRACE("Number of Available Ports: %d\n", fPortCountAvail); TRACE("AHCI Version %lu.%lu\n", fRegs->vs >> 16, fRegs->vs & 0xff); TRACE("Interrupt %u\n", fIRQ); @@ -132,7 +130,7 @@ AHCIController::Init() goto err; } - for (int i = 0; i <= fPortMax; i++) { + for (int i = 0; i <= fPortCountMax; i++) { if (fRegs->pi & (1 << i)) { fPort[i] = new (std::nothrow)AHCIPort(this, i); if (!fPort[i]) { @@ -166,7 +164,7 @@ AHCIController::Uninit() { TRACE("AHCIController::Uninit\n"); - for (int i = 0; i <= fPortMax; i++) { + for (int i = 0; i <= fPortCountMax; i++) { if (fPort[i]) { fPort[i]->Uninit(); delete fPort[i]; @@ -233,7 +231,7 @@ AHCIController::Interrupt(void *data) if (int_stat == 0) return B_UNHANDLED_INTERRUPT; - for (int i = 0; i < self->fPortMax; i++) { + for (int i = 0; i < self->fPortCountMax; i++) { if (int_stat & (1 << i)) { if (self->fPort[i]) { self->fPort[i]->Interrupt(); diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h index 25e2f5ffc1..bbded5f248 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h @@ -44,8 +44,8 @@ private: volatile ahci_hba * fRegs; area_id fRegsArea; int fCommandSlotCount; - int fPortCount; - int fPortMax; + int fPortCountMax; + int fPortCountAvail; uint8 fIRQ; AHCIPort * fPort[32]; diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h index 23ab9aa9cf..7e20cfec78 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h @@ -47,10 +47,37 @@ enum { }; +enum { + INT_CPD = (1 << 31), // Cold Port Detect Status/Enable + INT_TFE = (1 << 30), // Task File Error Status/Enable + INT_HBF = (1 << 29), // Host Bus Fatal Error Status/Enable + INT_HBD = (1 << 28), // Host Bus Data Error Status/Enable + INT_IF = (1 << 27), // Interface Fatal Error Status/Enable + INT_INF = (1 << 26), // Interface Non-fatal Error Status/Enable + INT_OF = (1 << 24), // Overflow Status/Enable + INT_IPM = (1 << 23), // Incorrect Port Multiplier Status/Enable + INT_PRC = (1 << 22), // PhyRdy Change Status/Enable + INT_DMP = (1 << 7), // Device Mechanical Presence Status/Enable + INT_PC = (1 << 6), // Port Change Interrupt Status/Enable + INT_DP = (1 << 5), // Descriptor Processed Interrupt/Enable + INT_UF = (1 << 4), // Unknown FIS Interrupt/Enable + INT_SDB = (1 << 3), // Set Device Bits Interrupt/Enable + INT_DS = (1 << 2), // DMA Setup FIS Interrupt/Enable + INT_PS = (1 << 1), // PIO Setup FIS Interrupt/Enable + INT_DHR = (1 << 0), // Device to Host Register FIS Interrupt/Enable +}; + + +enum { + AHCI_CLB_SIZE = 1024, + AHCI_FIS_SIZE = 256, +}; + + typedef struct { - uint32 clb; // Command List Base Address + uint32 clb; // Command List Base Address (alignment 1024 byte) uint32 clbu; // Command List Base Address Upper 32-Bits - uint32 fb; // FIS Base Address + uint32 fb; // FIS Base Address (alignment 256 byte) uint32 fbu; // FIS Base Address Upper 32-Bits uint32 is; // Interrupt Status uint32 ie; // Interrupt Enable @@ -91,4 +118,22 @@ extern device_manager_info *gDeviceManager; extern pci_device_module_info *gPCI; extern scsi_for_sim_interface *gSCSI; +#define LO32(val) ((uint32)(val)) +#define HI32(val) (((uint64)(val)) >> 32) + +#ifdef __cplusplus + +template +int count_bits_set(T value) +{ + int count = 0; + for (T mask = 1; mask; mask <<= 1) + if (value & mask) + count++; + return count; +} + +#endif /* __cplusplus */ + + #endif /* _AHCI_DEFS_H */ 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 62a1fe0055..f9d670a2c2 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -5,6 +5,7 @@ #include "ahci_port.h" #include "ahci_controller.h" +#include "util.h" #include #include @@ -16,6 +17,7 @@ AHCIPort::AHCIPort(AHCIController *controller, int index) : fIndex(index) , fRegs(&controller->fRegs->port[index]) + , fArea(-1) { } @@ -29,6 +31,29 @@ status_t AHCIPort::Init() { TRACE("AHCIPort::Init port %d\n", fIndex); + + size_t size = 999; + + void *virtAddr; + void *physAddr; + + fArea = alloc_mem(&virtAddr, &physAddr, size, 0, "some AHCI port"); + if (fArea < B_OK) { + TRACE("failed allocating memory for port %d\n", fIndex); + return fArea; + } + + void *virtClbAddr; + void *physClbAddr = physAddr; + void *virtFisAddr; + void *physFisAddr = (char *)physAddr + 1024; + + + fRegs->clb = LO32(physClbAddr); + fRegs->clbu = HI32(physClbAddr); + fRegs->fb = LO32(physFisAddr); + fRegs->fbu = HI32(physFisAddr); + return B_OK; } @@ -37,6 +62,20 @@ void AHCIPort::Uninit() { TRACE("AHCIPort::Uninit port %d\n", fIndex); + + // disable interrupts + fRegs->ie = 0; + + // clear pending interrupts + fRegs->is = fRegs->is; + + // invalidate DMA addresses + fRegs->clb = 0; + fRegs->clbu = 0; + fRegs->fb = 0; + fRegs->fbu = 0; + + delete_area(fArea); } 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 ca487d9c83..ce58406205 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h @@ -25,10 +25,12 @@ public: uchar TerminateRequest(scsi_ccb *request); uchar ResetDevice(); +private: private: int fIndex; volatile ahci_port * fRegs; +area_id fArea; }; #endif // _AHCI_PORT_H