xref: /haiku/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp (revision 6f80a9801fedbe7355c4360bd204ba746ec3ec2d)
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