xref: /haiku/src/add-ons/kernel/bus_managers/scsi/devices.cpp (revision 4535495d80c86e19e2610e7444a4fcefe3e0f8e6)
1*4535495dSIngo Weinhold /*
2*4535495dSIngo Weinhold  * Copyright 2004-2006, Haiku, Inc. All RightsReserved.
3*4535495dSIngo Weinhold  * Copyright 2002/03, Thomas Kurschel. All rights reserved.
4*4535495dSIngo Weinhold  *
5*4535495dSIngo Weinhold  * Distributed under the terms of the MIT License.
6*4535495dSIngo Weinhold  */
7*4535495dSIngo Weinhold 
8*4535495dSIngo Weinhold /*
9*4535495dSIngo Weinhold 	Device node layer.
10*4535495dSIngo Weinhold 
11*4535495dSIngo Weinhold 	When a SCSI bus is registered, this layer scans for SCSI devices
12*4535495dSIngo Weinhold 	and registers a node for each of them. Peripheral drivers are on
13*4535495dSIngo Weinhold 	top of these nodes.
14*4535495dSIngo Weinhold */
15*4535495dSIngo Weinhold 
16*4535495dSIngo Weinhold #include "scsi_internal.h"
17*4535495dSIngo Weinhold 
18*4535495dSIngo Weinhold #include <string.h>
19*4535495dSIngo Weinhold #include <stdlib.h>
20*4535495dSIngo Weinhold #include <stdio.h>
21*4535495dSIngo Weinhold 
22*4535495dSIngo Weinhold #include <algorithm>
23*4535495dSIngo Weinhold 
24*4535495dSIngo Weinhold 
25*4535495dSIngo Weinhold /** free autosense request of device */
26*4535495dSIngo Weinhold 
27*4535495dSIngo Weinhold static void
28*4535495dSIngo Weinhold scsi_free_autosense_request(scsi_device_info *device)
29*4535495dSIngo Weinhold {
30*4535495dSIngo Weinhold 	SHOW_FLOW0( 3, "" );
31*4535495dSIngo Weinhold 
32*4535495dSIngo Weinhold 	if (device->auto_sense_request != NULL) {
33*4535495dSIngo Weinhold 		scsi_free_ccb(device->auto_sense_request);
34*4535495dSIngo Weinhold 		device->auto_sense_request = NULL;
35*4535495dSIngo Weinhold 	}
36*4535495dSIngo Weinhold 
37*4535495dSIngo Weinhold 	if (device->auto_sense_area > 0) {
38*4535495dSIngo Weinhold 		delete_area(device->auto_sense_area);
39*4535495dSIngo Weinhold 		device->auto_sense_area = 0;
40*4535495dSIngo Weinhold 	}
41*4535495dSIngo Weinhold }
42*4535495dSIngo Weinhold 
43*4535495dSIngo Weinhold 
44*4535495dSIngo Weinhold /** free all data of device */
45*4535495dSIngo Weinhold 
46*4535495dSIngo Weinhold static void
47*4535495dSIngo Weinhold scsi_free_device(scsi_device_info *device)
48*4535495dSIngo Weinhold {
49*4535495dSIngo Weinhold 	SHOW_FLOW0( 3, "" );
50*4535495dSIngo Weinhold 
51*4535495dSIngo Weinhold 	scsi_free_emulation_buffer(device);
52*4535495dSIngo Weinhold 	scsi_free_autosense_request(device);
53*4535495dSIngo Weinhold 
54*4535495dSIngo Weinhold 	unregister_kernel_daemon(scsi_dma_buffer_daemon, device);
55*4535495dSIngo Weinhold 
56*4535495dSIngo Weinhold 	scsi_dma_buffer_free(&device->dma_buffer);
57*4535495dSIngo Weinhold 
58*4535495dSIngo Weinhold 	DELETE_BEN(&device->dma_buffer_lock);
59*4535495dSIngo Weinhold 	delete_sem(device->dma_buffer_owner);
60*4535495dSIngo Weinhold 
61*4535495dSIngo Weinhold 	free(device);
62*4535495dSIngo Weinhold }
63*4535495dSIngo Weinhold 
64*4535495dSIngo Weinhold 
65*4535495dSIngo Weinhold /**	copy string src without trailing zero to dst and remove trailing
66*4535495dSIngo Weinhold  *	spaces size of dst is dst_size, size of src is dst_size-1
67*4535495dSIngo Weinhold  */
68*4535495dSIngo Weinhold 
69*4535495dSIngo Weinhold static void
70*4535495dSIngo Weinhold beautify_string(char *dst, char *src, int dst_size)
71*4535495dSIngo Weinhold {
72*4535495dSIngo Weinhold 	int i;
73*4535495dSIngo Weinhold 
74*4535495dSIngo Weinhold 	memcpy(dst, src, dst_size - 1);
75*4535495dSIngo Weinhold 
76*4535495dSIngo Weinhold 	for (i = dst_size - 2; i >= 0; --i) {
77*4535495dSIngo Weinhold 		if (dst[i] != ' ')
78*4535495dSIngo Weinhold 			break;
79*4535495dSIngo Weinhold 	}
80*4535495dSIngo Weinhold 
81*4535495dSIngo Weinhold 	dst[i + 1] = 0;
82*4535495dSIngo Weinhold }
83*4535495dSIngo Weinhold 
84*4535495dSIngo Weinhold 
85*4535495dSIngo Weinhold /** register new device */
86*4535495dSIngo Weinhold 
87*4535495dSIngo Weinhold status_t
88*4535495dSIngo Weinhold scsi_register_device(scsi_bus_info *bus, uchar target_id,
89*4535495dSIngo Weinhold 	uchar target_lun, scsi_res_inquiry *inquiry_data)
90*4535495dSIngo Weinhold {
91*4535495dSIngo Weinhold 	bool is_atapi, manual_autosense;
92*4535495dSIngo Weinhold 	uint32 orig_max_blocks, max_blocks;
93*4535495dSIngo Weinhold 
94*4535495dSIngo Weinhold 	SHOW_FLOW0( 3, "" );
95*4535495dSIngo Weinhold 
96*4535495dSIngo Weinhold 	// ask for restrictions
97*4535495dSIngo Weinhold 	bus->interface->get_restrictions(bus->sim_cookie,
98*4535495dSIngo Weinhold 		target_id, &is_atapi, &manual_autosense, &max_blocks);
99*4535495dSIngo Weinhold 	if (target_lun != 0)
100*4535495dSIngo Weinhold 		dprintf("WARNING: SCSI target %d lun %d getting restrictions without lun\n",
101*4535495dSIngo Weinhold 			target_id, target_lun);
102*4535495dSIngo Weinhold 
103*4535495dSIngo Weinhold 	// find maximum transfer blocks
104*4535495dSIngo Weinhold 	// set default value to max (need something like ULONG_MAX here)
105*4535495dSIngo Weinhold 	orig_max_blocks = ~0;
106*4535495dSIngo Weinhold 	pnp->get_attr_uint32(bus->node, B_DMA_MAX_TRANSFER_BLOCKS, &orig_max_blocks,
107*4535495dSIngo Weinhold 		true);
108*4535495dSIngo Weinhold 
109*4535495dSIngo Weinhold 	max_blocks = std::min(max_blocks, orig_max_blocks);
110*4535495dSIngo Weinhold 
111*4535495dSIngo Weinhold 	{
112*4535495dSIngo Weinhold 		char vendor_ident[sizeof( inquiry_data->vendor_ident ) + 1];
113*4535495dSIngo Weinhold 		char product_ident[sizeof( inquiry_data->product_ident ) + 1];
114*4535495dSIngo Weinhold 		char product_rev[sizeof( inquiry_data->product_rev ) + 1];
115*4535495dSIngo Weinhold 		device_attr attrs[] = {
116*4535495dSIngo Weinhold 			// connection
117*4535495dSIngo Weinhold 			{ SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }},
118*4535495dSIngo Weinhold 			{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
119*4535495dSIngo Weinhold 
120*4535495dSIngo Weinhold 			// inquiry data (used for both identification and information)
121*4535495dSIngo Weinhold 			{ SCSI_DEVICE_INQUIRY_ITEM, B_RAW_TYPE,
122*4535495dSIngo Weinhold 				{ raw: { inquiry_data, sizeof( *inquiry_data ) }}},
123*4535495dSIngo Weinhold 
124*4535495dSIngo Weinhold 			// some more info for driver loading
125*4535495dSIngo Weinhold 			{ SCSI_DEVICE_TYPE_ITEM, B_UINT8_TYPE, { ui8: inquiry_data->device_type }},
126*4535495dSIngo Weinhold 			{ SCSI_DEVICE_VENDOR_ITEM, B_STRING_TYPE, { string: vendor_ident }},
127*4535495dSIngo Weinhold 			{ SCSI_DEVICE_PRODUCT_ITEM, B_STRING_TYPE, { string: product_ident }},
128*4535495dSIngo Weinhold 			{ SCSI_DEVICE_REVISION_ITEM, B_STRING_TYPE, { string: product_rev }},
129*4535495dSIngo Weinhold 
130*4535495dSIngo Weinhold 			// description of peripheral drivers
131*4535495dSIngo Weinhold 			{ B_DEVICE_BUS, B_STRING_TYPE, { string: "scsi" }},
132*4535495dSIngo Weinhold 
133*4535495dSIngo Weinhold 			// extra restriction of maximum number of blocks per transfer
134*4535495dSIngo Weinhold 			{ B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { ui32: max_blocks }},
135*4535495dSIngo Weinhold 
136*4535495dSIngo Weinhold 			// atapi emulation
137*4535495dSIngo Weinhold 			{ SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }},
138*4535495dSIngo Weinhold 			// manual autosense
139*4535495dSIngo Weinhold 			{ SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM, B_UINT8_TYPE, { ui8: manual_autosense }},
140*4535495dSIngo Weinhold 			{ NULL }
141*4535495dSIngo Weinhold 		};
142*4535495dSIngo Weinhold 
143*4535495dSIngo Weinhold 		beautify_string(vendor_ident, inquiry_data->vendor_ident, sizeof(vendor_ident));
144*4535495dSIngo Weinhold 		beautify_string(product_ident, inquiry_data->product_ident, sizeof(product_ident));
145*4535495dSIngo Weinhold 		beautify_string(product_rev, inquiry_data->product_rev, sizeof(product_rev));
146*4535495dSIngo Weinhold 
147*4535495dSIngo Weinhold 		return pnp->register_node(bus->node, SCSI_DEVICE_MODULE_NAME, attrs,
148*4535495dSIngo Weinhold 			NULL, NULL);
149*4535495dSIngo Weinhold 	}
150*4535495dSIngo Weinhold 
151*4535495dSIngo Weinhold 	return B_OK;
152*4535495dSIngo Weinhold }
153*4535495dSIngo Weinhold 
154*4535495dSIngo Weinhold 
155*4535495dSIngo Weinhold // create data structure for a device
156*4535495dSIngo Weinhold static scsi_device_info *
157*4535495dSIngo Weinhold scsi_create_device(device_node *node, scsi_bus_info *bus,
158*4535495dSIngo Weinhold 	int target_id, int target_lun)
159*4535495dSIngo Weinhold {
160*4535495dSIngo Weinhold 	scsi_device_info *device;
161*4535495dSIngo Weinhold 
162*4535495dSIngo Weinhold 	SHOW_FLOW0( 3, "" );
163*4535495dSIngo Weinhold 
164*4535495dSIngo Weinhold 	device = (scsi_device_info *)malloc(sizeof(*device));
165*4535495dSIngo Weinhold 	if (device == NULL)
166*4535495dSIngo Weinhold 		return NULL;
167*4535495dSIngo Weinhold 
168*4535495dSIngo Weinhold 	memset(device, 0, sizeof(*device));
169*4535495dSIngo Weinhold 
170*4535495dSIngo Weinhold 	device->lock_count = device->blocked[0] = device->blocked[1] = 0;
171*4535495dSIngo Weinhold 	device->sim_overflow = 0;
172*4535495dSIngo Weinhold 	device->queued_reqs = NULL;
173*4535495dSIngo Weinhold 	device->bus = bus;
174*4535495dSIngo Weinhold 	device->target_id = target_id;
175*4535495dSIngo Weinhold 	device->target_lun = target_lun;
176*4535495dSIngo Weinhold 	device->valid = true;
177*4535495dSIngo Weinhold 	device->node = node;
178*4535495dSIngo Weinhold 
179*4535495dSIngo Weinhold 	scsi_dma_buffer_init(&device->dma_buffer);
180*4535495dSIngo Weinhold 
181*4535495dSIngo Weinhold 	if (INIT_BEN(&device->dma_buffer_lock, "dma_buffer") < 0)
182*4535495dSIngo Weinhold 		goto err;
183*4535495dSIngo Weinhold 
184*4535495dSIngo Weinhold 	device->dma_buffer_owner = create_sem(1, "dma_buffer");
185*4535495dSIngo Weinhold 	if (device->dma_buffer_owner < 0)
186*4535495dSIngo Weinhold 		goto err2;
187*4535495dSIngo Weinhold 
188*4535495dSIngo Weinhold 	register_kernel_daemon(scsi_dma_buffer_daemon, device, 5 * 10);
189*4535495dSIngo Weinhold 
190*4535495dSIngo Weinhold 	return device;
191*4535495dSIngo Weinhold 
192*4535495dSIngo Weinhold err2:
193*4535495dSIngo Weinhold 	DELETE_BEN(&device->dma_buffer_lock);
194*4535495dSIngo Weinhold err:
195*4535495dSIngo Weinhold 	free(device);
196*4535495dSIngo Weinhold 	return NULL;
197*4535495dSIngo Weinhold }
198*4535495dSIngo Weinhold 
199*4535495dSIngo Weinhold 
200*4535495dSIngo Weinhold /**	prepare autosense request.
201*4535495dSIngo Weinhold  *	this cannot be done on demand but during init as we may
202*4535495dSIngo Weinhold  *	have run out of ccbs when we need it
203*4535495dSIngo Weinhold  */
204*4535495dSIngo Weinhold 
205*4535495dSIngo Weinhold static status_t
206*4535495dSIngo Weinhold scsi_create_autosense_request(scsi_device_info *device)
207*4535495dSIngo Weinhold {
208*4535495dSIngo Weinhold 	scsi_ccb *request;
209*4535495dSIngo Weinhold 	unsigned char *buffer;
210*4535495dSIngo Weinhold 	scsi_cmd_request_sense *cmd;
211*4535495dSIngo Weinhold 	size_t total_size;
212*4535495dSIngo Weinhold 
213*4535495dSIngo Weinhold 	SHOW_FLOW0( 3, "" );
214*4535495dSIngo Weinhold 
215*4535495dSIngo Weinhold 	device->auto_sense_request = request = scsi_alloc_ccb(device);
216*4535495dSIngo Weinhold 	if (device->auto_sense_request == NULL)
217*4535495dSIngo Weinhold 		return B_NO_MEMORY;
218*4535495dSIngo Weinhold 
219*4535495dSIngo Weinhold 	total_size = SCSI_MAX_SENSE_SIZE + sizeof(physical_entry);
220*4535495dSIngo Weinhold 	total_size = (total_size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
221*4535495dSIngo Weinhold 
222*4535495dSIngo Weinhold 	// allocate buffer for space sense data and S/G list
223*4535495dSIngo Weinhold 	device->auto_sense_area = create_area("auto_sense", (void**)&buffer,
224*4535495dSIngo Weinhold 		B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_32_BIT_FULL_LOCK, 0);
225*4535495dSIngo Weinhold 		// TODO: Use B_FULL_LOCK, if addresses >= 4 GB are supported!
226*4535495dSIngo Weinhold 	if (device->auto_sense_area < 0)
227*4535495dSIngo Weinhold 		goto err;
228*4535495dSIngo Weinhold 
229*4535495dSIngo Weinhold 	request->data = buffer;
230*4535495dSIngo Weinhold 	request->data_length = SCSI_MAX_SENSE_SIZE;
231*4535495dSIngo Weinhold 	request->sg_list = (physical_entry *)(buffer + SCSI_MAX_SENSE_SIZE);
232*4535495dSIngo Weinhold 	request->sg_count = 1;
233*4535495dSIngo Weinhold 
234*4535495dSIngo Weinhold 	get_memory_map(buffer, SCSI_MAX_SENSE_SIZE,
235*4535495dSIngo Weinhold 		(physical_entry *)request->sg_list, 1);
236*4535495dSIngo Weinhold 
237*4535495dSIngo Weinhold 	// disable auto-autosense, just in case;
238*4535495dSIngo Weinhold 	// make sure no other request overtakes sense request;
239*4535495dSIngo Weinhold 	// buffer is/must be DMA safe as we cannot risk trouble with
240*4535495dSIngo Weinhold 	// dynamically allocated DMA buffer
241*4535495dSIngo Weinhold 	request->flags = SCSI_DIR_IN | SCSI_DIS_AUTOSENSE |
242*4535495dSIngo Weinhold 		SCSI_ORDERED_QTAG | SCSI_DMA_SAFE;
243*4535495dSIngo Weinhold 
244*4535495dSIngo Weinhold 	cmd = (scsi_cmd_request_sense *)request->cdb;
245*4535495dSIngo Weinhold 	request->cdb_length = sizeof(*cmd);
246*4535495dSIngo Weinhold 
247*4535495dSIngo Weinhold 	memset(cmd, 0, sizeof(*cmd));
248*4535495dSIngo Weinhold 	cmd->opcode = SCSI_OP_REQUEST_SENSE;
249*4535495dSIngo Weinhold 	cmd->lun = device->target_lun;
250*4535495dSIngo Weinhold 	cmd->allocation_length = SCSI_MAX_SENSE_SIZE;
251*4535495dSIngo Weinhold 
252*4535495dSIngo Weinhold 	return B_OK;
253*4535495dSIngo Weinhold 
254*4535495dSIngo Weinhold err:
255*4535495dSIngo Weinhold 	scsi_free_ccb(request);
256*4535495dSIngo Weinhold 	return B_NO_MEMORY;
257*4535495dSIngo Weinhold }
258*4535495dSIngo Weinhold 
259*4535495dSIngo Weinhold 
260*4535495dSIngo Weinhold #define SET_BIT(field, bit) field[(bit) >> 3] |= 1 << ((bit) & 7)
261*4535495dSIngo Weinhold 
262*4535495dSIngo Weinhold static status_t
263*4535495dSIngo Weinhold scsi_init_device(device_node *node, void **cookie)
264*4535495dSIngo Weinhold {
265*4535495dSIngo Weinhold 	const scsi_res_inquiry *inquiry_data = NULL;
266*4535495dSIngo Weinhold 	uint8 target_id, target_lun, path_id;
267*4535495dSIngo Weinhold 	scsi_bus_info *bus;
268*4535495dSIngo Weinhold 	scsi_device_info *device;
269*4535495dSIngo Weinhold 	status_t res;
270*4535495dSIngo Weinhold 	size_t inquiry_data_len;
271*4535495dSIngo Weinhold 	uint8 is_atapi, manual_autosense;
272*4535495dSIngo Weinhold 
273*4535495dSIngo Weinhold 	SHOW_FLOW0(3, "");
274*4535495dSIngo Weinhold 
275*4535495dSIngo Weinhold 	if (pnp->get_attr_uint8( node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, false) != B_OK
276*4535495dSIngo Weinhold 		|| pnp->get_attr_uint8( node, SCSI_DEVICE_TARGET_LUN_ITEM, &target_lun, false) != B_OK
277*4535495dSIngo Weinhold 		|| pnp->get_attr_uint8( node, SCSI_DEVICE_IS_ATAPI_ITEM, &is_atapi, false) != B_OK
278*4535495dSIngo Weinhold 		|| pnp->get_attr_uint8( node, SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM, &manual_autosense, false) != B_OK
279*4535495dSIngo Weinhold 		|| pnp->get_attr_raw( node, SCSI_DEVICE_INQUIRY_ITEM,
280*4535495dSIngo Weinhold 				(const void **)&inquiry_data, &inquiry_data_len, false) != B_OK
281*4535495dSIngo Weinhold 		|| inquiry_data_len != sizeof(*inquiry_data)) {
282*4535495dSIngo Weinhold 		return B_ERROR;
283*4535495dSIngo Weinhold 	}
284*4535495dSIngo Weinhold 
285*4535495dSIngo Weinhold 	{
286*4535495dSIngo Weinhold 		device_node *parent = pnp->get_parent_node(node);
287*4535495dSIngo Weinhold 		pnp->get_driver(parent, NULL, (void **)&bus);
288*4535495dSIngo Weinhold 		pnp->put_node(parent);
289*4535495dSIngo Weinhold 	}
290*4535495dSIngo Weinhold 
291*4535495dSIngo Weinhold 	device = scsi_create_device(node, bus, target_id, target_lun);
292*4535495dSIngo Weinhold 	if (device == NULL)
293*4535495dSIngo Weinhold 		return B_NO_MEMORY;
294*4535495dSIngo Weinhold 
295*4535495dSIngo Weinhold 	// never mind if there is no path - it might be an emulated controller
296*4535495dSIngo Weinhold 	path_id = (uint8)-1;
297*4535495dSIngo Weinhold 
298*4535495dSIngo Weinhold 	pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true);
299*4535495dSIngo Weinhold 
300*4535495dSIngo Weinhold 	device->inquiry_data = *inquiry_data;
301*4535495dSIngo Weinhold 
302*4535495dSIngo Weinhold 	// save restrictions
303*4535495dSIngo Weinhold 	device->is_atapi = is_atapi;
304*4535495dSIngo Weinhold 	device->manual_autosense = manual_autosense;
305*4535495dSIngo Weinhold 
306*4535495dSIngo Weinhold 	// size of device queue must be detected by trial and error, so
307*4535495dSIngo Weinhold 	// we start with a really high number and see when the device chokes
308*4535495dSIngo Weinhold 	device->total_slots = 4096;
309*4535495dSIngo Weinhold 
310*4535495dSIngo Weinhold 	// disable queuing if bus doesn't support it
311*4535495dSIngo Weinhold 	if ((bus->inquiry_data.hba_inquiry & SCSI_PI_TAG_ABLE) == 0)
312*4535495dSIngo Weinhold 		device->total_slots = 1;
313*4535495dSIngo Weinhold 
314*4535495dSIngo Weinhold 	// if there is no autosense, disable queuing to make sure autosense is
315*4535495dSIngo Weinhold 	// not overtaken by other requests
316*4535495dSIngo Weinhold 	if (device->manual_autosense)
317*4535495dSIngo Weinhold 		device->total_slots = 1;
318*4535495dSIngo Weinhold 
319*4535495dSIngo Weinhold 	device->left_slots = device->total_slots;
320*4535495dSIngo Weinhold 
321*4535495dSIngo Weinhold 	// get autosense request if required
322*4535495dSIngo Weinhold 	if (device->manual_autosense) {
323*4535495dSIngo Weinhold 		if (scsi_create_autosense_request(device) != B_OK) {
324*4535495dSIngo Weinhold 			res = B_NO_MEMORY;
325*4535495dSIngo Weinhold 			goto err;
326*4535495dSIngo Weinhold 		}
327*4535495dSIngo Weinhold 	}
328*4535495dSIngo Weinhold 
329*4535495dSIngo Weinhold 	// if this is an ATAPI device, we need an emulation buffer
330*4535495dSIngo Weinhold 	if (scsi_init_emulation_buffer(device, SCSI_ATAPI_BUFFER_SIZE) != B_OK) {
331*4535495dSIngo Weinhold 		res = B_NO_MEMORY;
332*4535495dSIngo Weinhold 		goto err;
333*4535495dSIngo Weinhold 	}
334*4535495dSIngo Weinhold 
335*4535495dSIngo Weinhold 	memset(device->emulation_map, 0, sizeof(device->emulation_map));
336*4535495dSIngo Weinhold 
337*4535495dSIngo Weinhold 	if (device->is_atapi) {
338*4535495dSIngo Weinhold 		SET_BIT(device->emulation_map, SCSI_OP_READ_6);
339*4535495dSIngo Weinhold 		SET_BIT(device->emulation_map, SCSI_OP_WRITE_6);
340*4535495dSIngo Weinhold 		SET_BIT(device->emulation_map, SCSI_OP_MODE_SENSE_6);
341*4535495dSIngo Weinhold 		SET_BIT(device->emulation_map, SCSI_OP_MODE_SELECT_6);
342*4535495dSIngo Weinhold 		SET_BIT(device->emulation_map, SCSI_OP_INQUIRY);
343*4535495dSIngo Weinhold 	}
344*4535495dSIngo Weinhold 
345*4535495dSIngo Weinhold 	*cookie = device;
346*4535495dSIngo Weinhold 	return B_OK;
347*4535495dSIngo Weinhold 
348*4535495dSIngo Weinhold err:
349*4535495dSIngo Weinhold 	scsi_free_device(device);
350*4535495dSIngo Weinhold 	return res;
351*4535495dSIngo Weinhold }
352*4535495dSIngo Weinhold 
353*4535495dSIngo Weinhold 
354*4535495dSIngo Weinhold static void
355*4535495dSIngo Weinhold scsi_uninit_device(scsi_device_info *device)
356*4535495dSIngo Weinhold {
357*4535495dSIngo Weinhold 	SHOW_FLOW0(3, "");
358*4535495dSIngo Weinhold 
359*4535495dSIngo Weinhold 	scsi_free_device(device);
360*4535495dSIngo Weinhold }
361*4535495dSIngo Weinhold 
362*4535495dSIngo Weinhold 
363*4535495dSIngo Weinhold static void
364*4535495dSIngo Weinhold scsi_device_removed(scsi_device_info *device)
365*4535495dSIngo Weinhold {
366*4535495dSIngo Weinhold 	SHOW_FLOW0(3, "");
367*4535495dSIngo Weinhold 
368*4535495dSIngo Weinhold 	if (device == NULL)
369*4535495dSIngo Weinhold 		return;
370*4535495dSIngo Weinhold 
371*4535495dSIngo Weinhold 	// this must be atomic as no lock is used
372*4535495dSIngo Weinhold 	device->valid = false;
373*4535495dSIngo Weinhold }
374*4535495dSIngo Weinhold 
375*4535495dSIngo Weinhold 
376*4535495dSIngo Weinhold /**	get device info; create a temporary one if it's not registered
377*4535495dSIngo Weinhold  *	(used during detection)
378*4535495dSIngo Weinhold  *	on success, scan_lun_lock of bus is hold
379*4535495dSIngo Weinhold  */
380*4535495dSIngo Weinhold 
381*4535495dSIngo Weinhold status_t
382*4535495dSIngo Weinhold scsi_force_get_device(scsi_bus_info *bus, uchar target_id,
383*4535495dSIngo Weinhold 	uchar target_lun, scsi_device_info **res_device)
384*4535495dSIngo Weinhold {
385*4535495dSIngo Weinhold 	device_attr attrs[] = {
386*4535495dSIngo Weinhold 		{ SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }},
387*4535495dSIngo Weinhold 		{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
388*4535495dSIngo Weinhold 		{ NULL }
389*4535495dSIngo Weinhold 	};
390*4535495dSIngo Weinhold 	device_node *node;
391*4535495dSIngo Weinhold 	status_t res;
392*4535495dSIngo Weinhold 	driver_module_info *driver_interface;
393*4535495dSIngo Weinhold 	scsi_device device;
394*4535495dSIngo Weinhold 
395*4535495dSIngo Weinhold 	SHOW_FLOW0(3, "");
396*4535495dSIngo Weinhold 
397*4535495dSIngo Weinhold 	// very important: only one can use a forced device to avoid double detection
398*4535495dSIngo Weinhold 	acquire_sem(bus->scan_lun_lock);
399*4535495dSIngo Weinhold 
400*4535495dSIngo Weinhold 	// check whether device registered already
401*4535495dSIngo Weinhold 	node = NULL;
402*4535495dSIngo Weinhold 	pnp->get_next_child_node(bus->node, attrs, &node);
403*4535495dSIngo Weinhold 
404*4535495dSIngo Weinhold 	SHOW_FLOW(3, "%p", node);
405*4535495dSIngo Weinhold 
406*4535495dSIngo Weinhold 	if (node != NULL) {
407*4535495dSIngo Weinhold 		// TODO: have a second look a this one!
408*4535495dSIngo Weinhold 		// there is one - get it
409*4535495dSIngo Weinhold 		res = pnp->get_driver(node, &driver_interface, (void **)&device);
410*4535495dSIngo Weinhold 		if (res != B_OK)
411*4535495dSIngo Weinhold 			pnp->put_node(node);
412*4535495dSIngo Weinhold 	} else {
413*4535495dSIngo Weinhold 		// device doesn't exist yet - create a temporary one
414*4535495dSIngo Weinhold 		device = scsi_create_device(NULL, bus, target_id, target_lun);
415*4535495dSIngo Weinhold 		if (device == NULL)
416*4535495dSIngo Weinhold 			res = B_NO_MEMORY;
417*4535495dSIngo Weinhold 		else
418*4535495dSIngo Weinhold 			res = B_OK;
419*4535495dSIngo Weinhold 	}
420*4535495dSIngo Weinhold 
421*4535495dSIngo Weinhold 	*res_device = device;
422*4535495dSIngo Weinhold 
423*4535495dSIngo Weinhold 	if (res != B_OK)
424*4535495dSIngo Weinhold 		release_sem(bus->scan_lun_lock);
425*4535495dSIngo Weinhold 
426*4535495dSIngo Weinhold 	return res;
427*4535495dSIngo Weinhold }
428*4535495dSIngo Weinhold 
429*4535495dSIngo Weinhold 
430*4535495dSIngo Weinhold /**	cleanup device received from scsi_force_get_device
431*4535495dSIngo Weinhold  *	on return, scan_lun_lock of bus is released
432*4535495dSIngo Weinhold  */
433*4535495dSIngo Weinhold 
434*4535495dSIngo Weinhold void
435*4535495dSIngo Weinhold scsi_put_forced_device(scsi_device_info *device)
436*4535495dSIngo Weinhold {
437*4535495dSIngo Weinhold 	scsi_bus_info *bus = device->bus;
438*4535495dSIngo Weinhold 
439*4535495dSIngo Weinhold 	SHOW_FLOW0(3, "");
440*4535495dSIngo Weinhold 
441*4535495dSIngo Weinhold 	if (device->node != NULL) {
442*4535495dSIngo Weinhold 		// device is registered
443*4535495dSIngo Weinhold 		pnp->put_node(device->node);
444*4535495dSIngo Weinhold 	} else {
445*4535495dSIngo Weinhold 		// device is temporary
446*4535495dSIngo Weinhold 		scsi_free_device(device);
447*4535495dSIngo Weinhold 	}
448*4535495dSIngo Weinhold 
449*4535495dSIngo Weinhold 	release_sem(bus->scan_lun_lock);
450*4535495dSIngo Weinhold }
451*4535495dSIngo Weinhold 
452*4535495dSIngo Weinhold 
453*4535495dSIngo Weinhold static uchar
454*4535495dSIngo Weinhold scsi_reset_device(scsi_device_info *device)
455*4535495dSIngo Weinhold {
456*4535495dSIngo Weinhold 	SHOW_FLOW0(3, "");
457*4535495dSIngo Weinhold 
458*4535495dSIngo Weinhold 	if (device->node == NULL)
459*4535495dSIngo Weinhold 		return SCSI_DEV_NOT_THERE;
460*4535495dSIngo Weinhold 
461*4535495dSIngo Weinhold 	return device->bus->interface->reset_device(device->bus->sim_cookie,
462*4535495dSIngo Weinhold 		device->target_id, device->target_lun);
463*4535495dSIngo Weinhold }
464*4535495dSIngo Weinhold 
465*4535495dSIngo Weinhold 
466*4535495dSIngo Weinhold static status_t
467*4535495dSIngo Weinhold scsi_ioctl(scsi_device_info *device, uint32 op, void *buffer, size_t length)
468*4535495dSIngo Weinhold {
469*4535495dSIngo Weinhold 	if (device->bus->interface->ioctl != NULL) {
470*4535495dSIngo Weinhold 		return device->bus->interface->ioctl(device->bus->sim_cookie,
471*4535495dSIngo Weinhold 			device->target_id, op, buffer, length);
472*4535495dSIngo Weinhold 	}
473*4535495dSIngo Weinhold 
474*4535495dSIngo Weinhold 	return B_BAD_VALUE;
475*4535495dSIngo Weinhold }
476*4535495dSIngo Weinhold 
477*4535495dSIngo Weinhold 
478*4535495dSIngo Weinhold static status_t
479*4535495dSIngo Weinhold std_ops(int32 op, ...)
480*4535495dSIngo Weinhold {
481*4535495dSIngo Weinhold 	switch (op) {
482*4535495dSIngo Weinhold 		case B_MODULE_INIT:
483*4535495dSIngo Weinhold 		{
484*4535495dSIngo Weinhold 			// Link to SCSI bus.
485*4535495dSIngo Weinhold 			// SCSI device driver must have SCSI bus loaded, but it calls its functions
486*4535495dSIngo Weinhold 			// directly instead via official interface, so this pointer is never read.
487*4535495dSIngo Weinhold 			module_info *dummy;
488*4535495dSIngo Weinhold 			return get_module(SCSI_BUS_MODULE_NAME, &dummy);
489*4535495dSIngo Weinhold 		}
490*4535495dSIngo Weinhold 		case B_MODULE_UNINIT:
491*4535495dSIngo Weinhold 			return put_module(SCSI_BUS_MODULE_NAME);
492*4535495dSIngo Weinhold 
493*4535495dSIngo Weinhold 		default:
494*4535495dSIngo Weinhold 			return B_ERROR;
495*4535495dSIngo Weinhold 	}
496*4535495dSIngo Weinhold }
497*4535495dSIngo Weinhold 
498*4535495dSIngo Weinhold 
499*4535495dSIngo Weinhold scsi_device_interface scsi_device_module = {
500*4535495dSIngo Weinhold 	{
501*4535495dSIngo Weinhold 		{
502*4535495dSIngo Weinhold 			SCSI_DEVICE_MODULE_NAME,
503*4535495dSIngo Weinhold 			0,
504*4535495dSIngo Weinhold 			std_ops
505*4535495dSIngo Weinhold 		},
506*4535495dSIngo Weinhold 
507*4535495dSIngo Weinhold 		NULL,	// supported devices
508*4535495dSIngo Weinhold 		NULL,	// register node
509*4535495dSIngo Weinhold 		scsi_init_device,
510*4535495dSIngo Weinhold 		(void (*)(void *)) scsi_uninit_device,
511*4535495dSIngo Weinhold 		NULL,	// register child devices
512*4535495dSIngo Weinhold 		NULL,	// rescan
513*4535495dSIngo Weinhold 		(void (*)(void *)) scsi_device_removed
514*4535495dSIngo Weinhold 	},
515*4535495dSIngo Weinhold 
516*4535495dSIngo Weinhold 	scsi_alloc_ccb,
517*4535495dSIngo Weinhold 	scsi_free_ccb,
518*4535495dSIngo Weinhold 
519*4535495dSIngo Weinhold 	scsi_async_io,
520*4535495dSIngo Weinhold 	scsi_sync_io,
521*4535495dSIngo Weinhold 	scsi_abort,
522*4535495dSIngo Weinhold 	scsi_reset_device,
523*4535495dSIngo Weinhold 	scsi_term_io,
524*4535495dSIngo Weinhold 	scsi_ioctl,
525*4535495dSIngo Weinhold };
526