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