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 <algorithm> 10 #include <KernelExport.h> 11 #include <stdio.h> 12 #include <string.h> 13 #include <new> 14 15 #define TRACE(a...) dprintf("ahci: " a) 16 #define FLOW(a...) dprintf("ahci: " a) 17 18 19 AHCIController::AHCIController(device_node *node, 20 pci_device_module_info *pciModule, pci_device *device) 21 : 22 fNode(node), 23 fPCI(pciModule), 24 fPCIDevice(device), 25 fPCIVendorID(0xffff), 26 fPCIDeviceID(0xffff), 27 fFlags(0), 28 fCommandSlotCount(0), 29 fPortCount(0), 30 fPortImplementedMask(0), 31 fIRQ(0), 32 fUseMSI(false), 33 fInstanceCheck(-1) 34 { 35 memset(fPort, 0, sizeof(fPort)); 36 37 ASSERT(sizeof(ahci_port) == 128); 38 ASSERT(sizeof(ahci_hba) == 4352); 39 ASSERT(sizeof(fis) == 256); 40 ASSERT(sizeof(command_list_entry) == 32); 41 ASSERT(sizeof(command_table) == 128); 42 ASSERT(sizeof(prd) == 16); 43 } 44 45 46 AHCIController::~AHCIController() 47 { 48 } 49 50 51 status_t 52 AHCIController::Init() 53 { 54 pci_info pciInfo; 55 fPCI->get_pci_info(fPCIDevice, &pciInfo); 56 57 fPCIVendorID = pciInfo.vendor_id; 58 fPCIDeviceID = pciInfo.device_id; 59 60 TRACE("AHCIController::Init %u:%u:%u vendor %04x, device %04x\n", 61 pciInfo.bus, pciInfo.device, pciInfo.function, fPCIVendorID, fPCIDeviceID); 62 63 // --- Instance check workaround begin 64 char sName[32]; 65 snprintf(sName, sizeof(sName), "ahci-inst-%u-%u-%u", pciInfo.bus, pciInfo.device, pciInfo.function); 66 if (find_port(sName) >= 0) { 67 dprintf("AHCIController::Init ERROR: an instance for object %u:%u:%u already exists\n", 68 pciInfo.bus, pciInfo.device, pciInfo.function); 69 return B_ERROR; 70 } 71 fInstanceCheck = create_port(1, sName); 72 // --- Instance check workaround end 73 74 get_device_info(fPCIVendorID, fPCIDeviceID, NULL, &fFlags); 75 76 uchar capabilityOffset; 77 status_t res = fPCI->find_pci_capability(fPCIDevice, PCI_cap_id_sata, &capabilityOffset); 78 if (res == B_OK) { 79 uint32 satacr0; 80 uint32 satacr1; 81 TRACE("PCI SATA capability found at offset 0x%x\n", capabilityOffset); 82 satacr0 = fPCI->read_pci_config(fPCIDevice, capabilityOffset, 4); 83 satacr1 = fPCI->read_pci_config(fPCIDevice, capabilityOffset + 4, 4); 84 TRACE("satacr0 = 0x%08" B_PRIx32 ", satacr1 = 0x%08" B_PRIx32 "\n", 85 satacr0, satacr1); 86 } 87 88 uint16 pcicmd = fPCI->read_pci_config(fPCIDevice, PCI_command, 2); 89 TRACE("pcicmd old 0x%04x\n", pcicmd); 90 pcicmd &= ~(PCI_command_io | PCI_command_int_disable); 91 pcicmd |= PCI_command_master | PCI_command_memory; 92 TRACE("pcicmd new 0x%04x\n", pcicmd); 93 fPCI->write_pci_config(fPCIDevice, PCI_command, 2, pcicmd); 94 95 if (fPCIVendorID == PCI_VENDOR_JMICRON) { 96 uint32 ctrl = fPCI->read_pci_config(fPCIDevice, PCI_JMICRON_CONTROLLER_CONTROL_1, 4); 97 TRACE("Jmicron controller control 1 old 0x%08" B_PRIx32 "\n", ctrl); 98 ctrl &= ~((1 << 9) | (1 << 12) | (1 << 14)); // disable SFF 8038i emulation 99 ctrl |= (1 << 8) | (1 << 13) | (1 << 15); // enable AHCI controller 100 TRACE("Jmicron controller control 1 new 0x%08" B_PRIx32 "\n", ctrl); 101 fPCI->write_pci_config(fPCIDevice, PCI_JMICRON_CONTROLLER_CONTROL_1, 4, ctrl); 102 } 103 104 fIRQ = pciInfo.u.h0.interrupt_line; 105 if (gPCIx86Module != NULL && gPCIx86Module->get_msi_count( 106 pciInfo.bus, pciInfo.device, pciInfo.function) >= 1) { 107 uint8 vector; 108 if (gPCIx86Module->configure_msi(pciInfo.bus, pciInfo.device, 109 pciInfo.function, 1, &vector) == B_OK 110 && gPCIx86Module->enable_msi(pciInfo.bus, pciInfo.device, 111 pciInfo.function) == B_OK) { 112 TRACE("using MSI vector %u\n", vector); 113 fIRQ = vector; 114 fUseMSI = true; 115 } else { 116 TRACE("couldn't use MSI\n"); 117 } 118 } 119 if (fIRQ == 0 || fIRQ == 0xff) { 120 TRACE("Error: PCI IRQ not assigned\n"); 121 return B_ERROR; 122 } 123 124 phys_addr_t addr = pciInfo.u.h0.base_registers[5]; 125 size_t size = pciInfo.u.h0.base_register_sizes[5]; 126 127 TRACE("registers at %#" B_PRIxPHYSADDR ", size %#" B_PRIxSIZE "\n", addr, 128 size); 129 if (addr == 0) { 130 TRACE("PCI base address register 5 not assigned\n"); 131 return B_ERROR; 132 } 133 134 fRegsArea = map_mem((void **)&fRegs, addr, size, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 135 "AHCI HBA regs"); 136 if (fRegsArea < B_OK) { 137 TRACE("mapping registers failed\n"); 138 return B_ERROR; 139 } 140 141 // make sure interrupts are disabled 142 fRegs->ghc &= ~GHC_IE; 143 FlushPostedWrites(); 144 145 if (ResetController() < B_OK) { 146 TRACE("controller reset failed\n"); 147 goto err; 148 } 149 150 fCommandSlotCount = 1 + ((fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); 151 fPortCount = 1 + ((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); 152 153 fPortImplementedMask = fRegs->pi; 154 // reported mask of implemented ports is sometimes empty 155 if (fPortImplementedMask == 0) { 156 fPortImplementedMask = 0xffffffff >> (32 - fPortCount); 157 TRACE("ports-implemented mask is zero, using 0x%" B_PRIx32 " instead.\n", 158 fPortImplementedMask); 159 } 160 161 // reported number of ports is sometimes too small 162 int highestPort; 163 highestPort = fls(fPortImplementedMask); // 1-based, 1 to 32 164 if (fPortCount < highestPort) { 165 TRACE("reported number of ports is wrong, using %d instead.\n", highestPort); 166 fPortCount = highestPort; 167 } 168 169 TRACE("cap: Interface Speed Support: generation %" B_PRIu32 "\n", 170 (fRegs->cap >> CAP_ISS_SHIFT) & CAP_ISS_MASK); 171 TRACE("cap: Number of Command Slots: %d (raw %#" B_PRIx32 ")\n", 172 fCommandSlotCount, (fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); 173 TRACE("cap: Number of Ports: %d (raw %#" B_PRIx32 ")\n", fPortCount, 174 (fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); 175 TRACE("cap: Supports Port Multiplier: %s\n", 176 (fRegs->cap & CAP_SPM) ? "yes" : "no"); 177 TRACE("cap: Supports External SATA: %s\n", 178 (fRegs->cap & CAP_SXS) ? "yes" : "no"); 179 TRACE("cap: Enclosure Management Supported: %s\n", 180 (fRegs->cap & CAP_EMS) ? "yes" : "no"); 181 182 TRACE("cap: FIS-based Switching Control: %s\n", 183 (fRegs->cap & CAP_FBSS) ? "yes" : "no"); 184 185 TRACE("cap: Supports Command List Override: %s\n", 186 (fRegs->cap & CAP_SCLO) ? "yes" : "no"); 187 TRACE("cap: Supports Staggered Spin-up: %s\n", 188 (fRegs->cap & CAP_SSS) ? "yes" : "no"); 189 TRACE("cap: Supports Mechanical Presence Switch: %s\n", 190 (fRegs->cap & CAP_SMPS) ? "yes" : "no"); 191 192 TRACE("cap: Supports 64-bit Addressing: %s\n", 193 (fRegs->cap & CAP_S64A) ? "yes" : "no"); 194 TRACE("cap: Supports Native Command Queuing: %s\n", 195 (fRegs->cap & CAP_SNCQ) ? "yes" : "no"); 196 TRACE("cap: Supports SNotification Register: %s\n", 197 (fRegs->cap & CAP_SSNTF) ? "yes" : "no"); 198 TRACE("cap: Supports Command List Override: %s\n", 199 (fRegs->cap & CAP_SCLO) ? "yes" : "no"); 200 201 TRACE("cap: Supports AHCI mode only: %s\n", (fRegs->cap & CAP_SAM) ? "yes" : "no"); 202 203 if (fRegs->vs >= 0x00010200) { 204 TRACE("cap2: DevSleep Entrance from Slumber Only: %s\n", 205 (fRegs->cap2 & CAP2_DESO) ? "yes" : "no"); 206 TRACE("cap2: Supports Aggressive Device Sleep Management: %s\n", 207 (fRegs->cap2 & CAP2_SADM) ? "yes" : "no"); 208 TRACE("cap2: Supports Device Sleep: %s\n", 209 (fRegs->cap2 & CAP2_SDS) ? "yes" : "no"); 210 TRACE("cap2: Automatic Partial to Slumber Transitions: %s\n", 211 (fRegs->cap2 & CAP2_APST) ? "yes" : "no"); 212 TRACE("cap2: NVMHCI Present: %s\n", 213 (fRegs->cap2 & CAP2_NVMP) ? "yes" : "no"); 214 TRACE("cap2: BIOS/OS Handoff: %s\n", 215 (fRegs->cap2 & CAP2_BOH) ? "yes" : "no"); 216 } 217 TRACE("ghc: AHCI Enable: %s\n", (fRegs->ghc & GHC_AE) ? "yes" : "no"); 218 TRACE("Ports Implemented Mask: %#08" B_PRIx32 " Number of Available Ports:" 219 " %d\n", fPortImplementedMask, count_bits_set(fPortImplementedMask)); 220 TRACE("AHCI Version %02" B_PRIx32 "%02" B_PRIx32 ".%02" B_PRIx32 ".%02" 221 B_PRIx32 " Interrupt %u\n", fRegs->vs >> 24, (fRegs->vs >> 16) & 0xff, 222 (fRegs->vs >> 8) & 0xff, fRegs->vs & 0xff, fIRQ); 223 224 // setup interrupt handler 225 if (install_io_interrupt_handler(fIRQ, Interrupt, this, 0) < B_OK) { 226 TRACE("can't install interrupt handler\n"); 227 goto err; 228 } 229 230 for (int i = 0; i < fPortCount; i++) { 231 if (fPortImplementedMask & (1 << i)) { 232 fPort[i] = new (std::nothrow)AHCIPort(this, i); 233 if (!fPort[i]) { 234 TRACE("out of memory creating port %d\n", i); 235 break; 236 } 237 status_t status = fPort[i]->Init1(); 238 if (status < B_OK) { 239 TRACE("init-1 port %d failed\n", i); 240 delete fPort[i]; 241 fPort[i] = NULL; 242 } 243 } 244 } 245 246 // clear any pending interrupts 247 uint32 interruptsPending; 248 interruptsPending = fRegs->is; 249 fRegs->is = interruptsPending; 250 FlushPostedWrites(); 251 252 // enable interrupts 253 fRegs->ghc |= GHC_IE; 254 FlushPostedWrites(); 255 256 for (int i = 0; i < fPortCount; i++) { 257 if (fPort[i]) { 258 status_t status = fPort[i]->Init2(); 259 if (status < B_OK) { 260 TRACE("init-2 port %d failed\n", i); 261 fPort[i]->Uninit(); 262 delete fPort[i]; 263 fPort[i] = NULL; 264 } 265 } 266 } 267 268 269 return B_OK; 270 271 err: 272 delete_area(fRegsArea); 273 return B_ERROR; 274 } 275 276 277 void 278 AHCIController::Uninit() 279 { 280 TRACE("AHCIController::Uninit\n"); 281 282 for (int i = 0; i < fPortCount; i++) { 283 if (fPort[i]) { 284 fPort[i]->Uninit(); 285 delete fPort[i]; 286 } 287 } 288 289 // disable interrupts 290 fRegs->ghc &= ~GHC_IE; 291 FlushPostedWrites(); 292 293 // clear pending interrupts 294 fRegs->is = 0xffffffff; 295 FlushPostedWrites(); 296 297 // well... 298 remove_io_interrupt_handler(fIRQ, Interrupt, this); 299 300 if (fUseMSI && gPCIx86Module != NULL) { 301 pci_info pciInfo; 302 fPCI->get_pci_info(fPCIDevice, &pciInfo); 303 gPCIx86Module->disable_msi(pciInfo.bus, 304 pciInfo.device, pciInfo.function); 305 gPCIx86Module->unconfigure_msi(pciInfo.bus, 306 pciInfo.device, pciInfo.function); 307 } 308 309 delete_area(fRegsArea); 310 311 // --- Instance check workaround begin 312 delete_port(fInstanceCheck); 313 // --- Instance check workaround end 314 } 315 316 317 status_t 318 AHCIController::ResetController() 319 { 320 uint32 saveCaps = fRegs->cap & (CAP_SMPS | CAP_SSS | CAP_SPM | CAP_EMS | CAP_SXS); 321 uint32 savePI = fRegs->pi; 322 323 // AHCI 1.3: Software may perform an HBA reset prior to initializing the controller 324 // by setting GHC.AE to ‘1’ and then setting GHC.HR to ‘1’ if desired. 325 fRegs->ghc |= GHC_AE; 326 FlushPostedWrites(); 327 fRegs->ghc |= GHC_HR; 328 FlushPostedWrites(); 329 if (wait_until_clear(&fRegs->ghc, GHC_HR, 1000000) < B_OK) 330 return B_TIMED_OUT; 331 332 fRegs->ghc |= GHC_AE; 333 FlushPostedWrites(); 334 fRegs->cap |= saveCaps; 335 fRegs->pi = savePI; 336 FlushPostedWrites(); 337 338 if (fPCIVendorID == PCI_VENDOR_INTEL) { 339 // Intel PCS—Port Control and Status 340 // SATA port enable bits must be set 341 int portCount = std::max(fls(fRegs->pi), 1 + (int)((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK)); 342 if (portCount > 8) { 343 // TODO: fix this when specification available 344 TRACE("don't know how to enable SATA ports 9 to %d\n", portCount); 345 portCount = 8; 346 } 347 uint16 pcs = fPCI->read_pci_config(fPCIDevice, 0x92, 2); 348 pcs |= (0xff >> (8 - portCount)); 349 fPCI->write_pci_config(fPCIDevice, 0x92, 2, pcs); 350 } 351 return B_OK; 352 } 353 354 355 int32 356 AHCIController::Interrupt(void *data) 357 { 358 AHCIController *self = (AHCIController *)data; 359 uint32 interruptPending = self->fRegs->is & self->fPortImplementedMask; 360 361 if (interruptPending == 0) 362 return B_UNHANDLED_INTERRUPT; 363 364 for (int i = 0; i < self->fPortCount; i++) { 365 if (interruptPending & (1 << i)) { 366 if (self->fPort[i]) { 367 self->fPort[i]->Interrupt(); 368 } else { 369 FLOW("interrupt on non-existent port %d\n", i); 370 } 371 } 372 } 373 374 // clear pending interrupts 375 self->fRegs->is = interruptPending; 376 377 return B_INVOKE_SCHEDULER; 378 } 379 380 381 void 382 AHCIController::ExecuteRequest(scsi_ccb *request) 383 { 384 if (request->target_lun || !fPort[request->target_id]) { 385 request->subsys_status = SCSI_DEV_NOT_THERE; 386 gSCSI->finished(request, 1); 387 return; 388 } 389 390 fPort[request->target_id]->ScsiExecuteRequest(request); 391 } 392 393 394 uchar 395 AHCIController::AbortRequest(scsi_ccb *request) 396 { 397 if (request->target_lun || !fPort[request->target_id]) 398 return SCSI_DEV_NOT_THERE; 399 400 return fPort[request->target_id]->ScsiAbortRequest(request); 401 } 402 403 404 uchar 405 AHCIController::TerminateRequest(scsi_ccb *request) 406 { 407 if (request->target_lun || !fPort[request->target_id]) 408 return SCSI_DEV_NOT_THERE; 409 410 return fPort[request->target_id]->ScsiTerminateRequest(request); 411 } 412 413 414 uchar 415 AHCIController::ResetDevice(uchar targetID, uchar targetLUN) 416 { 417 if (targetLUN || !fPort[targetID]) 418 return SCSI_DEV_NOT_THERE; 419 420 return fPort[targetID]->ScsiResetDevice(); 421 } 422 423 424 void 425 AHCIController::GetRestrictions(uchar targetID, bool *isATAPI, 426 bool *noAutoSense, uint32 *maxBlocks) 427 { 428 if (!fPort[targetID]) 429 return; 430 431 fPort[targetID]->ScsiGetRestrictions(isATAPI, noAutoSense, maxBlocks); 432 } 433