xref: /haiku/src/add-ons/kernel/busses/scsi/ahci/ahci.c (revision 35f57d15ffc68ce74fbb4408c939173f080ee4cc)
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 device_manager_info *gDeviceManager;
21 
22 
23 static status_t
24 register_sim(device_node_handle parent)
25 {
26 	int32 id = gDeviceManager->create_id(AHCI_ID_GENERATOR);
27 	if (id < 0)
28 		return id;
29 
30 	{
31 		device_attr attrs[] = {
32 			{ B_DRIVER_MODULE, B_STRING_TYPE,
33 				{ string: AHCI_SIM_MODULE_NAME }},
34 			{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE,
35 				{ string: SCSI_FOR_SIM_MODULE_NAME }},
36 
37 			{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
38 				{ string: AHCI_DEVICE_MODULE_NAME }},
39 			{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: 255 }},
40 			{ AHCI_ID_ITEM, B_UINT32_TYPE, { ui32: id }},
41 			{ PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE,
42 				{ string: AHCI_ID_GENERATOR }},
43 			{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: id }},
44 
45 			{ NULL }
46 		};
47 
48 		device_node_handle node;
49 		status_t status = gDeviceManager->register_device(parent, attrs, NULL,
50 			&node);
51 		if (status < B_OK)
52 			gDeviceManager->free_id(AHCI_ID_GENERATOR, id);
53 
54 		return status;
55 	}
56 }
57 
58 
59 //	#pragma mark -
60 
61 
62 static float
63 ahci_supports_device(device_node_handle parent, bool *_noConnection)
64 {
65 	uint8 baseClass, subClass, classAPI;
66 	uint16 vendorID;
67 	uint16 deviceID;
68 	char *bus;
69 
70 	TRACE("ahci_supports_device\n");
71 
72 	if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus,
73 				false) != B_OK
74 		|| gDeviceManager->get_attr_uint8(parent,
75 				PCI_DEVICE_BASE_CLASS_ID_ITEM, &baseClass, false) != B_OK
76 		|| gDeviceManager->get_attr_uint8(parent,
77 				PCI_DEVICE_SUB_CLASS_ID_ITEM, &subClass, false) != B_OK
78 		|| gDeviceManager->get_attr_uint8(parent,
79 				PCI_DEVICE_API_ID_ITEM, &classAPI, false) != B_OK
80 		|| gDeviceManager->get_attr_uint16(parent,
81 				PCI_DEVICE_VENDOR_ID_ITEM, &vendorID, false) != B_OK
82 		|| gDeviceManager->get_attr_uint16(parent,
83 			PCI_DEVICE_DEVICE_ID_ITEM, &deviceID, false) != B_OK)
84 		return B_ERROR;
85 
86 #if 1
87 	if (strcmp(bus, "pci") || baseClass != PCI_mass_storage
88 		|| subClass != PCI_sata || classAPI != PCI_sata_ahci) {
89 		free(bus);
90 		return 0.0f;
91 	}
92 #else
93 	if (strcmp(bus, "pci") || baseClass != PCI_mass_storage
94 		|| subClass != PCI_ide) {
95 		free(bus);
96 		return 0.0;
97 	}
98 #endif
99 
100 	TRACE("controller found! vendor 0x%04x, device 0x%04x\n",
101 		vendorID, deviceID);
102 
103 	free(bus);
104 	return 0.5;
105 }
106 
107 
108 static status_t
109 ahci_register_device(device_node_handle parent)
110 {
111 	device_node_handle node;
112 	status_t status;
113 
114 	device_attr attrs[] = {
115 		// info about ourself and our consumer
116 		{ B_DRIVER_MODULE, B_STRING_TYPE, { string: AHCI_DEVICE_MODULE_NAME }},
117 
118 		{ SCSI_DEVICE_MAX_TARGET_COUNT, B_UINT32_TYPE,
119 			{ ui32: 33 }},
120 
121 		// DMA properties
122 		// data must be word-aligned;
123 		{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE,
124 			{ ui32: 1 }},
125 		// one S/G block must not cross 64K boundary
126 		{ B_BLOCK_DEVICE_DMA_BOUNDARY, B_UINT32_TYPE,
127 			{ ui32: 0xffff }},
128 		// max size of S/G block is 16 bits with zero being 64K
129 		{ B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, B_UINT32_TYPE,
130 			{ ui32: 0x10000 }},
131 		// see definition of MAX_SG_COUNT
132 		{ B_BLOCK_DEVICE_MAX_SG_BLOCKS, B_UINT32_TYPE,
133 			{ ui32: 32 /* whatever... */ }},
134 		{ NULL }
135 	};
136 
137 	TRACE("ahci_register_device\n");
138 
139 	status = gDeviceManager->register_device(parent, attrs,
140 		NULL, &node);
141 	if (status < B_OK)
142 		return status;
143 
144 	// TODO: register SIM for every controller we find!
145 	return register_sim(node);
146 }
147 
148 
149 static status_t
150 ahci_init_driver(device_node_handle node, void *userCookie, void **_cookie)
151 {
152 	pci_device *_userCookie = userCookie;
153 	pci_device pciDevice;
154 	device_node_handle parent;
155 	status_t status;
156 
157 	TRACE("ahci_init_driver, userCookie %p\n", userCookie);
158 
159 	parent = gDeviceManager->get_parent(node);
160 
161 	// initialize parent (the bus) to get the PCI interface and device
162 	status = gDeviceManager->init_driver(parent, NULL,
163 		(driver_module_info **)&gPCI, (void **)&pciDevice);
164 	if (status != B_OK)
165 		return status;
166 
167 	gDeviceManager->put_device_node(parent);
168 
169 	*_userCookie = pciDevice;
170 	*_cookie = node;
171 	return B_OK;
172 }
173 
174 
175 static status_t
176 ahci_uninit_driver(void *cookie)
177 {
178 	device_node_handle node = cookie;
179 	device_node_handle parent;
180 
181 	TRACE("ahci_uninit_driver, cookie %p\n", cookie);
182 
183 	parent = gDeviceManager->get_parent(node);
184 	gDeviceManager->uninit_driver(parent);
185 	gDeviceManager->put_device_node(parent);
186 	return B_OK;
187 }
188 
189 
190 static void
191 ahci_device_removed(device_node_handle node, void *cookie)
192 {
193 	TRACE("ahci_device_removed, cookie %p\n", cookie);
194 }
195 
196 
197 static void
198 ahci_device_cleanup(device_node_handle node)
199 {
200 	TRACE("ahci_device_cleanup\n");
201 }
202 
203 
204 static void
205 ahci_get_supported_paths(const char ***_busses, const char ***_devices)
206 {
207 	static const char *kBus[] = { "pci", NULL };
208 	static const char *kDevice[] = { "drivers/dev/disk/sata", NULL };
209 
210 	TRACE("ahci_get_supported_paths\n");
211 
212 	*_busses = kBus;
213 	*_devices = kDevice;
214 }
215 
216 
217 static status_t
218 std_ops(int32 op, ...)
219 {
220 	switch (op) {
221 		case B_MODULE_INIT:
222 		case B_MODULE_UNINIT:
223 			return B_OK;
224 
225 		default:
226 			return B_ERROR;
227 	}
228 }
229 
230 
231 driver_module_info sAHCIDevice = {
232 	{
233 		AHCI_DEVICE_MODULE_NAME,
234 		0,
235 		std_ops
236 	},
237 	ahci_supports_device,
238 	ahci_register_device,
239 	ahci_init_driver,
240 	ahci_uninit_driver,
241 	ahci_device_removed,
242 	ahci_device_cleanup,
243 	ahci_get_supported_paths,
244 };
245 
246 module_dependency module_dependencies[] = {
247 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
248 	{ SCSI_FOR_SIM_MODULE_NAME, (module_info **)&gSCSI },
249 	{}
250 };
251 
252 module_info *modules[] = {
253 	(module_info *)&sAHCIDevice,
254 	(module_info *)&gAHCISimInterface,
255 	NULL
256 };
257