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
12#define TRACE(a...) dprintf("ahci: " a)
13#define FLOW(a...)	dprintf("ahci: " a)
14
15#define AHCI_ID_GENERATOR "ahci/id"
16#define AHCI_ID_ITEM "ahci/id"
17#define AHCI_BRIDGE_PRETTY_NAME "AHCI Bridge"
18#define AHCI_CONTROLLER_PRETTY_NAME "AHCI Controller"
19
20
21const 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	{ 0x10de, 0x0ab4, "NVIDIA MCP79" },
78	{ 0x10de, 0x0ab5, "NVIDIA MCP79" },
79	{ 0x10de, 0x0ab6, "NVIDIA MCP79" },
80	{ 0x10de, 0x0ab7, "NVIDIA MCP79" },
81	{ 0x10de, 0x0ab8, "NVIDIA MCP79" },
82	{ 0x10de, 0x0ab9, "NVIDIA MCP79" },
83	{ 0x10de, 0x0aba, "NVIDIA MCP79" },
84	{ 0x10de, 0x0abb, "NVIDIA MCP79" },
85	{ 0x10de, 0x0abc, "NVIDIA MCP79" },
86	{ 0x10de, 0x0abd, "NVIDIA MCP79" },
87	{ 0x10de, 0x0abe, "NVIDIA MCP79" },
88	{ 0x10de, 0x0abf, "NVIDIA MCP79" },
89	{ 0x10de, 0x0d84, "NVIDIA MCP89" },
90	{ 0x10de, 0x0d85, "NVIDIA MCP89" },
91	{ 0x10de, 0x0d86, "NVIDIA MCP89" },
92	{ 0x10de, 0x0d87, "NVIDIA MCP89" },
93	{ 0x10de, 0x0d88, "NVIDIA MCP89" },
94	{ 0x10de, 0x0d89, "NVIDIA MCP89" },
95	{ 0x10de, 0x0d8a, "NVIDIA MCP89" },
96	{ 0x10de, 0x0d8b, "NVIDIA MCP89" },
97	{ 0x10de, 0x0d8c, "NVIDIA MCP89" },
98	{ 0x10de, 0x0d8d, "NVIDIA MCP89" },
99	{ 0x10de, 0x0d8e, "NVIDIA MCP89" },
100	{ 0x10de, 0x0d8f, "NVIDIA MCP89" },
101	{ 0x1106, 0x3349, "VIA VT8251" },
102	{ 0x1106, 0x6287, "VIA VT8251" },
103	{ 0x11ab, 0x6121, "Marvell 6121" },
104	{ 0x11ab, 0x6145, "Marvell 6145" },
105	{ 0x197b, 0x2360, "JMicron JMB360" },
106	{ 0x197b, 0x2361, "JMicron JMB361" },
107	{ 0x197b, 0x2362, "JMicron JMB362" },
108	{ 0x197b, 0x2363, "JMicron JMB363" },
109	{ 0x197b, 0x2366, "JMicron JMB366" },
110	{ 0x8086, 0x2652, "Intel ICH6R" },
111	{ 0x8086, 0x2653, "Intel ICH6-M" },
112	{ 0x8086, 0x2681, "Intel 63xxESB" },
113	{ 0x8086, 0x2682, "Intel ESB2" },
114	{ 0x8086, 0x2683, "Intel ESB2" },
115	{ 0x8086, 0x27c1, "Intel ICH7R (AHCI mode)" },
116	{ 0x8086, 0x27c3, "Intel ICH7R (RAID mode)" },
117	{ 0x8086, 0x27c5, "Intel ICH7-M (AHCI mode)" },
118	{ 0x8086, 0x27c6, "Intel ICH7-M DH (RAID mode)" },
119	{ 0x8086, 0x2821, "Intel ICH8 (AHCI mode)" },
120	{ 0x8086, 0x2822, "Intel ICH8R / ICH9 (RAID mode)" },
121	{ 0x8086, 0x2824, "Intel ICH8 (AHCI mode)" },
122	{ 0x8086, 0x2829, "Intel ICH8M (AHCI mode)" },
123	{ 0x8086, 0x282a, "Intel ICH8M (RAID mode)" },
124	{ 0x8086, 0x2922, "Intel ICH9 (AHCI mode)" },
125	{ 0x8086, 0x2923, "Intel ICH9 (AHCI mode)" },
126	{ 0x8086, 0x2924, "Intel ICH9" },
127	{ 0x8086, 0x2925, "Intel ICH9" },
128	{ 0x8086, 0x2927, "Intel ICH9" },
129	{ 0x8086, 0x2929, "Intel ICH9M" },
130	{ 0x8086, 0x292a, "Intel ICH9M" },
131	{ 0x8086, 0x292b, "Intel ICH9M" },
132	{ 0x8086, 0x292c, "Intel ICH9M" },
133	{ 0x8086, 0x292f, "Intel ICH9M" },
134	{ 0x8086, 0x294d, "Intel ICH9" },
135	{ 0x8086, 0x294e, "Intel ICH9M" },
136	{ 0x8086, 0x3a05, "Intel ICH10" },
137	{ 0x8086, 0x3a22, "Intel ICH10" },
138	{ 0x8086, 0x3a25, "Intel ICH10" },
139	{}
140};
141
142
143device_manager_info *gDeviceManager;
144scsi_for_sim_interface *gSCSI;
145
146
147status_t
148get_device_info(uint16 vendorID, uint16 deviceID, const char **name,
149	uint32 *flags)
150{
151	const device_info *info;
152	for (info = kSupportedDevices; info->vendor; info++) {
153		if (info->vendor == vendorID && info->device == deviceID) {
154			if (name)
155				*name = info->name;
156			if (flags)
157				*flags = info->flags;
158			return B_OK;
159		}
160	}
161	return B_ERROR;
162}
163
164
165static status_t
166register_sim(device_node *parent)
167{
168	int32 id = gDeviceManager->create_id(AHCI_ID_GENERATOR);
169	if (id < 0)
170		return id;
171
172	{
173		device_attr attrs[] = {
174			{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
175				{ string: SCSI_FOR_SIM_MODULE_NAME }},
176			{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
177				{ string: AHCI_CONTROLLER_PRETTY_NAME }},
178
179			{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
180				{ string: AHCI_DEVICE_MODULE_NAME }},
181			{ B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { ui32: 255 }},
182			{ AHCI_ID_ITEM, B_UINT32_TYPE, { ui32: id }},
183//			{ PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE,
184//				{ string: AHCI_ID_GENERATOR }},
185//			{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: id }},
186
187			{ NULL }
188		};
189
190		status_t status = gDeviceManager->register_node(parent,
191			AHCI_SIM_MODULE_NAME, attrs, NULL, NULL);
192		if (status < B_OK)
193			gDeviceManager->free_id(AHCI_ID_GENERATOR, id);
194
195		return status;
196	}
197}
198
199
200//	#pragma mark -
201
202
203static float
204ahci_supports_device(device_node *parent)
205{
206	uint16 baseClass, subClass, classAPI;
207	uint16 vendorID;
208	uint16 deviceID;
209	const char *name;
210	const char *bus;
211
212	TRACE("ahci_supports_device\n");
213
214	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
215			< B_OK)
216		return 0.0f;
217
218	if (strcmp(bus, "pci"))
219		return 0.0f;
220
221	if (gDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &baseClass,
222				false) < B_OK
223		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subClass,
224				false) < B_OK
225		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_INTERFACE,
226				&classAPI, false) < B_OK
227		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID,
228				&vendorID, false) < B_OK
229		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID,
230				false) < B_OK)
231		return 0.0f;
232
233	if (get_device_info(vendorID, deviceID, &name, NULL) < B_OK) {
234		if (baseClass != PCI_mass_storage || subClass != PCI_sata
235			|| classAPI != PCI_sata_ahci)
236			return 0.0f;
237		TRACE("generic AHCI controller found! vendor 0x%04x, device 0x%04x\n", vendorID, deviceID);
238		return 0.8f;
239	}
240
241	if (vendorID == PCI_VENDOR_JMICRON) {
242		// JMicron uses the same device ID for SATA and PATA controllers,
243		// check if BAR5 exists to determine if it's a AHCI controller
244		pci_device_module_info *pci;
245		pci_device *device;
246		pci_info info;
247
248		gDeviceManager->get_driver(parent, (driver_module_info **)&pci,
249			(void **)&device);
250		pci->get_pci_info(device, &info);
251
252		if (info.u.h0.base_register_sizes[5] == 0)
253			return 0.0f;
254	}
255
256	TRACE("AHCI controller %s found!\n", name);
257	return 1.0f;
258}
259
260
261static status_t
262ahci_register_device(device_node *parent)
263{
264	device_attr attrs[] = {
265		{ SCSI_DEVICE_MAX_TARGET_COUNT, B_UINT32_TYPE,
266			{ ui32: 33 }},
267		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
268			{ string: AHCI_BRIDGE_PRETTY_NAME }},
269
270		// DMA properties
271		// data must be word-aligned;
272		{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1 }},
273		// one S/G block must not cross 64K boundary
274		{ B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
275		// max size of S/G block is 16 bits with zero being 64K
276		{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { ui32: 0x10000 }},
277		{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
278			{ ui32: 32 /* whatever... */ }},
279		{ B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { ui64: 0x100000000LL }},
280			// TODO: We don't know at this point whether 64 bit addressing is
281			// supported. That's indicated by a capability flag. Play it safe
282			// for now.
283		{ NULL }
284	};
285
286	TRACE("ahci_register_device\n");
287
288	return gDeviceManager->register_node(parent, AHCI_DEVICE_MODULE_NAME,
289		attrs, NULL, NULL);
290}
291
292
293static status_t
294ahci_init_driver(device_node *node, void **_cookie)
295{
296	TRACE("ahci_init_driver\n");
297	*_cookie = node;
298	return B_OK;
299}
300
301
302static void
303ahci_uninit_driver(void *cookie)
304{
305	TRACE("ahci_uninit_driver, cookie %p\n", cookie);
306}
307
308
309static status_t
310ahci_register_child_devices(void *cookie)
311{
312	device_node *node = (device_node *)cookie;
313
314	// TODO: register SIM for every controller we find!
315	return register_sim(node);
316}
317
318
319static void
320ahci_device_removed(void *cookie)
321{
322	TRACE("ahci_device_removed, cookie %p\n", cookie);
323}
324
325
326static status_t
327std_ops(int32 op, ...)
328{
329	switch (op) {
330		case B_MODULE_INIT:
331		case B_MODULE_UNINIT:
332			return B_OK;
333
334		default:
335			return B_ERROR;
336	}
337}
338
339
340driver_module_info sAHCIDevice = {
341	{
342		AHCI_DEVICE_MODULE_NAME,
343		0,
344		std_ops
345	},
346	ahci_supports_device,
347	ahci_register_device,
348	ahci_init_driver,
349	ahci_uninit_driver,
350	ahci_register_child_devices,
351	NULL,	// rescan
352	ahci_device_removed
353};
354
355
356module_dependency module_dependencies[] = {
357	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
358	{ SCSI_FOR_SIM_MODULE_NAME, (module_info **)&gSCSI },
359	{}
360};
361
362
363module_info *modules[] = {
364	(module_info *)&sAHCIDevice,
365	(module_info *)&gAHCISimInterface,
366	NULL
367};
368