1 /* 2 * Copyright 2007-2009, Marcus Overhagen. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "ahci_controller.h" 7 #include "util.h" 8 9 #include <KernelExport.h> 10 #include <stdio.h> 11 #include <string.h> 12 #include <new> 13 14 #define TRACE(a...) dprintf("ahci: " a) 15 #define FLOW(a...) dprintf("ahci: " a) 16 17 18 AHCIController::AHCIController(device_node *node, 19 pci_device_module_info *pciModule, pci_device *device) 20 : 21 fNode(node), 22 fPCI(pciModule), 23 fPCIDevice(device), 24 fPCIVendorID(0xffff), 25 fPCIDeviceID(0xffff), 26 fFlags(0), 27 fCommandSlotCount(0), 28 fPortCountMax(0), 29 fPortCountAvail(0), 30 fPortImplementedMask(0), 31 fIRQ(0), 32 fInstanceCheck(-1) 33 { 34 memset(fPort, 0, sizeof(fPort)); 35 36 ASSERT(sizeof(ahci_port) == 128); 37 ASSERT(sizeof(ahci_hba) == 4352); 38 ASSERT(sizeof(fis) == 256); 39 ASSERT(sizeof(command_list_entry) == 32); 40 ASSERT(sizeof(command_table) == 128); 41 ASSERT(sizeof(prd) == 16); 42 } 43 44 45 AHCIController::~AHCIController() 46 { 47 } 48 49 50 status_t 51 AHCIController::Init() 52 { 53 pci_info pciInfo; 54 fPCI->get_pci_info(fPCIDevice, &pciInfo); 55 56 fPCIVendorID = pciInfo.vendor_id; 57 fPCIDeviceID = pciInfo.device_id; 58 59 TRACE("AHCIController::Init %u:%u:%u vendor %04x, device %04x\n", 60 pciInfo.bus, pciInfo.device, pciInfo.function, fPCIVendorID, fPCIDeviceID); 61 62 // --- Instance check workaround begin 63 char sName[32]; 64 snprintf(sName, sizeof(sName), "ahci-inst-%u-%u-%u", pciInfo.bus, pciInfo.device, pciInfo.function); 65 if (find_port(sName) >= 0) { 66 dprintf("AHCIController::Init ERROR: an instance for object %u:%u:%u already exists\n", 67 pciInfo.bus, pciInfo.device, pciInfo.function); 68 return B_ERROR; 69 } 70 fInstanceCheck = create_port(1, sName); 71 // --- Instance check workaround end 72 73 get_device_info(fPCIVendorID, fPCIDeviceID, NULL, &fFlags); 74 75 uchar capabilityOffset; 76 status_t res = fPCI->find_pci_capability(fPCIDevice, PCI_cap_id_sata, &capabilityOffset); 77 if (res == B_OK) { 78 uint32 satacr0; 79 uint32 satacr1; 80 TRACE("PCI SATA capability found at offset 0x%x\n", capabilityOffset); 81 satacr0 = fPCI->read_pci_config(fPCIDevice, capabilityOffset, 4); 82 satacr1 = fPCI->read_pci_config(fPCIDevice, capabilityOffset + 4, 4); 83 TRACE("satacr0 = 0x%08lx, satacr1 = 0x%08lx\n", satacr0, satacr1); 84 } 85 86 uint16 pcicmd = fPCI->read_pci_config(fPCIDevice, PCI_command, 2); 87 TRACE("pcicmd old 0x%04x\n", pcicmd); 88 pcicmd &= ~(PCI_command_io | PCI_command_int_disable); 89 pcicmd |= PCI_command_master | PCI_command_memory; 90 TRACE("pcicmd new 0x%04x\n", pcicmd); 91 fPCI->write_pci_config(fPCIDevice, PCI_command, 2, pcicmd); 92 93 if (fPCIVendorID == PCI_VENDOR_JMICRON) { 94 uint32 ctrl = fPCI->read_pci_config(fPCIDevice, PCI_JMICRON_CONTROLLER_CONTROL_1, 4); 95 TRACE("Jmicron controller control 1 old 0x%08lx\n", ctrl); 96 ctrl &= ~((1 << 9) | (1 << 12) | (1 << 14)); // disable SFF 8038i emulation 97 ctrl |= (1 << 8) | (1 << 13) | (1 << 15); // enable AHCI controller 98 TRACE("Jmicron controller control 1 new 0x%08lx\n", ctrl); 99 fPCI->write_pci_config(fPCIDevice, PCI_JMICRON_CONTROLLER_CONTROL_1, 4, ctrl); 100 } 101 102 fIRQ = pciInfo.u.h0.interrupt_line; 103 if (fIRQ == 0 || fIRQ == 0xff) { 104 TRACE("Error: PCI IRQ not assigned\n"); 105 return B_ERROR; 106 } 107 108 phys_addr_t addr = pciInfo.u.h0.base_registers[5]; 109 size_t size = pciInfo.u.h0.base_register_sizes[5]; 110 111 TRACE("registers at %#" B_PRIxPHYSADDR ", size %#" B_PRIxSIZE "\n", addr, 112 size); 113 if (addr == 0) { 114 TRACE("PCI base address register 5 not assigned\n"); 115 return B_ERROR; 116 } 117 118 fRegsArea = map_mem((void **)&fRegs, addr, size, 0, "AHCI HBA regs"); 119 if (fRegsArea < B_OK) { 120 TRACE("mapping registers failed\n"); 121 return B_ERROR; 122 } 123 124 if (ResetController() < B_OK) { 125 TRACE("controller reset failed\n"); 126 goto err; 127 } 128 129 fCommandSlotCount = 1 + ((fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); 130 fPortCountMax = 1 + ((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); 131 132 fPortImplementedMask = fRegs->pi; 133 if (fPortImplementedMask == 0) { 134 fPortImplementedMask = 0xffffffff >> (32 - fPortCountMax); 135 TRACE("ports-implemented mask is zero, using 0x%lx instead.\n", fPortImplementedMask); 136 } 137 138 fPortCountAvail = count_bits_set(fPortImplementedMask); 139 140 TRACE("cap: Interface Speed Support: generation %lu\n", (fRegs->cap >> CAP_ISS_SHIFT) & CAP_ISS_MASK); 141 TRACE("cap: Number of Command Slots: %d (raw %#lx)\n", fCommandSlotCount, (fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); 142 TRACE("cap: Number of Ports: %d (raw %#lx)\n", fPortCountMax, (fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); 143 TRACE("cap: Supports Port Multiplier: %s\n", (fRegs->cap & CAP_SPM) ? "yes" : "no"); 144 TRACE("cap: Supports External SATA: %s\n", (fRegs->cap & CAP_SXS) ? "yes" : "no"); 145 TRACE("cap: Enclosure Management Supported: %s\n", (fRegs->cap & CAP_EMS) ? "yes" : "no"); 146 147 TRACE("cap: Supports Command List Override: %s\n", (fRegs->cap & CAP_SCLO) ? "yes" : "no"); 148 TRACE("cap: Supports Staggered Spin-up: %s\n", (fRegs->cap & CAP_SSS) ? "yes" : "no"); 149 TRACE("cap: Supports Mechanical Presence Switch: %s\n", (fRegs->cap & CAP_SMPS) ? "yes" : "no"); 150 151 TRACE("cap: Supports 64-bit Addressing: %s\n", (fRegs->cap & CAP_S64A) ? "yes" : "no"); 152 TRACE("cap: Supports Native Command Queuing: %s\n", (fRegs->cap & CAP_SNCQ) ? "yes" : "no"); 153 TRACE("cap: Supports SNotification Register: %s\n", (fRegs->cap & CAP_SSNTF) ? "yes" : "no"); 154 TRACE("cap: Supports Command List Override: %s\n", (fRegs->cap & CAP_SCLO) ? "yes" : "no"); 155 156 157 TRACE("cap: Supports AHCI mode only: %s\n", (fRegs->cap & CAP_SAM) ? "yes" : "no"); 158 TRACE("ghc: AHCI Enable: %s\n", (fRegs->ghc & GHC_AE) ? "yes" : "no"); 159 TRACE("Ports Implemented Mask: %#08lx\n", fPortImplementedMask); 160 TRACE("Number of Available Ports: %d\n", fPortCountAvail); 161 TRACE("AHCI Version %lu.%lu\n", fRegs->vs >> 16, fRegs->vs & 0xff); 162 TRACE("Interrupt %u\n", fIRQ); 163 164 // setup interrupt handler 165 if (install_io_interrupt_handler(fIRQ, Interrupt, this, 0) < B_OK) { 166 TRACE("can't install interrupt handler\n"); 167 goto err; 168 } 169 170 for (int i = 0; i <= fPortCountMax; i++) { 171 if (fPortImplementedMask & (1 << i)) { 172 fPort[i] = new (std::nothrow)AHCIPort(this, i); 173 if (!fPort[i]) { 174 TRACE("out of memory creating port %d", i); 175 break; 176 } 177 status_t status = fPort[i]->Init1(); 178 if (status < B_OK) { 179 TRACE("init-1 port %d failed", i); 180 delete fPort[i]; 181 fPort[i] = NULL; 182 } 183 } 184 } 185 186 // enable interrupts 187 fRegs->ghc |= GHC_IE; 188 FlushPostedWrites(); 189 190 for (int i = 0; i <= fPortCountMax; i++) { 191 if (fPort[i]) { 192 status_t status = fPort[i]->Init2(); 193 if (status < B_OK) { 194 TRACE("init-2 port %d failed", i); 195 fPort[i]->Uninit(); 196 delete fPort[i]; 197 fPort[i] = NULL; 198 } 199 } 200 } 201 202 203 return B_OK; 204 205 err: 206 delete_area(fRegsArea); 207 return B_ERROR; 208 } 209 210 211 void 212 AHCIController::Uninit() 213 { 214 TRACE("AHCIController::Uninit\n"); 215 216 for (int i = 0; i <= fPortCountMax; i++) { 217 if (fPort[i]) { 218 fPort[i]->Uninit(); 219 delete fPort[i]; 220 } 221 } 222 223 // disable interrupts 224 fRegs->ghc &= ~GHC_IE; 225 FlushPostedWrites(); 226 227 // clear pending interrupts 228 fRegs->is = 0xffffffff; 229 FlushPostedWrites(); 230 231 // well... 232 remove_io_interrupt_handler(fIRQ, Interrupt, this); 233 234 delete_area(fRegsArea); 235 236 // --- Instance check workaround begin 237 delete_port(fInstanceCheck); 238 // --- Instance check workaround end 239 } 240 241 242 status_t 243 AHCIController::ResetController() 244 { 245 uint32 saveCaps = fRegs->cap & (CAP_SMPS | CAP_SSS | CAP_SPM | CAP_EMS | CAP_SXS); 246 uint32 savePI = fRegs->pi; 247 248 fRegs->ghc |= GHC_HR; 249 FlushPostedWrites(); 250 if (wait_until_clear(&fRegs->ghc, GHC_HR, 1000000) < B_OK) 251 return B_TIMED_OUT; 252 253 fRegs->ghc |= GHC_AE; 254 FlushPostedWrites(); 255 fRegs->cap |= saveCaps; 256 fRegs->pi = savePI; 257 FlushPostedWrites(); 258 259 if (fPCIVendorID == PCI_VENDOR_INTEL) { 260 // Intel PCS—Port Control and Status 261 // SATA port enable bits must be set 262 int portCount = 1 + ((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); 263 if (portCount > 8) 264 panic("Intel AHCI: too many SATA ports! Please report at http://dev.haiku-os.org"); 265 uint16 pcs = fPCI->read_pci_config(fPCIDevice, 0x92, 2); 266 pcs |= (0xff >> (8 - portCount)); 267 fPCI->write_pci_config(fPCIDevice, 0x92, 2, pcs); 268 } 269 return B_OK; 270 } 271 272 273 int32 274 AHCIController::Interrupt(void *data) 275 { 276 AHCIController *self = (AHCIController *)data; 277 uint32 interruptPending = self->fRegs->is & self->fPortImplementedMask; 278 279 if (interruptPending == 0) 280 return B_UNHANDLED_INTERRUPT; 281 282 for (int i = 0; i < self->fPortCountMax; i++) { 283 if (interruptPending & (1 << i)) { 284 if (self->fPort[i]) { 285 self->fPort[i]->Interrupt(); 286 } else { 287 FLOW("interrupt on non-existent port %d\n", i); 288 } 289 } 290 } 291 292 // clear pending interrupts 293 self->fRegs->is = interruptPending; 294 295 return B_INVOKE_SCHEDULER; 296 } 297 298 299 void 300 AHCIController::ExecuteRequest(scsi_ccb *request) 301 { 302 if (request->target_lun || !fPort[request->target_id]) { 303 request->subsys_status = SCSI_DEV_NOT_THERE; 304 gSCSI->finished(request, 1); 305 return; 306 } 307 308 fPort[request->target_id]->ScsiExecuteRequest(request); 309 } 310 311 312 uchar 313 AHCIController::AbortRequest(scsi_ccb *request) 314 { 315 if (request->target_lun || !fPort[request->target_id]) 316 return SCSI_DEV_NOT_THERE; 317 318 return fPort[request->target_id]->ScsiAbortRequest(request); 319 } 320 321 322 uchar 323 AHCIController::TerminateRequest(scsi_ccb *request) 324 { 325 if (request->target_lun || !fPort[request->target_id]) 326 return SCSI_DEV_NOT_THERE; 327 328 return fPort[request->target_id]->ScsiTerminateRequest(request); 329 } 330 331 332 uchar 333 AHCIController::ResetDevice(uchar targetID, uchar targetLUN) 334 { 335 if (targetLUN || !fPort[targetID]) 336 return SCSI_DEV_NOT_THERE; 337 338 return fPort[targetID]->ScsiResetDevice(); 339 } 340 341 342 void 343 AHCIController::GetRestrictions(uchar targetID, bool *isATAPI, 344 bool *noAutoSense, uint32 *maxBlocks) 345 { 346 if (!fPort[targetID]) 347 return; 348 349 fPort[targetID]->ScsiGetRestrictions(isATAPI, noAutoSense, maxBlocks); 350 } 351