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