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 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%08" B_PRIx32 ", satacr1 = 0x%08" B_PRIx32 "\n", 84 satacr0, satacr1); 85 } 86 87 uint16 pcicmd = fPCI->read_pci_config(fPCIDevice, PCI_command, 2); 88 TRACE("pcicmd old 0x%04x\n", pcicmd); 89 pcicmd &= ~(PCI_command_io | PCI_command_int_disable); 90 pcicmd |= PCI_command_master | PCI_command_memory; 91 TRACE("pcicmd new 0x%04x\n", pcicmd); 92 fPCI->write_pci_config(fPCIDevice, PCI_command, 2, pcicmd); 93 94 if (fPCIVendorID == PCI_VENDOR_JMICRON) { 95 uint32 ctrl = fPCI->read_pci_config(fPCIDevice, PCI_JMICRON_CONTROLLER_CONTROL_1, 4); 96 TRACE("Jmicron controller control 1 old 0x%08" B_PRIx32 "\n", ctrl); 97 ctrl &= ~((1 << 9) | (1 << 12) | (1 << 14)); // disable SFF 8038i emulation 98 ctrl |= (1 << 8) | (1 << 13) | (1 << 15); // enable AHCI controller 99 TRACE("Jmicron controller control 1 new 0x%08" B_PRIx32 "\n", ctrl); 100 fPCI->write_pci_config(fPCIDevice, PCI_JMICRON_CONTROLLER_CONTROL_1, 4, ctrl); 101 } 102 103 fIRQ = pciInfo.u.h0.interrupt_line; 104 if (fIRQ == 0 || fIRQ == 0xff) { 105 TRACE("Error: PCI IRQ not assigned\n"); 106 return B_ERROR; 107 } 108 109 phys_addr_t addr = pciInfo.u.h0.base_registers[5]; 110 size_t size = pciInfo.u.h0.base_register_sizes[5]; 111 112 TRACE("registers at %#" B_PRIxPHYSADDR ", size %#" B_PRIxSIZE "\n", addr, 113 size); 114 if (addr == 0) { 115 TRACE("PCI base address register 5 not assigned\n"); 116 return B_ERROR; 117 } 118 119 fRegsArea = map_mem((void **)&fRegs, addr, size, 0, "AHCI HBA regs"); 120 if (fRegsArea < B_OK) { 121 TRACE("mapping registers failed\n"); 122 return B_ERROR; 123 } 124 125 // make sure interrupts are disabled 126 fRegs->ghc &= ~GHC_IE; 127 FlushPostedWrites(); 128 129 if (ResetController() < B_OK) { 130 TRACE("controller reset failed\n"); 131 goto err; 132 } 133 134 fCommandSlotCount = 1 + ((fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); 135 fPortCount = 1 + ((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); 136 137 fPortImplementedMask = fRegs->pi; 138 // reported mask of implemented ports is sometimes empty 139 if (fPortImplementedMask == 0) { 140 fPortImplementedMask = 0xffffffff >> (32 - fPortCount); 141 TRACE("ports-implemented mask is zero, using 0x%" B_PRIx32 " instead.\n", 142 fPortImplementedMask); 143 } 144 145 // reported number of ports is sometimes too small 146 int highestPort; 147 highestPort = fls(fPortImplementedMask); // 1-based, 1 to 32 148 if (fPortCount < highestPort) { 149 TRACE("reported number of ports is wrong, using %d instead.\n", highestPort); 150 fPortCount = highestPort; 151 } 152 153 TRACE("cap: Interface Speed Support: generation %" B_PRIu32 "\n", (fRegs->cap >> CAP_ISS_SHIFT) & CAP_ISS_MASK); 154 TRACE("cap: Number of Command Slots: %d (raw %#" B_PRIx32 ")\n", fCommandSlotCount, (fRegs->cap >> CAP_NCS_SHIFT) & CAP_NCS_MASK); 155 TRACE("cap: Number of Ports: %d (raw %#" B_PRIx32 ")\n", fPortCount, (fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK); 156 TRACE("cap: Supports Port Multiplier: %s\n", (fRegs->cap & CAP_SPM) ? "yes" : "no"); 157 TRACE("cap: Supports External SATA: %s\n", (fRegs->cap & CAP_SXS) ? "yes" : "no"); 158 TRACE("cap: Enclosure Management Supported: %s\n", (fRegs->cap & CAP_EMS) ? "yes" : "no"); 159 160 TRACE("cap: Supports Command List Override: %s\n", (fRegs->cap & CAP_SCLO) ? "yes" : "no"); 161 TRACE("cap: Supports Staggered Spin-up: %s\n", (fRegs->cap & CAP_SSS) ? "yes" : "no"); 162 TRACE("cap: Supports Mechanical Presence Switch: %s\n", (fRegs->cap & CAP_SMPS) ? "yes" : "no"); 163 164 TRACE("cap: Supports 64-bit Addressing: %s\n", (fRegs->cap & CAP_S64A) ? "yes" : "no"); 165 TRACE("cap: Supports Native Command Queuing: %s\n", (fRegs->cap & CAP_SNCQ) ? "yes" : "no"); 166 TRACE("cap: Supports SNotification Register: %s\n", (fRegs->cap & CAP_SSNTF) ? "yes" : "no"); 167 TRACE("cap: Supports Command List Override: %s\n", (fRegs->cap & CAP_SCLO) ? "yes" : "no"); 168 169 170 TRACE("cap: Supports AHCI mode only: %s\n", (fRegs->cap & CAP_SAM) ? "yes" : "no"); 171 TRACE("ghc: AHCI Enable: %s\n", (fRegs->ghc & GHC_AE) ? "yes" : "no"); 172 TRACE("Ports Implemented Mask: %#08" B_PRIx32 "\n", fPortImplementedMask); 173 TRACE("Number of Available Ports: %d\n", count_bits_set(fPortImplementedMask)); 174 TRACE("AHCI Version %" B_PRIu32 ".%" B_PRIu32 "\n", fRegs->vs >> 16, fRegs->vs & 0xff); 175 TRACE("Interrupt %u\n", fIRQ); 176 177 // setup interrupt handler 178 if (install_io_interrupt_handler(fIRQ, Interrupt, this, 0) < B_OK) { 179 TRACE("can't install interrupt handler\n"); 180 goto err; 181 } 182 183 for (int i = 0; i < fPortCount; i++) { 184 if (fPortImplementedMask & (1 << i)) { 185 fPort[i] = new (std::nothrow)AHCIPort(this, i); 186 if (!fPort[i]) { 187 TRACE("out of memory creating port %d\n", i); 188 break; 189 } 190 status_t status = fPort[i]->Init1(); 191 if (status < B_OK) { 192 TRACE("init-1 port %d failed\n", i); 193 delete fPort[i]; 194 fPort[i] = NULL; 195 } 196 } 197 } 198 199 // clear any pending interrupts 200 uint32 interruptsPending; 201 interruptsPending = fRegs->is; 202 fRegs->is = interruptsPending; 203 FlushPostedWrites(); 204 205 // enable interrupts 206 fRegs->ghc |= GHC_IE; 207 FlushPostedWrites(); 208 209 for (int i = 0; i < fPortCount; i++) { 210 if (fPort[i]) { 211 status_t status = fPort[i]->Init2(); 212 if (status < B_OK) { 213 TRACE("init-2 port %d failed\n", i); 214 fPort[i]->Uninit(); 215 delete fPort[i]; 216 fPort[i] = NULL; 217 } 218 } 219 } 220 221 222 return B_OK; 223 224 err: 225 delete_area(fRegsArea); 226 return B_ERROR; 227 } 228 229 230 void 231 AHCIController::Uninit() 232 { 233 TRACE("AHCIController::Uninit\n"); 234 235 for (int i = 0; i < fPortCount; i++) { 236 if (fPort[i]) { 237 fPort[i]->Uninit(); 238 delete fPort[i]; 239 } 240 } 241 242 // disable interrupts 243 fRegs->ghc &= ~GHC_IE; 244 FlushPostedWrites(); 245 246 // clear pending interrupts 247 fRegs->is = 0xffffffff; 248 FlushPostedWrites(); 249 250 // well... 251 remove_io_interrupt_handler(fIRQ, Interrupt, this); 252 253 delete_area(fRegsArea); 254 255 // --- Instance check workaround begin 256 delete_port(fInstanceCheck); 257 // --- Instance check workaround end 258 } 259 260 261 status_t 262 AHCIController::ResetController() 263 { 264 uint32 saveCaps = fRegs->cap & (CAP_SMPS | CAP_SSS | CAP_SPM | CAP_EMS | CAP_SXS); 265 uint32 savePI = fRegs->pi; 266 267 // AHCI 1.3: Software may perform an HBA reset prior to initializing the controller 268 // by setting GHC.AE to ‘1’ and then setting GHC.HR to ‘1’ if desired. 269 fRegs->ghc |= GHC_AE; 270 FlushPostedWrites(); 271 fRegs->ghc |= GHC_HR; 272 FlushPostedWrites(); 273 if (wait_until_clear(&fRegs->ghc, GHC_HR, 1000000) < B_OK) 274 return B_TIMED_OUT; 275 276 fRegs->ghc |= GHC_AE; 277 FlushPostedWrites(); 278 fRegs->cap |= saveCaps; 279 fRegs->pi = savePI; 280 FlushPostedWrites(); 281 282 if (fPCIVendorID == PCI_VENDOR_INTEL) { 283 // Intel PCS—Port Control and Status 284 // SATA port enable bits must be set 285 int portCount = std::max(fls(fRegs->pi), 1 + (int)((fRegs->cap >> CAP_NP_SHIFT) & CAP_NP_MASK)); 286 if (portCount > 8) { 287 // TODO: fix this when specification available 288 TRACE("don't know how to enable SATA ports 9 to %d\n", portCount); 289 portCount = 8; 290 } 291 uint16 pcs = fPCI->read_pci_config(fPCIDevice, 0x92, 2); 292 pcs |= (0xff >> (8 - portCount)); 293 fPCI->write_pci_config(fPCIDevice, 0x92, 2, pcs); 294 } 295 return B_OK; 296 } 297 298 299 int32 300 AHCIController::Interrupt(void *data) 301 { 302 AHCIController *self = (AHCIController *)data; 303 uint32 interruptPending = self->fRegs->is & self->fPortImplementedMask; 304 305 if (interruptPending == 0) 306 return B_UNHANDLED_INTERRUPT; 307 308 for (int i = 0; i < self->fPortCount; i++) { 309 if (interruptPending & (1 << i)) { 310 if (self->fPort[i]) { 311 self->fPort[i]->Interrupt(); 312 } else { 313 FLOW("interrupt on non-existent port %d\n", i); 314 } 315 } 316 } 317 318 // clear pending interrupts 319 self->fRegs->is = interruptPending; 320 321 return B_INVOKE_SCHEDULER; 322 } 323 324 325 void 326 AHCIController::ExecuteRequest(scsi_ccb *request) 327 { 328 if (request->target_lun || !fPort[request->target_id]) { 329 request->subsys_status = SCSI_DEV_NOT_THERE; 330 gSCSI->finished(request, 1); 331 return; 332 } 333 334 fPort[request->target_id]->ScsiExecuteRequest(request); 335 } 336 337 338 uchar 339 AHCIController::AbortRequest(scsi_ccb *request) 340 { 341 if (request->target_lun || !fPort[request->target_id]) 342 return SCSI_DEV_NOT_THERE; 343 344 return fPort[request->target_id]->ScsiAbortRequest(request); 345 } 346 347 348 uchar 349 AHCIController::TerminateRequest(scsi_ccb *request) 350 { 351 if (request->target_lun || !fPort[request->target_id]) 352 return SCSI_DEV_NOT_THERE; 353 354 return fPort[request->target_id]->ScsiTerminateRequest(request); 355 } 356 357 358 uchar 359 AHCIController::ResetDevice(uchar targetID, uchar targetLUN) 360 { 361 if (targetLUN || !fPort[targetID]) 362 return SCSI_DEV_NOT_THERE; 363 364 return fPort[targetID]->ScsiResetDevice(); 365 } 366 367 368 void 369 AHCIController::GetRestrictions(uchar targetID, bool *isATAPI, 370 bool *noAutoSense, uint32 *maxBlocks) 371 { 372 if (!fPort[targetID]) 373 return; 374 375 fPort[targetID]->ScsiGetRestrictions(isATAPI, noAutoSense, maxBlocks); 376 } 377