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
34static void
35scsi_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
54static int32
55scsi_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
86static scsi_bus_info *
87scsi_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	mutex_init(&bus->mutex, "scsi_bus_mutex");
136	spinlock_irq_init(&bus->dpc_lock);
137
138	res = scsi_init_ccb_alloc(bus);
139	if (res < B_OK)
140		goto err2;
141
142	bus->service_thread = spawn_kernel_thread(scsi_service_threadproc,
143		"scsi_bus_service", BUS_SERVICE_PRIORITY, bus);
144
145	if (bus->service_thread < 0) {
146		res = bus->service_thread;
147		goto err1;
148	}
149
150	resume_thread(bus->service_thread);
151
152	return bus;
153
154err1:
155	scsi_uninit_ccb_alloc(bus);
156err2:
157	mutex_destroy(&bus->mutex);
158	delete_sem(bus->start_service);
159err4:
160	delete_sem(bus->scan_lun_lock);
161err6:
162	free(bus);
163	return NULL;
164}
165
166
167static status_t
168scsi_destroy_bus(scsi_bus_info *bus)
169{
170	int32 retcode;
171
172	// noone is using this bus now, time to clean it up
173	bus->shutting_down = true;
174	release_sem(bus->start_service);
175
176	wait_for_thread(bus->service_thread, &retcode);
177
178	delete_sem(bus->start_service);
179	mutex_destroy(&bus->mutex);
180	delete_sem(bus->scan_lun_lock);
181
182	scsi_uninit_ccb_alloc(bus);
183
184	return B_OK;
185}
186
187
188static status_t
189scsi_init_bus(device_node *node, void **cookie)
190{
191	uint8 path_id;
192	scsi_bus_info *bus;
193	status_t res;
194
195	SHOW_FLOW0( 3, "" );
196
197	if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, false) != B_OK)
198		return B_ERROR;
199
200	bus = scsi_create_bus(node, path_id);
201	if (bus == NULL)
202		return B_NO_MEMORY;
203
204	// extract controller/protocoll restrictions from node
205	if (pnp->get_attr_uint32(node, B_DMA_ALIGNMENT, &bus->dma_params.alignment,
206			true) != B_OK)
207		bus->dma_params.alignment = 0;
208	if (pnp->get_attr_uint32(node, B_DMA_MAX_TRANSFER_BLOCKS,
209			&bus->dma_params.max_blocks, true) != B_OK)
210		bus->dma_params.max_blocks = 0xffffffff;
211	if (pnp->get_attr_uint32(node, B_DMA_BOUNDARY,
212			&bus->dma_params.dma_boundary, true) != B_OK)
213		bus->dma_params.dma_boundary = ~0;
214	if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_BLOCKS,
215			&bus->dma_params.max_sg_block_size, true) != B_OK)
216		bus->dma_params.max_sg_block_size = 0xffffffff;
217	if (pnp->get_attr_uint32(node, B_DMA_MAX_SEGMENT_COUNT,
218			&bus->dma_params.max_sg_blocks, true) != B_OK)
219		bus->dma_params.max_sg_blocks = ~0;
220
221	// do some sanity check:
222	bus->dma_params.max_sg_block_size &= ~bus->dma_params.alignment;
223
224	if (bus->dma_params.alignment > B_PAGE_SIZE) {
225		SHOW_ERROR(0, "Alignment (0x%" B_PRIx32 ") must be less then "
226			"B_PAGE_SIZE", bus->dma_params.alignment);
227		res = B_ERROR;
228		goto err;
229	}
230
231	if (bus->dma_params.max_sg_block_size < 1) {
232		SHOW_ERROR(0, "Max s/g block size (0x%" B_PRIx32 ") is too small",
233			bus->dma_params.max_sg_block_size);
234		res = B_ERROR;
235		goto err;
236	}
237
238	if (bus->dma_params.dma_boundary < B_PAGE_SIZE - 1) {
239		SHOW_ERROR(0, "DMA boundary (0x%" B_PRIx32 ") must be at least "
240			"B_PAGE_SIZE", bus->dma_params.dma_boundary);
241		res = B_ERROR;
242		goto err;
243	}
244
245	if (bus->dma_params.max_blocks < 1 || bus->dma_params.max_sg_blocks < 1) {
246		SHOW_ERROR(0, "Max blocks (%" B_PRIu32 ") and max s/g blocks (%"
247			B_PRIu32 ") must be at least 1", bus->dma_params.max_blocks,
248			bus->dma_params.max_sg_blocks);
249		res = B_ERROR;
250		goto err;
251	}
252
253	{
254		device_node *parent = pnp->get_parent_node(node);
255		pnp->get_driver(parent, (driver_module_info **)&bus->interface,
256			(void **)&bus->sim_cookie);
257		pnp->put_node(parent);
258
259		bus->interface->set_scsi_bus(bus->sim_cookie, bus);
260	}
261
262	// cache inquiry data
263	scsi_inquiry_path(bus, &bus->inquiry_data);
264
265	// get max. number of commands on bus
266	bus->left_slots = bus->inquiry_data.hba_queue_size;
267	SHOW_FLOW( 3, "Bus has %d slots", bus->left_slots );
268
269	*cookie = bus;
270
271	return B_OK;
272
273err:
274	scsi_destroy_bus(bus);
275	return res;
276}
277
278
279static void
280scsi_uninit_bus(scsi_bus_info *bus)
281{
282	scsi_destroy_bus(bus);
283}
284
285
286uchar
287scsi_inquiry_path(scsi_bus bus, scsi_path_inquiry *inquiry_data)
288{
289	SHOW_FLOW(4, "path_id=%d", bus->path_id);
290	return bus->interface->path_inquiry(bus->sim_cookie, inquiry_data);
291}
292
293
294static uchar
295scsi_reset_bus(scsi_bus_info *bus)
296{
297	return bus->interface->reset_bus(bus->sim_cookie);
298}
299
300
301static status_t
302scsi_bus_module_init(void)
303{
304	SHOW_FLOW0(4, "");
305	return init_temp_sg();
306}
307
308
309static status_t
310scsi_bus_module_uninit(void)
311{
312	SHOW_INFO0(4, "");
313
314	uninit_temp_sg();
315	return B_OK;
316}
317
318
319static status_t
320std_ops(int32 op, ...)
321{
322	switch (op) {
323		case B_MODULE_INIT:
324			return scsi_bus_module_init();
325		case B_MODULE_UNINIT:
326			return scsi_bus_module_uninit();
327
328		default:
329			return B_ERROR;
330	}
331}
332
333
334scsi_bus_interface scsi_bus_module = {
335	{
336		{
337			SCSI_BUS_MODULE_NAME,
338			0,
339			std_ops
340		},
341
342		NULL,	// supported devices
343		NULL,	// register node
344		scsi_init_bus,
345		(void (*)(void *))scsi_uninit_bus,
346		(status_t (*)(void *))scsi_scan_bus,
347		(status_t (*)(void *))scsi_scan_bus,
348		NULL
349	},
350
351	scsi_inquiry_path,
352	scsi_reset_bus,
353};
354