xref: /haiku/src/add-ons/kernel/busses/scsi/ahci/ahci.c (revision cda5b8808fd0262f0fac472f6cfa809f846a83cf)
1 /*
2  * Copyright 2007, Marcus Overhagen. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "ahci_defs.h"
7 
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include <block_io.h>
12 
13 
14 #define TRACE(a...) dprintf("\33[35mahci:\33[0m " a)
15 #define FLOW(a...)	dprintf("ahci: " a)
16 
17 #define AHCI_ID_GENERATOR "ahci/id"
18 #define AHCI_ID_ITEM "ahci/id"
19 
20 
21 const device_info kSupportedDevices[] = {
22 	{ 0x1002, 0x4380, "ATI SB600" },
23 	{ 0x1002, 0x4390, "ATI SB700/800" },
24 	{ 0x1002, 0x4391, "ATI IXP700" },
25 	{ 0x1002, 0x4392, "ATI SB700/800" },
26 	{ 0x1002, 0x4393, "ATI SB700/800" },
27 	{ 0x1002, 0x4394, "ATI SB700/800" },
28 	{ 0x1002, 0x4395, "ATI SB700/800" },
29 	{ 0x1039, 0x1184, "SiS 966" },
30 	{ 0x1039, 0x1185, "SiS 966" },
31 	{ 0x1039, 0x0186, "SiS 968" },
32 	{ 0x10b9, 0x5288, "Acer Labs M5288" },
33 	{ 0x10de, 0x044c, "NVIDIA MCP65" },
34 	{ 0x10de, 0x044d, "NVIDIA MCP65" },
35 	{ 0x10de, 0x044e, "NVIDIA MCP65" },
36 	{ 0x10de, 0x044f, "NVIDIA MCP65" },
37 	{ 0x10de, 0x045c, "NVIDIA MCP65" },
38 	{ 0x10de, 0x045d, "NVIDIA MCP65" },
39 	{ 0x10de, 0x045e, "NVIDIA MCP65" },
40 	{ 0x10de, 0x045f, "NVIDIA MCP65" },
41 	{ 0x10de, 0x0550, "NVIDIA MCP67" },
42 	{ 0x10de, 0x0551, "NVIDIA MCP67" },
43 	{ 0x10de, 0x0552, "NVIDIA MCP67" },
44 	{ 0x10de, 0x0553, "NVIDIA MCP67" },
45 	{ 0x10de, 0x0554, "NVIDIA MCP67" },
46 	{ 0x10de, 0x0555, "NVIDIA MCP67" },
47 	{ 0x10de, 0x0556, "NVIDIA MCP67" },
48 	{ 0x10de, 0x0557, "NVIDIA MCP67" },
49 	{ 0x10de, 0x0558, "NVIDIA MCP67" },
50 	{ 0x10de, 0x0559, "NVIDIA MCP67" },
51 	{ 0x10de, 0x055a, "NVIDIA MCP67" },
52 	{ 0x10de, 0x055b, "NVIDIA MCP67" },
53 	{ 0x10de, 0x07f0, "NVIDIA MCP73" },
54 	{ 0x10de, 0x07f1, "NVIDIA MCP73" },
55 	{ 0x10de, 0x07f2, "NVIDIA MCP73" },
56 	{ 0x10de, 0x07f3, "NVIDIA MCP73" },
57 	{ 0x10de, 0x07f4, "NVIDIA MCP73" },
58 	{ 0x10de, 0x07f5, "NVIDIA MCP73" },
59 	{ 0x10de, 0x07f6, "NVIDIA MCP73" },
60 	{ 0x10de, 0x07f7, "NVIDIA MCP73" },
61 	{ 0x10de, 0x07f8, "NVIDIA MCP73" },
62 	{ 0x10de, 0x07f9, "NVIDIA MCP73" },
63 	{ 0x10de, 0x07fa, "NVIDIA MCP73" },
64 	{ 0x10de, 0x07fb, "NVIDIA MCP73" },
65 	{ 0x10de, 0x0ad0, "NVIDIA MCP77" },
66 	{ 0x10de, 0x0ad1, "NVIDIA MCP77" },
67 	{ 0x10de, 0x0ad2, "NVIDIA MCP77" },
68 	{ 0x10de, 0x0ad3, "NVIDIA MCP77" },
69 	{ 0x10de, 0x0ad4, "NVIDIA MCP77" },
70 	{ 0x10de, 0x0ad5, "NVIDIA MCP77" },
71 	{ 0x10de, 0x0ad6, "NVIDIA MCP77" },
72 	{ 0x10de, 0x0ad7, "NVIDIA MCP77" },
73 	{ 0x10de, 0x0ad8, "NVIDIA MCP77" },
74 	{ 0x10de, 0x0ad9, "NVIDIA MCP77" },
75 	{ 0x10de, 0x0ada, "NVIDIA MCP77" },
76 	{ 0x10de, 0x0adb, "NVIDIA MCP77" },
77 	{ 0x1106, 0x3349, "VIA VT8251" },
78 	{ 0x1106, 0x6287, "VIA VT8251" },
79 	{ 0x11ab, 0x6145, "Marvell 6145" },
80 	{ 0x197b, 0x2360, "JMicron JMB360" },
81 	{ 0x197b, 0x2361, "JMicron JMB361" },
82 	{ 0x197b, 0x2362, "JMicron JMB362" },
83 	{ 0x197b, 0x2363, "JMicron JMB363" },
84 	{ 0x197b, 0x2366, "JMicron JMB366" },
85 	{ 0x8086, 0x2652, "Intel ICH6R" },
86 	{ 0x8086, 0x2653, "Intel ICH6-M" },
87 	{ 0x8086, 0x2681, "Intel 63xxESB" },
88 	{ 0x8086, 0x2682, "Intel ESB2" },
89 	{ 0x8086, 0x2683, "Intel ESB2" },
90 	{ 0x8086, 0x27c1, "Intel ICH7R (AHCI mode)" },
91 	{ 0x8086, 0x27c3, "Intel ICH7R (RAID mode)" },
92 	{ 0x8086, 0x27c5, "Intel ICH7-M (AHCI mode)" },
93 	{ 0x8086, 0x27c6, "Intel ICH7-M DH (RAID mode)" },
94 	{ 0x8086, 0x2821, "Intel ICH8 (AHCI mode)" },
95 	{ 0x8086, 0x2822, "Intel ICH8R / ICH9 (RAID mode)" },
96 	{ 0x8086, 0x2824, "Intel ICH8 (AHCI mode)" },
97 	{ 0x8086, 0x2829, "Intel ICH8M (AHCI mode)" },
98 	{ 0x8086, 0x282a, "Intel ICH8M (RAID mode)" },
99 	{ 0x8086, 0x2922, "Intel ICH9 (AHCI mode)" },
100 	{ 0x8086, 0x2923, "Intel ICH9 (AHCI mode)" },
101 	{ 0x8086, 0x2924, "Intel ICH9" },
102 	{ 0x8086, 0x2925, "Intel ICH9" },
103 	{ 0x8086, 0x2927, "Intel ICH9" },
104 	{ 0x8086, 0x2929, "Intel ICH9M" },
105 	{ 0x8086, 0x292a, "Intel ICH9M" },
106 	{ 0x8086, 0x292b, "Intel ICH9M" },
107 	{ 0x8086, 0x292c, "Intel ICH9M" },
108 	{ 0x8086, 0x292f, "Intel ICH9M" },
109 	{ 0x8086, 0x294d, "Intel ICH9" },
110 	{ 0x8086, 0x294e, "Intel ICH9M" },
111 	{}
112 };
113 
114 
115 status_t
116 get_device_info(uint16 vendorID, uint16 deviceID, const char **name,
117 	uint32 *flags)
118 {
119 	const device_info *info;
120 	for (info = kSupportedDevices; info->vendor; info++) {
121 		if (info->vendor == vendorID && info->device == deviceID) {
122 			if (name)
123 				*name = info->name;
124 			if (flags)
125 				*flags = info->flags;
126 			return B_OK;
127 		}
128 	}
129 	return B_ERROR;
130 }
131 
132 
133 static status_t
134 register_sim(device_node_handle parent)
135 {
136 	int32 id = gDeviceManager->create_id(AHCI_ID_GENERATOR);
137 	if (id < 0)
138 		return id;
139 
140 	{
141 		device_attr attrs[] = {
142 			{ B_DRIVER_MODULE, B_STRING_TYPE,
143 				{ string: AHCI_SIM_MODULE_NAME }},
144 			{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE,
145 				{ string: SCSI_FOR_SIM_MODULE_NAME }},
146 
147 			{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
148 				{ string: AHCI_DEVICE_MODULE_NAME }},
149 			{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: 255 }},
150 			{ AHCI_ID_ITEM, B_UINT32_TYPE, { ui32: id }},
151 			{ PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE,
152 				{ string: AHCI_ID_GENERATOR }},
153 			{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: id }},
154 
155 			{ NULL }
156 		};
157 
158 		device_node_handle node;
159 		status_t status = gDeviceManager->register_device(parent, attrs, NULL,
160 			&node);
161 		if (status < B_OK)
162 			gDeviceManager->free_id(AHCI_ID_GENERATOR, id);
163 
164 		return status;
165 	}
166 }
167 
168 
169 //	#pragma mark -
170 
171 
172 static float
173 ahci_supports_device(device_node_handle parent, bool *_noConnection)
174 {
175 	uint8 baseClass, subClass, classAPI;
176 	uint16 vendorID;
177 	uint16 deviceID;
178 	bool isPCI;
179 	const char *name;
180 	char *bus;
181 
182 	TRACE("ahci_supports_device\n");
183 
184 	if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus,	false) < B_OK)
185 		return 0.0f;
186 	isPCI = !strcmp(bus, "pci");
187 	free(bus);
188 	if (!isPCI)
189 		return 0.0f;
190 
191 	if (gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_BASE_CLASS_ID_ITEM, &baseClass, false) < B_OK
192 		|| gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_SUB_CLASS_ID_ITEM, &subClass, false) < B_OK
193 		|| gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_API_ID_ITEM, &classAPI, false) < B_OK
194 		|| gDeviceManager->get_attr_uint16(parent, PCI_DEVICE_VENDOR_ID_ITEM, &vendorID, false) < B_OK
195 		|| gDeviceManager->get_attr_uint16(parent, PCI_DEVICE_DEVICE_ID_ITEM, &deviceID, false) < B_OK)
196 		return 0.0f;
197 
198 	if (get_device_info(vendorID, deviceID, &name, NULL) < B_OK) {
199 		if (baseClass != PCI_mass_storage || subClass != PCI_sata || classAPI != PCI_sata_ahci)
200 			return 0.0f;
201 		TRACE("generic AHCI controller found! vendor 0x%04x, device 0x%04x\n", vendorID, deviceID);
202 		return 0.8f;
203 	}
204 
205 	if (vendorID == PCI_VENDOR_JMICRON) {
206 		// JMicron uses the same device ID for SATA and PATA controllers,
207 		// check if BAR5 exists to determine if it's a AHCI controller
208 		uint8 bus, device, function;
209 		pci_info info;
210 		pci_module_info *pci;
211 		size_t size = 0;
212 		int i;
213 		gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_BUS_ITEM, &bus, false);
214 		gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_DEVICE_ITEM, &device, false);
215 		gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_FUNCTION_ITEM, &function, false);
216 		get_module(B_PCI_MODULE_NAME, (module_info **)&pci);
217 		for (i = 0; B_OK == pci->get_nth_pci_info(i, &info); i++) {
218 			if (info.bus == bus && info.device == device && info.function == function) {
219 				size = info.u.h0.base_register_sizes[5];
220 				break;
221 			}
222 		}
223 		put_module(B_PCI_MODULE_NAME);
224 		if (size == 0)
225 			return 0.0f;
226 	}
227 
228 	TRACE("AHCI controller %s found!\n", name);
229 	return 1.0f;
230 }
231 
232 
233 static status_t
234 ahci_register_device(device_node_handle parent)
235 {
236 	device_node_handle node;
237 	status_t status;
238 
239 	device_attr attrs[] = {
240 		// info about ourself and our consumer
241 		{ B_DRIVER_MODULE, B_STRING_TYPE, { string: AHCI_DEVICE_MODULE_NAME }},
242 
243 		{ SCSI_DEVICE_MAX_TARGET_COUNT, B_UINT32_TYPE,
244 			{ ui32: 33 }},
245 
246 		// DMA properties
247 		// data must be word-aligned;
248 		{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE,
249 			{ ui32: 1 }},
250 		// one S/G block must not cross 64K boundary
251 		{ B_BLOCK_DEVICE_DMA_BOUNDARY, B_UINT32_TYPE,
252 			{ ui32: 0xffff }},
253 		// max size of S/G block is 16 bits with zero being 64K
254 		{ B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE,
255 			{ ui32: 0x10000 }},
256 		// see definition of MAX_SG_COUNT
257 		{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE,
258 			{ ui32: 32 /* whatever... */ }},
259 		{ NULL }
260 	};
261 
262 	TRACE("ahci_register_device\n");
263 
264 	status = gDeviceManager->register_device(parent, attrs,
265 		NULL, &node);
266 	if (status < B_OK)
267 		return status;
268 
269 	// TODO: register SIM for every controller we find!
270 	return register_sim(node);
271 }
272 
273 
274 static status_t
275 ahci_init_driver(device_node_handle node, void *userCookie, void **_cookie)
276 {
277 	pci_device *_userCookie = userCookie;
278 	pci_device pciDevice;
279 	device_node_handle parent;
280 	status_t status;
281 
282 	TRACE("ahci_init_driver, userCookie %p\n", userCookie);
283 
284 	parent = gDeviceManager->get_parent(node);
285 
286 	// initialize parent (the bus) to get the PCI interface and device
287 	status = gDeviceManager->init_driver(parent, NULL,
288 		(driver_module_info **)&gPCI, (void **)&pciDevice);
289 	if (status != B_OK)
290 		return status;
291 
292 	TRACE("ahci_init_driver: gPCI %p, pciDevice %p\n", gPCI, pciDevice);
293 
294 	gDeviceManager->put_device_node(parent);
295 
296 	*_userCookie = pciDevice;
297 	*_cookie = node;
298 	return B_OK;
299 }
300 
301 
302 static status_t
303 ahci_uninit_driver(void *cookie)
304 {
305 	device_node_handle node = cookie;
306 	device_node_handle parent;
307 
308 	TRACE("ahci_uninit_driver, cookie %p\n", cookie);
309 
310 	parent = gDeviceManager->get_parent(node);
311 	gDeviceManager->uninit_driver(parent);
312 	gDeviceManager->put_device_node(parent);
313 	return B_OK;
314 }
315 
316 
317 static void
318 ahci_device_removed(device_node_handle node, void *cookie)
319 {
320 	TRACE("ahci_device_removed, cookie %p\n", cookie);
321 }
322 
323 
324 static void
325 ahci_device_cleanup(device_node_handle node)
326 {
327 	TRACE("ahci_device_cleanup\n");
328 }
329 
330 
331 static void
332 ahci_get_supported_paths(const char ***_busses, const char ***_devices)
333 {
334 	static const char *kBus[] = { "pci", NULL };
335 	static const char *kDevice[] = { "drivers/dev/disk/sata", NULL };
336 
337 	TRACE("ahci_get_supported_paths\n");
338 
339 	*_busses = kBus;
340 	*_devices = kDevice;
341 }
342 
343 
344 static status_t
345 std_ops(int32 op, ...)
346 {
347 	switch (op) {
348 		case B_MODULE_INIT:
349 		case B_MODULE_UNINIT:
350 			return B_OK;
351 
352 		default:
353 			return B_ERROR;
354 	}
355 }
356 
357 
358 driver_module_info sAHCIDevice = {
359 	{
360 		AHCI_DEVICE_MODULE_NAME,
361 		0,
362 		std_ops
363 	},
364 	ahci_supports_device,
365 	ahci_register_device,
366 	ahci_init_driver,
367 	ahci_uninit_driver,
368 	ahci_device_removed,
369 	ahci_device_cleanup,
370 	ahci_get_supported_paths,
371 };
372 
373 
374 module_dependency module_dependencies[] = {
375 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
376 //	{ B_PCI_MODULE_NAME, (module_info **)&gPCI },
377 	{ SCSI_FOR_SIM_MODULE_NAME, (module_info **)&gSCSI },
378 	{}
379 };
380 
381 
382 module_info *modules[] = {
383 	(module_info *)&sAHCIDevice,
384 	(module_info *)&gAHCISimInterface,
385 	NULL
386 };
387