xref: /haiku/src/add-ons/kernel/bus_managers/scsi/busses.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
1 /*
2  * Copyright 2002/03, Thomas Kurschel. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 /*
7 	Part of Open SCSI bus manager
8 
9 	Bus node layer.
10 
11 	Whenever a controller driver publishes a new controller, a new SCSI bus
12 	for public and internal use is registered in turn. After that, this
13 	bus is told to rescan for devices. For each device, there is a
14 	device registered for peripheral drivers. (see devices.c)
15 */
16 
17 #include "scsi_internal.h"
18 
19 #include <string.h>
20 #include <malloc.h>
21 
22 
23 // bus service should hurry up a bit - good controllers don't take much time
24 // but are very happy to be busy; don't make it realtime though as we
25 // don't really need that but would risk to steel processing power of
26 // realtime-demanding threads
27 #define BUS_SERVICE_PRIORITY B_URGENT_DISPLAY_PRIORITY
28 
29 
30 /**	implementation of service thread:
31  *	it handles DPC and pending requests
32  */
33 
34 static void
35 scsi_do_service(scsi_bus_info *bus)
36 {
37 	while (true) {
38 		SHOW_FLOW0( 3, "" );
39 
40 		// handle DPCs first as they are more urgent
41 		if (scsi_check_exec_dpc(bus))
42 			continue;
43 
44 		if (scsi_check_exec_service(bus))
45 			continue;
46 
47 		break;
48 	}
49 }
50 
51 
52 /** main loop of service thread */
53 
54 static int32
55 scsi_service_threadproc(void *arg)
56 {
57 	scsi_bus_info *bus = (scsi_bus_info *)arg;
58 	int32 processed_notifications = 0;
59 
60 	SHOW_FLOW(3, "bus = %p", bus);
61 
62 	while (true) {
63 		// we handle multiple requests in scsi_do_service at once;
64 		// to save time, we will acquire all notifications that are sent
65 		// up to now at once.
66 		// (Sadly, there is no "set semaphore to zero" function, so this
67 		//  is a poor-man emulation)
68 		acquire_sem_etc(bus->start_service, processed_notifications + 1, 0, 0);
69 
70 		SHOW_FLOW0( 3, "1" );
71 
72 		if (bus->shutting_down)
73 			break;
74 
75 		// get number of notifications _before_ servicing to make sure no new
76 		// notifications are sent after do_service()
77 		get_sem_count(bus->start_service, &processed_notifications);
78 
79 		scsi_do_service(bus);
80 	}
81 
82 	return 0;
83 }
84 
85 
86 static scsi_bus_info *
87 scsi_create_bus(device_node *node, uint8 path_id)
88 {
89 	scsi_bus_info *bus;
90 	int res;
91 
92 	SHOW_FLOW0(3, "");
93 
94 	bus = (scsi_bus_info *)malloc(sizeof(*bus));
95 	if (bus == NULL)
96 		return NULL;
97 
98 	memset(bus, 0, sizeof(*bus));
99 
100 	bus->path_id = path_id;
101 
102 	if (pnp->get_attr_uint32(node, SCSI_DEVICE_MAX_TARGET_COUNT, &bus->max_target_count, true) != B_OK)
103 		bus->max_target_count = MAX_TARGET_ID + 1;
104 	if (pnp->get_attr_uint32(node, SCSI_DEVICE_MAX_LUN_COUNT, &bus->max_lun_count, true) != B_OK)
105 		bus->max_lun_count = MAX_LUN_ID + 1;
106 
107 	// our scsi_ccb only has a uchar for target_id
108 	if (bus->max_target_count > 256)
109 		bus->max_target_count = 256;
110 	// our scsi_ccb only has a uchar for target_lun
111 	if (bus->max_lun_count > 256)
112 		bus->max_lun_count = 256;
113 
114 	bus->node = node;
115 	bus->lock_count = bus->blocked[0] = bus->blocked[1] = 0;
116 	bus->sim_overflow = 0;
117 	bus->shutting_down = false;
118 
119 	bus->waiting_devices = NULL;
120 	//bus->resubmitted_req = NULL;
121 
122 	bus->dpc_list = NULL;
123 
124 	if ((bus->scan_lun_lock = create_sem(1, "scsi_scan_lun_lock")) < 0) {
125 		res = bus->scan_lun_lock;
126 		goto err6;
127 	}
128 
129 	bus->start_service = create_sem(0, "scsi_start_service");
130 	if (bus->start_service < 0) {
131 		res = bus->start_service;
132 		goto err4;
133 	}
134 
135 	res = INIT_BEN(&bus->mutex, "scsi_bus_mutex");
136 
137 	if (res < B_OK)
138 		goto err3;
139 
140 	spinlock_irq_init(&bus->dpc_lock);
141 
142 	res = scsi_init_ccb_alloc(bus);
143 	if (res < B_OK)
144 		goto err2;
145 
146 	bus->service_thread = spawn_kernel_thread(scsi_service_threadproc,
147 		"scsi_bus_service", BUS_SERVICE_PRIORITY, bus);
148 
149 	if (bus->service_thread < 0) {
150 		res = bus->service_thread;
151 		goto err1;
152 	}
153 
154 	resume_thread(bus->service_thread);
155 
156 	return bus;
157 
158 err1:
159 	scsi_uninit_ccb_alloc(bus);
160 err2:
161 	DELETE_BEN(&bus->mutex);
162 err3:
163 	delete_sem(bus->start_service);
164 err4:
165 	delete_sem(bus->scan_lun_lock);
166 err6:
167 	free(bus);
168 	return NULL;
169 }
170 
171 
172 static status_t
173 scsi_destroy_bus(scsi_bus_info *bus)
174 {
175 	int32 retcode;
176 
177 	// noone is using this bus now, time to clean it up
178 	bus->shutting_down = true;
179 	release_sem(bus->start_service);
180 
181 	wait_for_thread(bus->service_thread, &retcode);
182 
183 	delete_sem(bus->start_service);
184 	DELETE_BEN(&bus->mutex);
185 	delete_sem(bus->scan_lun_lock);
186 
187 	scsi_uninit_ccb_alloc(bus);
188 
189 	return B_OK;
190 }
191 
192 
193 static status_t
194 scsi_init_bus(device_node *node, void **cookie)
195 {
196 	uint8 path_id;
197 	scsi_bus_info *bus;
198 	status_t res;
199 
200 	SHOW_FLOW0( 3, "" );
201 
202 	if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, false) != B_OK)
203 		return B_ERROR;
204 
205 	bus = scsi_create_bus(node, path_id);
206 	if (bus == NULL)
207 		return B_NO_MEMORY;
208 
209 	// extract controller/protocoll restrictions from node
210 	if (pnp->get_attr_uint32(node, B_DMA_ALIGNMENT, &bus->dma_params.alignment,
211 			true) != B_OK)
212 		bus->dma_params.alignment = 0;
213 	if (pnp->get_attr_uint32(node, B_DMA_MAX_TRANSFER_BLOCKS,
214 			&bus->dma_params.max_blocks, true) != B_OK)
215 		bus->dma_params.max_blocks = 0xffffffff;
216 	if (pnp->get_attr_uint32(node, B_DMA_BOUNDARY,
217 			&bus->dma_params.dma_boundary, true) != B_OK)
218 		bus->dma_params.dma_boundary = ~0;
219 	if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_BLOCKS,
220 			&bus->dma_params.max_sg_block_size, true) != B_OK)
221 		bus->dma_params.max_sg_block_size = 0xffffffff;
222 	if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_COUNT,
223 			&bus->dma_params.max_sg_blocks, true) != B_OK)
224 		bus->dma_params.max_sg_blocks = ~0;
225 
226 	// do some sanity check:
227 	bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment;
228 
229 	if (bus->dma_params.alignment > B_PAGE_SIZE) {
230 		SHOW_ERROR(0, "Alignment (0x%" B_PRIx32 ") must be less then "
231 			"B_PAGE_SIZE", bus->dma_params.alignment);
232 		res = B_ERROR;
233 		goto err;
234 	}
235 
236 	if (bus->dma_params.max_sg_block_size < 1) {
237 		SHOW_ERROR(0, "Max s/g block size (0x%" B_PRIx32 ") is too small",
238 			bus->dma_params.max_sg_block_size);
239 		res = B_ERROR;
240 		goto err;
241 	}
242 
243 	if (bus->dma_params.dma_boundary < B_PAGE_SIZE - 1) {
244 		SHOW_ERROR(0, "DMA boundary (0x%" B_PRIx32 ") must be at least "
245 			"B_PAGE_SIZE", bus->dma_params.dma_boundary);
246 		res = B_ERROR;
247 		goto err;
248 	}
249 
250 	if (bus->dma_params.max_blocks < 1 || bus->dma_params.max_sg_blocks < 1) {
251 		SHOW_ERROR(0, "Max blocks (%" B_PRIu32 ") and max s/g blocks (%"
252 			B_PRIu32 ") must be at least 1", bus->dma_params.max_blocks,
253 			bus->dma_params.max_sg_blocks);
254 		res = B_ERROR;
255 		goto err;
256 	}
257 
258 	{
259 		device_node *parent = pnp->get_parent_node(node);
260 		pnp->get_driver(parent, (driver_module_info **)&bus->interface,
261 			(void **)&bus->sim_cookie);
262 		pnp->put_node(parent);
263 
264 		bus->interface->set_scsi_bus(bus->sim_cookie, bus);
265 	}
266 
267 	// cache inquiry data
268 	scsi_inquiry_path(bus, &bus->inquiry_data);
269 
270 	// get max. number of commands on bus
271 	bus->left_slots = bus->inquiry_data.hba_queue_size;
272 	SHOW_FLOW( 3, "Bus has %d slots", bus->left_slots );
273 
274 	*cookie = bus;
275 
276 	return B_OK;
277 
278 err:
279 	scsi_destroy_bus(bus);
280 	return res;
281 }
282 
283 
284 static void
285 scsi_uninit_bus(scsi_bus_info *bus)
286 {
287 	scsi_destroy_bus(bus);
288 }
289 
290 
291 uchar
292 scsi_inquiry_path(scsi_bus bus, scsi_path_inquiry *inquiry_data)
293 {
294 	SHOW_FLOW(4, "path_id=%d", bus->path_id);
295 	return bus->interface->path_inquiry(bus->sim_cookie, inquiry_data);
296 }
297 
298 
299 static uchar
300 scsi_reset_bus(scsi_bus_info *bus)
301 {
302 	return bus->interface->reset_bus(bus->sim_cookie);
303 }
304 
305 
306 static status_t
307 scsi_bus_module_init(void)
308 {
309 	SHOW_FLOW0(4, "");
310 	return init_temp_sg();
311 }
312 
313 
314 static status_t
315 scsi_bus_module_uninit(void)
316 {
317 	SHOW_INFO0(4, "");
318 
319 	uninit_temp_sg();
320 	return B_OK;
321 }
322 
323 
324 static status_t
325 std_ops(int32 op, ...)
326 {
327 	switch (op) {
328 		case B_MODULE_INIT:
329 			return scsi_bus_module_init();
330 		case B_MODULE_UNINIT:
331 			return scsi_bus_module_uninit();
332 
333 		default:
334 			return B_ERROR;
335 	}
336 }
337 
338 
339 scsi_bus_interface scsi_bus_module = {
340 	{
341 		{
342 			SCSI_BUS_MODULE_NAME,
343 			0,
344 			std_ops
345 		},
346 
347 		NULL,	// supported devices
348 		NULL,	// register node
349 		scsi_init_bus,
350 		(void (*)(void *))scsi_uninit_bus,
351 		(status_t (*)(void *))scsi_scan_bus,
352 		(status_t (*)(void *))scsi_scan_bus,
353 		NULL
354 	},
355 
356 	scsi_inquiry_path,
357 	scsi_reset_bus,
358 };
359