xref: /haiku/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp (revision 7eab6b486ebadb54ca3c306601f4b04dd92359fa)
1 /*
2  * Copyright 2008-2023, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  *		Augustin Cavalier <waddlesplash>
8  */
9 
10 
11 #include "usb_disk.h"
12 
13 #include <ByteOrder.h>
14 #include <StackOrHeapArray.h>
15 #include <Drivers.h>
16 #include <bus/USB.h>
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #include <kernel.h>
23 #include <fs/devfs.h>
24 #include <syscall_restart.h>
25 #include <util/AutoLock.h>
26 
27 #include "IORequest.h"
28 
29 #include "scsi_sense.h"
30 #include "usb_disk_scsi.h"
31 #include "icons.h"
32 
33 
34 #define MAX_IO_BLOCKS					(128)
35 
36 #define USB_DISK_DEVICE_MODULE_NAME		"drivers/disk/usb_disk/device_v1"
37 #define USB_DISK_DRIVER_MODULE_NAME		"drivers/disk/usb_disk/driver_v1"
38 #define USB_DISK_DEVICE_ID_GENERATOR	"usb_disk/device_id"
39 
40 #define DRIVER_NAME			"usb_disk"
41 #define DEVICE_NAME_BASE	"disk/usb/"
42 #define DEVICE_NAME			DEVICE_NAME_BASE "%" B_PRIu32 "/%d/raw"
43 
44 
45 //#define TRACE_USB_DISK
46 #ifdef TRACE_USB_DISK
47 #define TRACE(x...)			dprintf(DRIVER_NAME ": " x)
48 #define TRACE_ALWAYS(x...)	dprintf(DRIVER_NAME ": " x)
49 #define CALLED() 			TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
50 #else
51 #define TRACE(x...)			/* nothing */
52 #define CALLED()
53 #define TRACE_ALWAYS(x...)	dprintf(DRIVER_NAME ": " x)
54 #endif
55 
56 
57 device_manager_info *gDeviceManager;
58 static usb_module_info *gUSBModule = NULL;
59 
60 struct {
61 	const char *vendor;
62 	const char *product;
63 	device_icon *icon;
64 	const char *name;
65 } kIconMatches[] = {
66 	// matches for Hama USB 2.0 Card Reader 35 in 1
67 	// vendor: "Transcend Information, Inc."
68 	// product: "63-in-1 Multi-Card Reader/Writer" ver. 0100
69 	// which report things like "Generic " "USB  CF Reader  "
70 //	{ NULL, " CF Reader", &kCFIconData, "devices/drive-removable-media-flash" },
71 	{ NULL, " SD Reader", &kSDIconData, "devices/drive-removable-media-flash" },
72 	{ NULL, " MS Reader", &kMSIconData, "devices/drive-removable-media-flash" },
73 //	{ NULL, " SM Reader", &kSMIconData, "devices/drive-removable-media-flash" },
74 	// match for my Kazam mobile phone
75 	// stupid thing says "MEDIATEK" " FLASH DISK     " even for internal memory
76 	{ "MEDIATEK", NULL, &kMobileIconData,
77 		"devices/drive-removable-media-flash" },
78 	{ NULL, NULL, NULL, NULL }
79 };
80 
81 
82 //
83 //#pragma mark - Forward Declarations
84 //
85 
86 
87 static void	usb_disk_callback(void *cookie, status_t status, void *data,
88 				size_t actualLength);
89 
90 uint8		usb_disk_get_max_lun(disk_device *device);
91 void		usb_disk_reset_recovery(disk_device *device);
92 status_t	usb_disk_receive_csw(disk_device *device,
93 				usb_massbulk_command_status_wrapper *status);
94 
95 status_t	usb_disk_send_diagnostic(device_lun *lun);
96 status_t	usb_disk_request_sense(device_lun *lun, err_act *action);
97 status_t	usb_disk_mode_sense(device_lun *lun);
98 status_t	usb_disk_test_unit_ready(device_lun *lun, err_act *action = NULL);
99 status_t	usb_disk_inquiry(device_lun *lun);
100 status_t	usb_disk_reset_capacity(device_lun *lun);
101 status_t	usb_disk_update_capacity(device_lun *lun);
102 status_t	usb_disk_synchronize(device_lun *lun, bool force);
103 
104 
105 // #pragma mark - disk_device helper functions
106 
107 
108 disk_device_s::disk_device_s()
109 	:
110 	notify(-1),
111 	interruptLock(-1)
112 {
113 	recursive_lock_init(&io_lock, "usb_disk i/o lock");
114 	mutex_init(&lock, "usb_disk device lock");
115 }
116 
117 
118 disk_device_s::~disk_device_s()
119 {
120 	recursive_lock_destroy(&io_lock);
121 	mutex_destroy(&lock);
122 
123 	if (notify >= 0)
124 		delete_sem(notify);
125 	if (interruptLock >= 0)
126 		delete_sem(interruptLock);
127 }
128 
129 
130 static DMAResource*
131 get_dma_resource(disk_device *device, uint32 blockSize)
132 {
133 	for (int32 i = 0; i < device->dma_resources.Count(); i++) {
134 		DMAResource* r = device->dma_resources[i];
135 		if (r->BlockSize() == blockSize)
136 			return r;
137 	}
138 	return NULL;
139 }
140 
141 
142 void
143 usb_disk_free_device_and_luns(disk_device *device)
144 {
145 	ASSERT_LOCKED_MUTEX(&device->lock);
146 
147 	for (int32 i = 0; i < device->dma_resources.Count(); i++)
148 		delete device->dma_resources[i];
149 	for (uint8 i = 0; i < device->lun_count; i++)
150 		free(device->luns[i]);
151 	free(device->luns);
152 	delete device;
153 }
154 
155 
156 //
157 //#pragma mark - Bulk-only Mass Storage Functions
158 //
159 
160 
161 static status_t
162 usb_disk_mass_storage_reset(disk_device *device)
163 {
164 	return gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_OUT
165 		| USB_REQTYPE_CLASS, USB_MASSBULK_REQUEST_MASS_STORAGE_RESET, 0x0000,
166 		device->interface, 0, NULL, NULL);
167 }
168 
169 
170 uint8
171 usb_disk_get_max_lun(disk_device *device)
172 {
173 	ASSERT_LOCKED_RECURSIVE(&device->io_lock);
174 
175 	uint8 result = 0;
176 	size_t actualLength = 0;
177 
178 	// devices that do not support multiple LUNs may stall this request
179 	if (gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_IN
180 		| USB_REQTYPE_CLASS, USB_MASSBULK_REQUEST_GET_MAX_LUN, 0x0000,
181 		device->interface, 1, &result, &actualLength) != B_OK
182 			|| actualLength != 1) {
183 		return 0;
184 	}
185 
186 	if (result > MAX_LOGICAL_UNIT_NUMBER) {
187 		// invalid max lun
188 		return 0;
189 	}
190 
191 	return result;
192 }
193 
194 
195 static void
196 usb_disk_clear_halt(usb_pipe pipe)
197 {
198 	gUSBModule->cancel_queued_transfers(pipe);
199 	gUSBModule->clear_feature(pipe, USB_FEATURE_ENDPOINT_HALT);
200 }
201 
202 
203 void
204 usb_disk_reset_recovery(disk_device *device, err_act *_action)
205 {
206 	TRACE("reset recovery\n");
207 	ASSERT_LOCKED_RECURSIVE(&device->io_lock);
208 
209 	usb_disk_mass_storage_reset(device);
210 	usb_disk_clear_halt(device->bulk_in);
211 	usb_disk_clear_halt(device->bulk_out);
212 	if (device->is_ufi)
213 		usb_disk_clear_halt(device->interrupt);
214 
215 	if (_action != NULL)
216 		*_action = err_act_retry;
217 }
218 
219 
220 struct transfer_data {
221 	union {
222 		physical_entry* phys_vecs;
223 		iovec* vecs;
224 	};
225 	uint32 vec_count = 0;
226 	bool physical = false;
227 };
228 
229 
230 static status_t
231 usb_disk_transfer_data(disk_device *device, bool directionIn, const transfer_data& data)
232 {
233 	status_t result;
234 	if (data.physical) {
235 		result = gUSBModule->queue_bulk_v_physical(
236 			directionIn ? device->bulk_in : device->bulk_out,
237 			data.phys_vecs, data.vec_count, usb_disk_callback, device);
238 	} else {
239 		result = gUSBModule->queue_bulk_v(
240 			directionIn ? device->bulk_in : device->bulk_out,
241 			data.vecs, data.vec_count, usb_disk_callback, device);
242 	}
243 	if (result != B_OK) {
244 		TRACE_ALWAYS("failed to queue data transfer: %s\n", strerror(result));
245 		return result;
246 	}
247 
248 	mutex_unlock(&device->lock);
249 	do {
250 		result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT,
251 			10 * 1000 * 1000);
252 		if (result == B_TIMED_OUT) {
253 			// Cancel the transfer and collect the sem that should now be
254 			// released through the callback on cancel. Handling of device
255 			// reset is done in usb_disk_operation() when it detects that
256 			// the transfer failed.
257 			gUSBModule->cancel_queued_transfers(directionIn ? device->bulk_in
258 				: device->bulk_out);
259 			acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 0);
260 		}
261 	} while (result == B_INTERRUPTED);
262 	mutex_lock(&device->lock);
263 
264 	if (result != B_OK) {
265 		TRACE_ALWAYS("acquire_sem failed while waiting for data transfer: %s\n",
266 			strerror(result));
267 		return result;
268 	}
269 
270 	return B_OK;
271 }
272 
273 
274 static status_t
275 usb_disk_transfer_data(disk_device *device, bool directionIn,
276 	void* buffer, size_t dataLength)
277 {
278 	iovec vec;
279 	vec.iov_base = buffer;
280 	vec.iov_len = dataLength;
281 
282 	struct transfer_data data;
283 	data.vecs = &vec;
284 	data.vec_count = 1;
285 
286 	return usb_disk_transfer_data(device, directionIn, data);
287 }
288 
289 
290 static void
291 callback_interrupt(void* cookie, int32 status, void* data, size_t length)
292 {
293 	disk_device* device = (disk_device*)cookie;
294 	// We release the lock even if the interrupt is invalid. This way there
295 	// is at least a chance for the driver to terminate properly.
296 	release_sem(device->interruptLock);
297 
298 	if (length != 2) {
299 		TRACE_ALWAYS("interrupt of length %" B_PRIuSIZE "! (expected 2)\n",
300 			length);
301 		// In this case we do not reschedule the interrupt. This means the
302 		// driver will be locked. The interrupt should perhaps be scheduled
303 		// when starting a transfer instead. But getting there means something
304 		// is really broken, so...
305 		return;
306 	}
307 
308 	// Reschedule the interrupt for next time
309 	gUSBModule->queue_interrupt(device->interrupt, device->interruptBuffer, 2,
310 		callback_interrupt, cookie);
311 }
312 
313 
314 static status_t
315 receive_csw_interrupt(disk_device *device,
316 	interrupt_status_wrapper *status)
317 {
318 	TRACE("Waiting for result...\n");
319 
320 	gUSBModule->queue_interrupt(device->interrupt,
321 			device->interruptBuffer, 2, callback_interrupt, device);
322 
323 	acquire_sem(device->interruptLock);
324 
325 	status->status = device->interruptBuffer[0];
326 	status->misc = device->interruptBuffer[1];
327 
328 	return B_OK;
329 }
330 
331 
332 static status_t
333 receive_csw_bulk(disk_device *device,
334 	usb_massbulk_command_status_wrapper *status)
335 {
336 	status_t result = usb_disk_transfer_data(device, true, status,
337 		sizeof(usb_massbulk_command_status_wrapper));
338 	if (result != B_OK)
339 		return result;
340 
341 	if (device->status != B_OK
342 			|| device->actual_length
343 			!= sizeof(usb_massbulk_command_status_wrapper)) {
344 		// receiving the command status wrapper failed
345 		return B_ERROR;
346 	}
347 
348 	return B_OK;
349 }
350 
351 
352 status_t
353 usb_disk_operation_interrupt(device_lun *lun, uint8* operation,
354 	const transfer_data& data, size_t *dataLength,
355 	bool directionIn, err_act *_action)
356 {
357 	TRACE("operation: lun: %u; op: 0x%x; data: %p; dlen: %p (%lu); in: %c\n",
358 		lun->logical_unit_number, operation[0], data.vecs, dataLength,
359 		dataLength ? *dataLength : 0, directionIn ? 'y' : 'n');
360 	ASSERT_LOCKED_RECURSIVE(&lun->device->io_lock);
361 
362 	disk_device* device = lun->device;
363 
364 	// Step 1 : send the SCSI operation as a class specific request
365 	size_t actualLength = 12;
366 	status_t result = gUSBModule->send_request(device->device,
367 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, 0 /*request*/,
368 		0/*value*/, device->interface/*index*/, 12, operation, &actualLength);
369 
370 	if (result != B_OK || actualLength != 12) {
371 		TRACE("Command stage: wrote %ld bytes (error: %s)\n",
372 			actualLength, strerror(result));
373 
374 		// There was an error, we have to do a request sense to reset the device
375 		if (operation[0] != SCSI_REQUEST_SENSE_6) {
376 			usb_disk_request_sense(lun, _action);
377 		}
378 		return result;
379 	}
380 
381 	// Step 2 : data phase : send or receive data
382 	size_t transferedData = 0;
383 	if (data.vec_count != 0) {
384 		// we have data to transfer in a data stage
385 		result = usb_disk_transfer_data(device, directionIn, data);
386 		if (result != B_OK) {
387 			TRACE("Error %s in data phase\n", strerror(result));
388 			return result;
389 		}
390 
391 		transferedData = device->actual_length;
392 		if (device->status != B_OK || transferedData != *dataLength) {
393 			// sending or receiving of the data failed
394 			if (device->status == B_DEV_STALLED) {
395 				TRACE("stall while transfering data\n");
396 				usb_disk_clear_halt(directionIn ? device->bulk_in : device->bulk_out);
397 			} else {
398 				TRACE_ALWAYS("sending or receiving of the data failed\n");
399 				usb_disk_reset_recovery(device, _action);
400 				return B_IO_ERROR;
401 			}
402 		}
403 	}
404 
405 	// step 3 : wait for the device to send the interrupt ACK
406 	if (operation[0] != SCSI_REQUEST_SENSE_6) {
407 		interrupt_status_wrapper status;
408 		result =  receive_csw_interrupt(device, &status);
409 		if (result != B_OK) {
410 			// in case of a stall or error clear the stall and try again
411 			TRACE("Error receiving interrupt: %s. Retrying...\n",
412 				strerror(result));
413 			usb_disk_clear_halt(device->bulk_in);
414 			result = receive_csw_interrupt(device, &status);
415 		}
416 
417 		if (result != B_OK) {
418 			TRACE_ALWAYS("receiving the command status interrupt failed\n");
419 			usb_disk_reset_recovery(device, _action);
420 			return result;
421 		}
422 
423 		// wait for the device to finish the operation.
424 		result = usb_disk_request_sense(lun, _action);
425 	}
426 	return result;
427 }
428 
429 
430 status_t
431 usb_disk_operation_bulk(device_lun *lun, uint8 *operation, size_t operationLength,
432 	const transfer_data& data, size_t *dataLength,
433 	bool directionIn, err_act *_action)
434 {
435 	TRACE("operation: lun: %u; op: %u; data: %p; dlen: %p (%lu); in: %c\n",
436 		lun->logical_unit_number, operation[0],
437 		data.vecs, dataLength, dataLength ? *dataLength : 0,
438 		directionIn ? 'y' : 'n');
439 	ASSERT_LOCKED_RECURSIVE(&lun->device->io_lock);
440 
441 	disk_device *device = lun->device;
442 	usb_massbulk_command_block_wrapper command;
443 	command.signature = USB_MASSBULK_CBW_SIGNATURE;
444 	command.tag = device->current_tag++;
445 	command.data_transfer_length = (dataLength != NULL ? *dataLength : 0);
446 	command.flags = (directionIn ? USB_MASSBULK_CBW_DATA_INPUT
447 		: USB_MASSBULK_CBW_DATA_OUTPUT);
448 	command.lun = lun->logical_unit_number;
449 	command.command_block_length
450 		= device->is_atapi ? ATAPI_COMMAND_LENGTH : operationLength;
451 	memset(command.command_block, 0, sizeof(command.command_block));
452 	memcpy(command.command_block, operation, operationLength);
453 
454 	status_t result = usb_disk_transfer_data(device, false, &command,
455 		sizeof(usb_massbulk_command_block_wrapper));
456 	if (result != B_OK)
457 		return result;
458 
459 	if (device->status != B_OK ||
460 		device->actual_length != sizeof(usb_massbulk_command_block_wrapper)) {
461 		// sending the command block wrapper failed
462 		TRACE_ALWAYS("sending the command block wrapper failed: %s\n",
463 			strerror(device->status));
464 		usb_disk_reset_recovery(device, _action);
465 		return B_IO_ERROR;
466 	}
467 
468 	size_t transferedData = 0;
469 	if (data.vec_count != 0) {
470 		// we have data to transfer in a data stage
471 		result = usb_disk_transfer_data(device, directionIn, data);
472 		if (result != B_OK)
473 			return result;
474 
475 		transferedData = device->actual_length;
476 		if (device->status != B_OK || transferedData != *dataLength) {
477 			// sending or receiving of the data failed
478 			if (device->status == B_DEV_STALLED) {
479 				TRACE("stall while transfering data\n");
480 				usb_disk_clear_halt(directionIn ? device->bulk_in : device->bulk_out);
481 			} else {
482 				TRACE_ALWAYS("sending or receiving of the data failed: %s\n",
483 					strerror(device->status));
484 				usb_disk_reset_recovery(device, _action);
485 				return B_IO_ERROR;
486 			}
487 		}
488 	}
489 
490 	usb_massbulk_command_status_wrapper status;
491 	result =  receive_csw_bulk(device, &status);
492 	if (result != B_OK) {
493 		// in case of a stall or error clear the stall and try again
494 		usb_disk_clear_halt(device->bulk_in);
495 		result = receive_csw_bulk(device, &status);
496 	}
497 
498 	if (result != B_OK) {
499 		TRACE_ALWAYS("receiving the command status wrapper failed: %s\n",
500 			strerror(result));
501 		usb_disk_reset_recovery(device, _action);
502 		return result;
503 	}
504 
505 	if (status.signature != USB_MASSBULK_CSW_SIGNATURE
506 		|| status.tag != command.tag) {
507 		// the command status wrapper is not valid
508 		TRACE_ALWAYS("command status wrapper is not valid: %#" B_PRIx32 "\n",
509 			status.signature);
510 		usb_disk_reset_recovery(device, _action);
511 		return B_ERROR;
512 	}
513 
514 	switch (status.status) {
515 		case USB_MASSBULK_CSW_STATUS_COMMAND_PASSED:
516 		case USB_MASSBULK_CSW_STATUS_COMMAND_FAILED:
517 		{
518 			// The residue from "status.data_residue" is not maintained
519 			// correctly by some devices, so calculate it instead.
520 			uint32 residue = command.data_transfer_length - transferedData;
521 
522 			if (dataLength != NULL) {
523 				*dataLength -= residue;
524 				if (transferedData < *dataLength) {
525 					TRACE_ALWAYS("less data transfered than indicated: %"
526 						B_PRIuSIZE " vs. %" B_PRIuSIZE "\n", transferedData,
527 						*dataLength);
528 					*dataLength = transferedData;
529 				}
530 			}
531 
532 			if (status.status == USB_MASSBULK_CSW_STATUS_COMMAND_PASSED) {
533 				// the operation is complete and has succeeded
534 				return B_OK;
535 			} else {
536 				if (operation[0] == SCSI_REQUEST_SENSE_6)
537 					return B_ERROR;
538 
539 				// the operation is complete but has failed at the SCSI level
540 				if (operation[0] != SCSI_TEST_UNIT_READY_6) {
541 					TRACE_ALWAYS("operation %#" B_PRIx8
542 						" failed at the SCSI level\n", operation[0]);
543 				}
544 
545 				result = usb_disk_request_sense(lun, _action);
546 				return result == B_OK ? B_ERROR : result;
547 			}
548 		}
549 
550 		case USB_MASSBULK_CSW_STATUS_PHASE_ERROR:
551 		{
552 			// a protocol or device error occured
553 			TRACE_ALWAYS("phase error in operation %#" B_PRIx8 "\n",
554 				operation[0]);
555 			usb_disk_reset_recovery(device, _action);
556 			return B_ERROR;
557 		}
558 
559 		default:
560 		{
561 			// command status wrapper is not meaningful
562 			TRACE_ALWAYS("command status wrapper has invalid status\n");
563 			usb_disk_reset_recovery(device, _action);
564 			return B_ERROR;
565 		}
566 	}
567 }
568 
569 
570 static status_t
571 usb_disk_operation(device_lun *lun, uint8* operation, size_t opLength,
572 	const transfer_data& data, size_t *dataLength,
573 	bool directionIn, err_act *_action = NULL)
574 {
575 	if (lun->device->is_ufi) {
576 		return usb_disk_operation_interrupt(lun, operation,
577 			data, dataLength, directionIn, _action);
578 	} else {
579 		return usb_disk_operation_bulk(lun, operation, opLength,
580 			data, dataLength, directionIn, _action);
581 	}
582 }
583 
584 
585 static status_t
586 usb_disk_operation(device_lun *lun, uint8* operation, size_t opLength,
587 	void *buffer, size_t *dataLength,
588 	bool directionIn, err_act *_action = NULL)
589 {
590 	iovec vec;
591 	vec.iov_base = buffer;
592 
593 	struct transfer_data data;
594 	data.vecs = &vec;
595 
596 	if (dataLength != NULL && *dataLength != 0) {
597 		vec.iov_len = *dataLength;
598 		data.vec_count = 1;
599 	} else {
600 		vec.iov_len = 0;
601 		data.vec_count = 0;
602 	}
603 
604 	return usb_disk_operation(lun, operation, opLength,
605 		data, dataLength, directionIn, _action);
606 }
607 
608 
609 //
610 //#pragma mark - Helper/Convenience Functions
611 //
612 
613 
614 status_t
615 usb_disk_send_diagnostic(device_lun *lun)
616 {
617 	uint8 commandBlock[12];
618 	memset(commandBlock, 0, sizeof(commandBlock));
619 
620 	commandBlock[0] = SCSI_SEND_DIAGNOSTIC;
621 	commandBlock[1] = (lun->logical_unit_number << 5) | 4;
622 
623 	status_t result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, false);
624 
625 	int retry = 100;
626 	err_act action = err_act_ok;
627 	while (result == B_DEV_NO_MEDIA && retry > 0) {
628 		snooze(10000);
629 		result = usb_disk_request_sense(lun, &action);
630 		retry--;
631 	}
632 
633 	if (result != B_OK)
634 		TRACE("Send Diagnostic failed: %s\n", strerror(result));
635 	return result;
636 }
637 
638 
639 status_t
640 usb_disk_request_sense(device_lun *lun, err_act *_action)
641 {
642 	size_t dataLength = sizeof(scsi_request_sense_6_parameter);
643 	uint8 commandBlock[12];
644 	memset(commandBlock, 0, sizeof(commandBlock));
645 
646 	commandBlock[0] = SCSI_REQUEST_SENSE_6;
647 	commandBlock[1] = lun->logical_unit_number << 5;
648 	commandBlock[2] = 0; // page code
649 	commandBlock[4] = dataLength;
650 
651 	scsi_request_sense_6_parameter parameter;
652 	status_t result = B_ERROR;
653 	for (uint32 tries = 0; tries < 3; tries++) {
654 		result = usb_disk_operation(lun, commandBlock, 6, &parameter,
655 			&dataLength, true);
656 		if (result != B_TIMED_OUT)
657 			break;
658 		snooze(100000);
659 	}
660 	if (result != B_OK) {
661 		TRACE_ALWAYS("getting request sense data failed: %s\n",
662 			strerror(result));
663 		return result;
664 	}
665 
666 	const char *label = NULL;
667 	err_act action = err_act_fail;
668 	status_t status = B_ERROR;
669 	scsi_get_sense_asc_info((parameter.additional_sense_code << 8)
670 		| parameter.additional_sense_code_qualifier, &label, &action,
671 		&status);
672 
673 	if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY
674 		&& parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) {
675 		TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: "
676 			"0x%02x; %s\n", parameter.sense_key,
677 			parameter.additional_sense_code,
678 			parameter.additional_sense_code_qualifier,
679 			label ? label : "(unknown)");
680 	}
681 
682 	if ((parameter.additional_sense_code == 0
683 			&& parameter.additional_sense_code_qualifier == 0)
684 		|| label == NULL) {
685 		scsi_get_sense_key_info(parameter.sense_key, &label, &action, &status);
686 	}
687 
688 	if (status == B_DEV_MEDIA_CHANGED) {
689 		lun->media_changed = true;
690 		lun->media_present = true;
691 	} else if (parameter.sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION
692 		&& status != B_DEV_NO_MEDIA) {
693 		lun->media_present = true;
694 	} else if (status == B_DEV_NOT_READY) {
695 		lun->media_present = false;
696 		usb_disk_reset_capacity(lun);
697 	}
698 
699 	if (_action != NULL)
700 		*_action = action;
701 
702 	return status;
703 }
704 
705 
706 status_t
707 usb_disk_mode_sense(device_lun *lun)
708 {
709 	size_t dataLength = sizeof(scsi_mode_sense_6_parameter);
710 
711 	uint8 commandBlock[12];
712 	memset(commandBlock, 0, sizeof(commandBlock));
713 
714 	commandBlock[0] = SCSI_MODE_SENSE_6;
715 	commandBlock[1] = SCSI_MODE_PAGE_DEVICE_CONFIGURATION;
716 	commandBlock[2] = 0; // Current values
717 	commandBlock[3] = dataLength >> 8;
718 	commandBlock[4] = dataLength;
719 
720 	scsi_mode_sense_6_parameter parameter;
721 	status_t result = usb_disk_operation(lun, commandBlock, 6,
722 		&parameter, &dataLength, true);
723 	if (result != B_OK) {
724 		TRACE_ALWAYS("getting mode sense data failed: %s\n", strerror(result));
725 		return result;
726 	}
727 
728 	lun->write_protected
729 		= (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT)
730 			!= 0;
731 	TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no");
732 	return B_OK;
733 }
734 
735 
736 status_t
737 usb_disk_test_unit_ready(device_lun *lun, err_act *_action)
738 {
739 	// if unsupported we assume the unit is fixed and therefore always ok
740 	if (lun->device->is_ufi || !lun->device->tur_supported)
741 		return B_OK;
742 
743 	status_t result = B_OK;
744 	uint8 commandBlock[12];
745 	memset(commandBlock, 0, sizeof(commandBlock));
746 
747 	if (lun->device->is_atapi) {
748 		commandBlock[0] = SCSI_START_STOP_UNIT_6;
749 		commandBlock[1] = lun->logical_unit_number << 5;
750 		commandBlock[2] = 0;
751 		commandBlock[3] = 0;
752 		commandBlock[4] = 1;
753 
754 		result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, false,
755 			_action);
756 	} else {
757 		commandBlock[0] = SCSI_TEST_UNIT_READY_6;
758 		commandBlock[1] = lun->logical_unit_number << 5;
759 		commandBlock[2] = 0;
760 		commandBlock[3] = 0;
761 		commandBlock[4] = 0;
762 		result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, true,
763 			_action);
764 	}
765 
766 	if (result == B_DEV_INVALID_IOCTL) {
767 		lun->device->tur_supported = false;
768 		return B_OK;
769 	}
770 
771 	return result;
772 }
773 
774 
775 status_t
776 usb_disk_inquiry(device_lun *lun)
777 {
778 	size_t dataLength = sizeof(scsi_inquiry_6_parameter);
779 
780 	uint8 commandBlock[12];
781 	memset(commandBlock, 0, sizeof(commandBlock));
782 
783 	commandBlock[0] = SCSI_INQUIRY_6;
784 	commandBlock[1] = lun->logical_unit_number << 5;
785 	commandBlock[2] = 0; // page code
786 	commandBlock[4] = dataLength;
787 
788 	scsi_inquiry_6_parameter parameter;
789 	status_t result = B_ERROR;
790 	err_act action = err_act_ok;
791 	for (uint32 tries = 0; tries < 3; tries++) {
792 		result = usb_disk_operation(lun, commandBlock, 6, &parameter,
793 			&dataLength, true, &action);
794 		if (result == B_OK || (action != err_act_retry
795 				&& action != err_act_many_retries)) {
796 			break;
797 		}
798 	}
799 	if (result != B_OK) {
800 		TRACE_ALWAYS("getting inquiry data failed: %s\n", strerror(result));
801 		lun->device_type = B_DISK;
802 		lun->removable = true;
803 		return result;
804 	}
805 
806 	TRACE("peripherial_device_type  0x%02x\n",
807 		parameter.peripherial_device_type);
808 	TRACE("peripherial_qualifier    0x%02x\n",
809 		parameter.peripherial_qualifier);
810 	TRACE("removable_medium         %s\n",
811 		parameter.removable_medium ? "yes" : "no");
812 	TRACE("version                  0x%02x\n", parameter.version);
813 	TRACE("response_data_format     0x%02x\n", parameter.response_data_format);
814 	TRACE_ALWAYS("vendor_identification    \"%.8s\"\n",
815 		parameter.vendor_identification);
816 	TRACE_ALWAYS("product_identification   \"%.16s\"\n",
817 		parameter.product_identification);
818 	TRACE_ALWAYS("product_revision_level   \"%.4s\"\n",
819 		parameter.product_revision_level);
820 
821 	memcpy(lun->vendor_name, parameter.vendor_identification,
822 		MIN(sizeof(lun->vendor_name), sizeof(parameter.vendor_identification)));
823 	memcpy(lun->product_name, parameter.product_identification,
824 		MIN(sizeof(lun->product_name),
825 			sizeof(parameter.product_identification)));
826 	memcpy(lun->product_revision, parameter.product_revision_level,
827 		MIN(sizeof(lun->product_revision),
828 			sizeof(parameter.product_revision_level)));
829 
830 	lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */
831 	lun->removable = (parameter.removable_medium == 1);
832 	return B_OK;
833 }
834 
835 
836 status_t
837 usb_disk_reset_capacity(device_lun *lun)
838 {
839 	lun->block_size = 512;
840 	lun->block_count = 0;
841 	return B_OK;
842 }
843 
844 
845 static status_t
846 usb_disk_update_capacity_16(device_lun *lun)
847 {
848 	size_t dataLength = sizeof(scsi_read_capacity_16_parameter);
849 	scsi_read_capacity_16_parameter parameter;
850 	status_t result = B_ERROR;
851 	err_act action = err_act_ok;
852 
853 	uint8 commandBlock[16];
854 	memset(commandBlock, 0, sizeof(commandBlock));
855 
856 	commandBlock[0] = SCSI_SERVICE_ACTION_IN;
857 	commandBlock[1] = SCSI_SAI_READ_CAPACITY_16;
858 	commandBlock[10] = dataLength >> 24;
859 	commandBlock[11] = dataLength >> 16;
860 	commandBlock[12] = dataLength >> 8;
861 	commandBlock[13] = dataLength;
862 
863 	// Retry reading the capacity up to three times. The first try might only
864 	// yield a unit attention telling us that the device or media status
865 	// changed, which is more or less expected if it is the first operation
866 	// on the device or the device only clears the unit atention for capacity
867 	// reads.
868 	for (int32 i = 0; i < 5; i++) {
869 		result = usb_disk_operation(lun, commandBlock, 16, &parameter,
870 			&dataLength, true, &action);
871 
872 		if (result == B_OK || (action != err_act_retry
873 				&& action != err_act_many_retries)) {
874 			break;
875 		}
876 	}
877 
878 	if (result != B_OK) {
879 		TRACE_ALWAYS("failed to update capacity: %s\n", strerror(result));
880 		lun->media_present = false;
881 		lun->media_changed = false;
882 		usb_disk_reset_capacity(lun);
883 		return result;
884 	}
885 
886 	lun->media_present = true;
887 	lun->media_changed = false;
888 	lun->block_size = B_BENDIAN_TO_HOST_INT32(parameter.logical_block_length);
889 	lun->physical_block_size = lun->block_size;
890 	lun->block_count =
891 		B_BENDIAN_TO_HOST_INT64(parameter.last_logical_block_address) + 1;
892 	return B_OK;
893 }
894 
895 
896 status_t
897 usb_disk_update_capacity(device_lun *lun)
898 {
899 	size_t dataLength = sizeof(scsi_read_capacity_10_parameter);
900 	scsi_read_capacity_10_parameter parameter;
901 	status_t result = B_ERROR;
902 	err_act action = err_act_ok;
903 
904 	uint8 commandBlock[12];
905 	memset(commandBlock, 0, sizeof(commandBlock));
906 
907 	commandBlock[0] = SCSI_READ_CAPACITY_10;
908 	commandBlock[1] = lun->logical_unit_number << 5;
909 
910 	// Retry reading the capacity up to three times. The first try might only
911 	// yield a unit attention telling us that the device or media status
912 	// changed, which is more or less expected if it is the first operation
913 	// on the device or the device only clears the unit atention for capacity
914 	// reads.
915 	for (int32 i = 0; i < 5; i++) {
916 		result = usb_disk_operation(lun, commandBlock, 10, &parameter,
917 			&dataLength, true, &action);
918 
919 		if (result == B_OK || (action != err_act_retry
920 				&& action != err_act_many_retries)) {
921 			break;
922 		}
923 
924 		// In some cases, it's best to wait a little for the device to settle
925 		// before retrying.
926 		if (lun->device->is_ufi && (result == B_DEV_NO_MEDIA
927 				|| result == B_TIMED_OUT || result == B_DEV_STALLED))
928 			snooze(10000);
929 	}
930 
931 	if (result != B_OK) {
932 		TRACE_ALWAYS("failed to update capacity: %s\n", strerror(result));
933 		lun->media_present = false;
934 		lun->media_changed = false;
935 		usb_disk_reset_capacity(lun);
936 		return result;
937 	}
938 
939 	lun->media_present = true;
940 	lun->media_changed = false;
941 	lun->block_size = B_BENDIAN_TO_HOST_INT32(parameter.logical_block_length);
942 	lun->physical_block_size = lun->block_size;
943 	lun->block_count =
944 		B_BENDIAN_TO_HOST_INT32(parameter.last_logical_block_address) + 1;
945 	if (lun->block_count == 0) {
946 		// try SCSI_READ_CAPACITY_16
947 		result = usb_disk_update_capacity_16(lun);
948 		if (result != B_OK)
949 			return result;
950 	}
951 
952 	// ensure we have a DMAResource for this block_size
953 	if (get_dma_resource(lun->device, lun->block_size) == NULL) {
954 		dma_restrictions restrictions = {};
955 		restrictions.max_transfer_size = (lun->block_size * MAX_IO_BLOCKS);
956 
957 		DMAResource* dmaResource = new DMAResource;
958 		result = dmaResource->Init(restrictions, lun->block_size, 1, 1);
959 		if (result != B_OK)
960 			return result;
961 
962 		lun->device->dma_resources.Add(dmaResource);
963 	}
964 
965 	return B_OK;
966 }
967 
968 
969 status_t
970 usb_disk_synchronize(device_lun *lun, bool force)
971 {
972 	if (lun->device->is_ufi) {
973 		// UFI use interrupt because it runs all commands immediately, and
974 		// tells us when its done. There is no cache involved in that case,
975 		// so nothing to synchronize.
976 		return B_UNSUPPORTED;
977 	}
978 
979 	if (lun->device->sync_support == 0) {
980 		// this device reported an illegal request when syncing or repeatedly
981 		// returned an other error, it apparently does not support syncing...
982 		return B_UNSUPPORTED;
983 	}
984 
985 	if (!lun->should_sync && !force)
986 		return B_OK;
987 
988 	uint8 commandBlock[12];
989 	memset(commandBlock, 0, sizeof(commandBlock));
990 
991 	commandBlock[0] = SCSI_SYNCHRONIZE_CACHE_10;
992 	commandBlock[1] = lun->logical_unit_number << 5;
993 
994 	status_t result = usb_disk_operation(lun, commandBlock, 10,
995 		NULL, NULL, false);
996 
997 	if (result == B_OK) {
998 		lun->device->sync_support = SYNC_SUPPORT_RELOAD;
999 		lun->should_sync = false;
1000 		return B_OK;
1001 	}
1002 
1003 	if (result == B_DEV_INVALID_IOCTL)
1004 		lun->device->sync_support = 0;
1005 	else
1006 		lun->device->sync_support--;
1007 
1008 	return result;
1009 }
1010 
1011 
1012 //
1013 //#pragma mark - Device Attach/Detach Notifications and Callback
1014 //
1015 
1016 
1017 static void
1018 usb_disk_callback(void *cookie, status_t status, void *data,
1019 	size_t actualLength)
1020 {
1021 	//TRACE("callback()\n");
1022 	disk_device *device = (disk_device *)cookie;
1023 	device->status = status;
1024 	device->actual_length = actualLength;
1025 	release_sem(device->notify);
1026 }
1027 
1028 
1029 static status_t
1030 usb_disk_attach(device_node *node, usb_device newDevice, void **cookie)
1031 {
1032 	TRACE("device_added(0x%08" B_PRIx32 ")\n", newDevice);
1033 	disk_device *device = new(std::nothrow) disk_device;
1034 	recursive_lock_lock(&device->io_lock);
1035 	mutex_lock(&device->lock);
1036 
1037 	device->node = node;
1038 	device->device = newDevice;
1039 	device->removed = false;
1040 	device->open_count = 0;
1041 	device->interface = 0xff;
1042 	device->current_tag = 0;
1043 	device->sync_support = SYNC_SUPPORT_RELOAD;
1044 	device->tur_supported = true;
1045 	device->is_atapi = false;
1046 	device->is_ufi = false;
1047 	device->luns = NULL;
1048 
1049 	// scan through the interfaces to find our bulk-only data interface
1050 	const usb_configuration_info *configuration
1051 		= gUSBModule->get_configuration(newDevice);
1052 	if (configuration == NULL) {
1053 		delete device;
1054 		return B_ERROR;
1055 	}
1056 
1057 	for (size_t i = 0; i < configuration->interface_count; i++) {
1058 		usb_interface_info *interface = configuration->interface[i].active;
1059 		if (interface == NULL)
1060 			continue;
1061 
1062 		if (interface->descr->interface_class == USB_MASS_STORAGE_DEVICE_CLASS
1063 			&& (((interface->descr->interface_subclass == 0x06 /* SCSI */
1064 					|| interface->descr->interface_subclass == 0x02 /* ATAPI */
1065 					|| interface->descr->interface_subclass == 0x05 /* ATAPI */)
1066 				&& interface->descr->interface_protocol == 0x50 /* bulk-only */)
1067 			|| (interface->descr->interface_subclass == 0x04 /* UFI */
1068 				&& interface->descr->interface_protocol == 0x00))) {
1069 
1070 			bool hasIn = false;
1071 			bool hasOut = false;
1072 			bool hasInt = false;
1073 			for (size_t j = 0; j < interface->endpoint_count; j++) {
1074 				usb_endpoint_info *endpoint = &interface->endpoint[j];
1075 				if (endpoint == NULL)
1076 					continue;
1077 
1078 				if (!hasIn && (endpoint->descr->endpoint_address
1079 					& USB_ENDPOINT_ADDR_DIR_IN) != 0
1080 					&& endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) {
1081 					device->bulk_in = endpoint->handle;
1082 					hasIn = true;
1083 				} else if (!hasOut && (endpoint->descr->endpoint_address
1084 					& USB_ENDPOINT_ADDR_DIR_IN) == 0
1085 					&& endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) {
1086 					device->bulk_out = endpoint->handle;
1087 					hasOut = true;
1088 				} else if (!hasInt && (endpoint->descr->endpoint_address
1089 					& USB_ENDPOINT_ADDR_DIR_IN)
1090 					&& endpoint->descr->attributes
1091 					== USB_ENDPOINT_ATTR_INTERRUPT) {
1092 					device->interrupt = endpoint->handle;
1093 					hasInt = true;
1094 				}
1095 
1096 				if (hasIn && hasOut && hasInt)
1097 					break;
1098 			}
1099 
1100 			if (!(hasIn && hasOut)) {
1101 				// Missing one of the required endpoints, try next interface
1102 				continue;
1103 			}
1104 
1105 			device->interface = interface->descr->interface_number;
1106 			device->is_atapi = interface->descr->interface_subclass != 0x06
1107 				&& interface->descr->interface_subclass != 0x04;
1108 			device->is_ufi = interface->descr->interface_subclass == 0x04;
1109 
1110 			if (device->is_ufi && !hasInt) {
1111 				// UFI without interrupt endpoint is not possible.
1112 				continue;
1113 			}
1114 			break;
1115 		}
1116 	}
1117 
1118 	if (device->interface == 0xff) {
1119 		TRACE_ALWAYS("no valid bulk-only or CBI interface found\n");
1120 		delete device;
1121 		return B_ERROR;
1122 	}
1123 
1124 	device->notify = create_sem(0, "usb_disk callback notify");
1125 	if (device->notify < B_OK) {
1126 		status_t result = device->notify;
1127 		delete device;
1128 		return result;
1129 	}
1130 
1131 	if (device->is_ufi) {
1132 		device->interruptLock = create_sem(0, "usb_disk interrupt lock");
1133 		if (device->interruptLock < B_OK) {
1134 			status_t result = device->interruptLock;
1135 			delete device;
1136 			return result;
1137 		}
1138 	}
1139 
1140 	device->lun_count = usb_disk_get_max_lun(device) + 1;
1141 	device->luns = (device_lun **)malloc(device->lun_count
1142 		* sizeof(device_lun *));
1143 	for (uint8 i = 0; i < device->lun_count; i++)
1144 		device->luns[i] = NULL;
1145 
1146 	status_t result = B_OK;
1147 
1148 	TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count);
1149 	for (uint8 i = 0; i < device->lun_count; i++) {
1150 		// create the individual luns present on this device
1151 		device_lun *lun = (device_lun *)malloc(sizeof(device_lun));
1152 		if (lun == NULL) {
1153 			result = B_NO_MEMORY;
1154 			break;
1155 		}
1156 
1157 		device->luns[i] = lun;
1158 		lun->device = device;
1159 		lun->logical_unit_number = i;
1160 		lun->should_sync = false;
1161 		lun->media_present = true;
1162 		lun->media_changed = true;
1163 
1164 		memset(lun->vendor_name, 0, sizeof(lun->vendor_name));
1165 		memset(lun->product_name, 0, sizeof(lun->product_name));
1166 		memset(lun->product_revision, 0, sizeof(lun->product_revision));
1167 
1168 		usb_disk_reset_capacity(lun);
1169 
1170 		// initialize this lun
1171 		result = usb_disk_inquiry(lun);
1172 
1173 		if (device->is_ufi) {
1174 			// Reset the device
1175 			// If we don't do it all the other commands except inquiry and send
1176 			// diagnostics will be stalled.
1177 			result = usb_disk_send_diagnostic(lun);
1178 		}
1179 
1180 		err_act action = err_act_ok;
1181 		for (uint32 tries = 0; tries < 8; tries++) {
1182 			TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " begin\n",
1183 				i, tries);
1184 			status_t ready = usb_disk_test_unit_ready(lun, &action);
1185 			if (ready == B_OK || ready == B_DEV_NO_MEDIA
1186 				|| ready == B_DEV_MEDIA_CHANGED) {
1187 				if (lun->device_type == B_CD)
1188 					lun->write_protected = true;
1189 				// TODO: check for write protection; disabled since some
1190 				// devices lock up when getting the mode sense
1191 				else if (/*usb_disk_mode_sense(lun) != B_OK*/true)
1192 					lun->write_protected = false;
1193 
1194 				TRACE("usb lun %" B_PRIu8 " ready. write protected = %c%s\n", i,
1195 					lun->write_protected ? 'y' : 'n',
1196 					ready == B_DEV_NO_MEDIA ? " (no media inserted)" : "");
1197 
1198 				break;
1199 			}
1200 			TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " failed\n",
1201 				i, tries);
1202 			if (action != err_act_retry && action != err_act_many_retries)
1203 				break;
1204 			bigtime_t snoozeTime = 1000000 * tries;
1205 			TRACE("snoozing %" B_PRIu64 " microseconds for usb lun\n",
1206 				snoozeTime);
1207 			snooze(snoozeTime);
1208 		}
1209 
1210 		if (result != B_OK)
1211 			break;
1212 	}
1213 
1214 	if (result != B_OK) {
1215 		TRACE_ALWAYS("failed to initialize logical units: %s\n",
1216 			strerror(result));
1217 		usb_disk_free_device_and_luns(device);
1218 		return result;
1219 	}
1220 
1221 	mutex_unlock(&device->lock);
1222 	recursive_lock_unlock(&device->io_lock);
1223 
1224 	TRACE("new device: 0x%p\n", device);
1225 	*cookie = (void *)device;
1226 	return B_OK;
1227 }
1228 
1229 
1230 static void
1231 usb_disk_device_removed(void *cookie)
1232 {
1233 	TRACE("device_removed(0x%p)\n", cookie);
1234 	disk_device *device = (disk_device *)cookie;
1235 	mutex_lock(&device->lock);
1236 
1237 	for (uint8 i = 0; i < device->lun_count; i++) {
1238 		// unpublish_device() can call close().
1239 		mutex_unlock(&device->lock);
1240 		gDeviceManager->unpublish_device(device->node, device->luns[i]->name);
1241 		mutex_lock(&device->lock);
1242 	}
1243 
1244 	device->removed = true;
1245 	gUSBModule->cancel_queued_transfers(device->bulk_in);
1246 	gUSBModule->cancel_queued_transfers(device->bulk_out);
1247 	if (device->is_ufi)
1248 		gUSBModule->cancel_queued_transfers(device->interrupt);
1249 
1250 	// At this point, open_count should always be 0 anyway.
1251 	if (device->open_count == 0)
1252 		usb_disk_free_device_and_luns(device);
1253 	else
1254 		mutex_unlock(&device->lock);
1255 }
1256 
1257 
1258 static bool
1259 usb_disk_needs_bounce(device_lun *lun, io_request *request)
1260 {
1261 	if (!request->Buffer()->IsVirtual())
1262 		return true;
1263 	if ((request->Offset() % lun->block_size) != 0)
1264 		return true;
1265 	if ((request->Length() % lun->block_size) != 0)
1266 		return true;
1267 	if (request->Length() > (lun->block_size * MAX_IO_BLOCKS))
1268 		return true;
1269 	return false;
1270 }
1271 
1272 
1273 static status_t
1274 usb_disk_block_read(device_lun *lun, uint64 blockPosition, size_t blockCount,
1275 	struct transfer_data data, size_t *length)
1276 {
1277 	uint8 commandBlock[16];
1278 	memset(commandBlock, 0, sizeof(commandBlock));
1279 	if (lun->device->is_ufi) {
1280 		commandBlock[0] = SCSI_READ_12;
1281 		commandBlock[1] = lun->logical_unit_number << 5;
1282 		commandBlock[2] = blockPosition >> 24;
1283 		commandBlock[3] = blockPosition >> 16;
1284 		commandBlock[4] = blockPosition >> 8;
1285 		commandBlock[5] = blockPosition;
1286 		commandBlock[6] = blockCount >> 24;
1287 		commandBlock[7] = blockCount >> 16;
1288 		commandBlock[8] = blockCount >> 8;
1289 		commandBlock[9] = blockCount;
1290 
1291 		status_t result = B_OK;
1292 		for (int tries = 0; tries < 5; tries++) {
1293 			result = usb_disk_operation(lun, commandBlock, 12, data,
1294 				length, true);
1295 			if (result == B_OK)
1296 				break;
1297 			else
1298 				snooze(10000);
1299 		}
1300 		return result;
1301 	} else if (blockPosition + blockCount < 0x100000000LL && blockCount <= 0x10000) {
1302 		commandBlock[0] = SCSI_READ_10;
1303 		commandBlock[1] = 0;
1304 		commandBlock[2] = blockPosition >> 24;
1305 		commandBlock[3] = blockPosition >> 16;
1306 		commandBlock[4] = blockPosition >> 8;
1307 		commandBlock[5] = blockPosition;
1308 		commandBlock[7] = blockCount >> 8;
1309 		commandBlock[8] = blockCount;
1310 		status_t result = usb_disk_operation(lun, commandBlock, 10,
1311 			data, length, true);
1312 		return result;
1313 	} else {
1314 		commandBlock[0] = SCSI_READ_16;
1315 		commandBlock[1] = 0;
1316 		commandBlock[2] = blockPosition >> 56;
1317 		commandBlock[3] = blockPosition >> 48;
1318 		commandBlock[4] = blockPosition >> 40;
1319 		commandBlock[5] = blockPosition >> 32;
1320 		commandBlock[6] = blockPosition >> 24;
1321 		commandBlock[7] = blockPosition >> 16;
1322 		commandBlock[8] = blockPosition >> 8;
1323 		commandBlock[9] = blockPosition;
1324 		commandBlock[10] = blockCount >> 24;
1325 		commandBlock[11] = blockCount >> 16;
1326 		commandBlock[12] = blockCount >> 8;
1327 		commandBlock[13] = blockCount;
1328 		status_t result = usb_disk_operation(lun, commandBlock, 16,
1329 			data, length, true);
1330 		return result;
1331 	}
1332 }
1333 
1334 
1335 static status_t
1336 usb_disk_block_write(device_lun *lun, uint64 blockPosition, size_t blockCount,
1337 	struct transfer_data data, size_t *length)
1338 {
1339 	uint8 commandBlock[16];
1340 	memset(commandBlock, 0, sizeof(commandBlock));
1341 
1342 	if (lun->device->is_ufi) {
1343 		commandBlock[0] = SCSI_WRITE_12;
1344 		commandBlock[1] = lun->logical_unit_number << 5;
1345 		commandBlock[2] = blockPosition >> 24;
1346 		commandBlock[3] = blockPosition >> 16;
1347 		commandBlock[4] = blockPosition >> 8;
1348 		commandBlock[5] = blockPosition;
1349 		commandBlock[6] = blockCount >> 24;
1350 		commandBlock[7] = blockCount >> 16;
1351 		commandBlock[8] = blockCount >> 8;
1352 		commandBlock[9] = blockCount;
1353 
1354 		status_t result;
1355 		result = usb_disk_operation(lun, commandBlock, 12,
1356 			data, length, false);
1357 
1358 		int retry = 10;
1359 		err_act action = err_act_ok;
1360 		while (result == B_DEV_NO_MEDIA && retry > 0) {
1361 			snooze(10000);
1362 			result = usb_disk_request_sense(lun, &action);
1363 			retry--;
1364 		}
1365 
1366 		if (result == B_OK)
1367 			lun->should_sync = true;
1368 		return result;
1369 	} else if (blockPosition + blockCount < 0x100000000LL && blockCount <= 0x10000) {
1370 		commandBlock[0] = SCSI_WRITE_10;
1371 		commandBlock[2] = blockPosition >> 24;
1372 		commandBlock[3] = blockPosition >> 16;
1373 		commandBlock[4] = blockPosition >> 8;
1374 		commandBlock[5] = blockPosition;
1375 		commandBlock[7] = blockCount >> 8;
1376 		commandBlock[8] = blockCount;
1377 		status_t result = usb_disk_operation(lun, commandBlock, 10,
1378 			data, length, false);
1379 		if (result == B_OK)
1380 			lun->should_sync = true;
1381 		return result;
1382 	} else {
1383 		commandBlock[0] = SCSI_WRITE_16;
1384 		commandBlock[1] = 0;
1385 		commandBlock[2] = blockPosition >> 56;
1386 		commandBlock[3] = blockPosition >> 48;
1387 		commandBlock[4] = blockPosition >> 40;
1388 		commandBlock[5] = blockPosition >> 32;
1389 		commandBlock[6] = blockPosition >> 24;
1390 		commandBlock[7] = blockPosition >> 16;
1391 		commandBlock[8] = blockPosition >> 8;
1392 		commandBlock[9] = blockPosition;
1393 		commandBlock[10] = blockCount >> 24;
1394 		commandBlock[11] = blockCount >> 16;
1395 		commandBlock[12] = blockCount >> 8;
1396 		commandBlock[13] = blockCount;
1397 		status_t result = usb_disk_operation(lun, commandBlock, 16,
1398 			data, length, false);
1399 		if (result == B_OK)
1400 			lun->should_sync = true;
1401 		return result;
1402 	}
1403 }
1404 
1405 
1406 //
1407 //#pragma mark - Driver Hooks
1408 //
1409 
1410 
1411 static status_t
1412 usb_disk_init_device(void* _info, void** _cookie)
1413 {
1414 	CALLED();
1415 	*_cookie = _info;
1416 	return B_OK;
1417 }
1418 
1419 
1420 static void
1421 usb_disk_uninit_device(void* _cookie)
1422 {
1423 	// Nothing to do.
1424 }
1425 
1426 
1427 static status_t
1428 usb_disk_open(void *deviceCookie, const char *path, int flags, void **_cookie)
1429 {
1430 	TRACE("open(%s)\n", path);
1431 	if (strncmp(path, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0)
1432 		return B_NAME_NOT_FOUND;
1433 
1434 	int32 lastPart = 0;
1435 	size_t nameLength = strlen(path);
1436 	for (int32 i = nameLength - 1; i >= 0; i--) {
1437 		if (path[i] == '/') {
1438 			lastPart = i;
1439 			break;
1440 		}
1441 	}
1442 
1443 	char rawName[nameLength + 4];
1444 	strncpy(rawName, path, lastPart + 1);
1445 	rawName[lastPart + 1] = 0;
1446 	strcat(rawName, "raw");
1447 
1448 	disk_device *device = (disk_device *)deviceCookie;
1449 	MutexLocker locker(device->lock);
1450 	for (uint8 i = 0; i < device->lun_count; i++) {
1451 		device_lun *lun = device->luns[i];
1452 		if (strncmp(rawName, lun->name, 32) == 0) {
1453 			// found the matching device/lun
1454 			if (device->removed)
1455 				return B_ERROR;
1456 
1457 			device->open_count++;
1458 			*_cookie = lun;
1459 			return B_OK;
1460 		}
1461 	}
1462 
1463 	return B_NAME_NOT_FOUND;
1464 }
1465 
1466 
1467 static status_t
1468 usb_disk_close(void *cookie)
1469 {
1470 	TRACE("close()\n");
1471 	device_lun *lun = (device_lun *)cookie;
1472 	disk_device *device = lun->device;
1473 
1474 	RecursiveLocker ioLocker(device->io_lock);
1475 	MutexLocker deviceLocker(device->lock);
1476 
1477 	if (!device->removed)
1478 		usb_disk_synchronize(lun, false);
1479 
1480 	return B_OK;
1481 }
1482 
1483 
1484 static status_t
1485 usb_disk_free(void *cookie)
1486 {
1487 	TRACE("free()\n");
1488 
1489 	device_lun *lun = (device_lun *)cookie;
1490 	disk_device *device = lun->device;
1491 	mutex_lock(&device->lock);
1492 
1493 	device->open_count--;
1494 	if (device->open_count == 0 && device->removed) {
1495 		// we can simply free the device here as it has been removed from
1496 		// the device list in the device removed notification hook
1497 		usb_disk_free_device_and_luns(device);
1498 	} else {
1499 		mutex_unlock(&device->lock);
1500 	}
1501 
1502 	return B_OK;
1503 }
1504 
1505 
1506 static inline void
1507 normalize_name(char *name, size_t nameLength)
1508 {
1509 	bool wasSpace = false;
1510 	size_t insertIndex = 0;
1511 	for (size_t i = 0; i < nameLength; i++) {
1512 		bool isSpace = name[i] == ' ';
1513 		if (isSpace && wasSpace)
1514 			continue;
1515 
1516 		name[insertIndex++] = name[i];
1517 		wasSpace = isSpace;
1518 	}
1519 
1520 	if (insertIndex > 0 && name[insertIndex - 1] == ' ')
1521 		insertIndex--;
1522 
1523 	name[insertIndex] = 0;
1524 }
1525 
1526 
1527 static status_t
1528 acquire_io_lock(disk_device *device, MutexLocker& locker, RecursiveLocker& ioLocker)
1529 {
1530 	locker.Unlock();
1531 	ioLocker.SetTo(device->io_lock, false, true);
1532 	locker.Lock();
1533 
1534 	if (!locker.IsLocked() || !ioLocker.IsLocked())
1535 		return B_ERROR;
1536 
1537 	if (device->removed)
1538 		return B_DEV_NOT_READY;
1539 
1540 	return B_OK;
1541 }
1542 
1543 
1544 static status_t
1545 handle_media_change(device_lun *lun, MutexLocker& locker)
1546 {
1547 	RecursiveLocker ioLocker;
1548 	status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1549 	if (result != B_OK)
1550 		return result;
1551 
1552 	// It may have been handled while we were waiting for locks.
1553 	if (lun->media_changed) {
1554 		result = usb_disk_update_capacity(lun);
1555 		if (result != B_OK)
1556 			return result;
1557 	}
1558 
1559 	return B_OK;
1560 }
1561 
1562 
1563 static status_t
1564 usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
1565 {
1566 	device_lun *lun = (device_lun *)cookie;
1567 	disk_device *device = lun->device;
1568 	MutexLocker locker(&device->lock);
1569 	if (device->removed)
1570 		return B_DEV_NOT_READY;
1571 	RecursiveLocker ioLocker;
1572 
1573 	switch (op) {
1574 		case B_GET_DEVICE_SIZE:
1575 		{
1576 			if (lun->media_changed) {
1577 				status_t result = handle_media_change(lun, locker);
1578 				if (result != B_OK)
1579 					return result;
1580 			}
1581 
1582 			size_t size = lun->block_size * lun->block_count;
1583 			return user_memcpy(buffer, &size, sizeof(size));
1584 		}
1585 
1586 		case B_GET_MEDIA_STATUS:
1587 		{
1588 			status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1589 			if (result != B_OK)
1590 				return result;
1591 
1592 			err_act action = err_act_ok;
1593 			status_t ready;
1594 			for (uint32 tries = 0; tries < 3; tries++) {
1595 				ready = usb_disk_test_unit_ready(lun, &action);
1596 				if (ready == B_OK || ready == B_DEV_NO_MEDIA
1597 					|| (action != err_act_retry
1598 						&& action != err_act_many_retries)) {
1599 					if (IS_USER_ADDRESS(buffer)) {
1600 						if (user_memcpy(buffer, &ready, sizeof(status_t)) != B_OK)
1601 							return B_BAD_ADDRESS;
1602 					} else if (is_called_via_syscall()) {
1603 						return B_BAD_ADDRESS;
1604 					} else
1605 						*(status_t *)buffer = ready;
1606 					break;
1607 				}
1608 				snooze(500000);
1609 			}
1610 			TRACE("B_GET_MEDIA_STATUS: 0x%08" B_PRIx32 "\n", ready);
1611 			return B_OK;
1612 		}
1613 
1614 		case B_GET_GEOMETRY:
1615 		{
1616 			if (buffer == NULL || length > sizeof(device_geometry))
1617 				return B_BAD_VALUE;
1618 			if (lun->media_changed) {
1619 				status_t result = handle_media_change(lun, locker);
1620 				if (result != B_OK)
1621 					return result;
1622 			}
1623 
1624 			device_geometry geometry;
1625 			devfs_compute_geometry_size(&geometry, lun->block_count,
1626 				lun->block_size);
1627 			geometry.bytes_per_physical_sector = lun->physical_block_size;
1628 
1629 			geometry.device_type = lun->device_type;
1630 			geometry.removable = lun->removable;
1631 			geometry.read_only = lun->write_protected;
1632 			geometry.write_once = lun->device_type == B_WORM;
1633 			TRACE("B_GET_GEOMETRY: %" B_PRId32 " sectors at %" B_PRId32
1634 				" bytes per sector\n", geometry.cylinder_count,
1635 				geometry.bytes_per_sector);
1636 			return user_memcpy(buffer, &geometry, length);
1637 		}
1638 
1639 		case B_FLUSH_DRIVE_CACHE:
1640 		{
1641 			TRACE("B_FLUSH_DRIVE_CACHE\n");
1642 
1643 			status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1644 			if (result != B_OK)
1645 				return result;
1646 
1647 			return usb_disk_synchronize(lun, true);
1648 		}
1649 
1650 		case B_EJECT_DEVICE:
1651 		{
1652 			status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1653 			if (result != B_OK)
1654 				return result;
1655 
1656 			uint8 commandBlock[12];
1657 			memset(commandBlock, 0, sizeof(commandBlock));
1658 
1659 			commandBlock[0] = SCSI_START_STOP_UNIT_6;
1660 			commandBlock[1] = lun->logical_unit_number << 5;
1661 			commandBlock[4] = 2;
1662 
1663 			return usb_disk_operation(lun, commandBlock, 6, NULL, NULL,
1664 				false);
1665 		}
1666 
1667 		case B_LOAD_MEDIA:
1668 		{
1669 			status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1670 			if (result != B_OK)
1671 				return result;
1672 
1673 			uint8 commandBlock[12];
1674 			memset(commandBlock, 0, sizeof(commandBlock));
1675 
1676 			commandBlock[0] = SCSI_START_STOP_UNIT_6;
1677 			commandBlock[1] = lun->logical_unit_number << 5;
1678 			commandBlock[4] = 3;
1679 
1680 			return usb_disk_operation(lun, commandBlock, 6, NULL, NULL,
1681 				false);
1682 		}
1683 
1684 		case B_GET_ICON:
1685 			// We don't support this legacy ioctl anymore, but the two other
1686 			// icon ioctls below instead.
1687 			break;
1688 
1689 		case B_GET_ICON_NAME:
1690 		{
1691 			const char *iconName = "devices/drive-removable-media-usb";
1692 			char vendor[sizeof(lun->vendor_name)+1];
1693 			char product[sizeof(lun->product_name)+1];
1694 
1695 			if (device->is_ufi) {
1696 				iconName = "devices/drive-floppy-usb";
1697 			}
1698 
1699 			switch (lun->device_type) {
1700 				case B_CD:
1701 				case B_OPTICAL:
1702 					iconName = "devices/drive-optical";
1703 					break;
1704 				case B_TAPE:	// TODO
1705 				default:
1706 					snprintf(vendor, sizeof(vendor), "%.8s",
1707 						lun->vendor_name);
1708 					snprintf(product, sizeof(product), "%.16s",
1709 						lun->product_name);
1710 					for (int i = 0; kIconMatches[i].icon; i++) {
1711 						if (kIconMatches[i].vendor != NULL
1712 							&& strstr(vendor, kIconMatches[i].vendor) == NULL)
1713 							continue;
1714 						if (kIconMatches[i].product != NULL
1715 							&& strstr(product, kIconMatches[i].product) == NULL)
1716 							continue;
1717 						iconName = kIconMatches[i].name;
1718 					}
1719 					break;
1720 			}
1721 			return user_strlcpy((char *)buffer, iconName,
1722 				B_FILE_NAME_LENGTH);
1723 		}
1724 
1725 		case B_GET_VECTOR_ICON:
1726 		{
1727 			device_icon *icon = &kKeyIconData;
1728 			char vendor[sizeof(lun->vendor_name)+1];
1729 			char product[sizeof(lun->product_name)+1];
1730 
1731 			if (length != sizeof(device_icon))
1732 				return B_BAD_VALUE;
1733 
1734 			if (device->is_ufi) {
1735 				// UFI is specific for floppy drives
1736 				icon = &kFloppyIconData;
1737 			} else {
1738 				switch (lun->device_type) {
1739 					case B_CD:
1740 					case B_OPTICAL:
1741 						icon = &kCDIconData;
1742 						break;
1743 					case B_TAPE:	// TODO
1744 					default:
1745 						snprintf(vendor, sizeof(vendor), "%.8s",
1746 								lun->vendor_name);
1747 						snprintf(product, sizeof(product), "%.16s",
1748 								lun->product_name);
1749 						for (int i = 0; kIconMatches[i].icon; i++) {
1750 							if (kIconMatches[i].vendor != NULL
1751 									&& strstr(vendor,
1752 										kIconMatches[i].vendor) == NULL)
1753 								continue;
1754 							if (kIconMatches[i].product != NULL
1755 									&& strstr(product,
1756 										kIconMatches[i].product) == NULL)
1757 								continue;
1758 							icon = kIconMatches[i].icon;
1759 						}
1760 						break;
1761 				}
1762 			}
1763 
1764 			device_icon iconData;
1765 			if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK)
1766 				return B_BAD_ADDRESS;
1767 
1768 			if (iconData.icon_size >= icon->icon_size) {
1769 				if (user_memcpy(iconData.icon_data, icon->icon_data,
1770 						(size_t)icon->icon_size) != B_OK)
1771 					return B_BAD_ADDRESS;
1772 			}
1773 
1774 			iconData.icon_size = icon->icon_size;
1775 			return user_memcpy(buffer, &iconData, sizeof(device_icon));
1776 		}
1777 
1778 		case B_GET_DEVICE_NAME:
1779 		{
1780 			size_t nameLength = sizeof(lun->vendor_name)
1781 				+ sizeof(lun->product_name) + sizeof(lun->product_revision) + 3;
1782 
1783 			char name[nameLength];
1784 			snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name,
1785 				lun->product_name, lun->product_revision);
1786 
1787 			normalize_name(name, nameLength);
1788 
1789 			status_t result = user_strlcpy((char *)buffer, name, length);
1790 			if (result > 0)
1791 				result = B_OK;
1792 
1793 			TRACE_ALWAYS("got device name \"%s\": %s\n", name,
1794 				strerror(result));
1795 			return result;
1796 		}
1797 	}
1798 
1799 	TRACE_ALWAYS("unhandled ioctl %" B_PRId32 "\n", op);
1800 	return B_DEV_INVALID_IOCTL;
1801 }
1802 
1803 
1804 static status_t
1805 usb_disk_bounced_io(device_lun *lun, io_request *request)
1806 {
1807 	DMAResource* dmaResource = get_dma_resource(lun->device, lun->block_size);
1808 	if (dmaResource == NULL)
1809 		return B_NO_INIT;
1810 
1811 	if (!request->Buffer()->IsPhysical()) {
1812 		status_t status = request->Buffer()->LockMemory(request->TeamID(), request->IsWrite());
1813 		if (status != B_OK) {
1814 			TRACE_ALWAYS("failed to lock memory: %s\n", strerror(status));
1815 			return status;
1816 		}
1817 		// SetStatusAndNotify() takes care of unlocking memory if necessary.
1818 	}
1819 
1820 	status_t status = B_OK;
1821 	while (request->RemainingBytes() > 0) {
1822 		IOOperation operation;
1823 		status = dmaResource->TranslateNext(request, &operation, 0);
1824 		if (status != B_OK)
1825 			break;
1826 
1827 		do {
1828 			TRACE("%p: IOO offset: %" B_PRIdOFF ", length: %" B_PRIuGENADDR
1829 				", write: %s\n", request, operation.Offset(),
1830 				operation.Length(), operation.IsWrite() ? "yes" : "no");
1831 
1832 			struct transfer_data data;
1833 			data.physical = true;
1834 			data.phys_vecs = (physical_entry*)operation.Vecs();
1835 			data.vec_count = operation.VecCount();
1836 
1837 			size_t length = operation.Length();
1838 			const uint64 blockPosition = operation.Offset() / lun->block_size;
1839 			const size_t blockCount = length / lun->block_size;
1840 			if (operation.IsWrite()) {
1841 				status = usb_disk_block_write(lun,
1842 					blockPosition, blockCount, data, &length);
1843 			} else {
1844 				status = usb_disk_block_read(lun,
1845 					blockPosition, blockCount, data, &length);
1846 			}
1847 
1848 			operation.SetStatus(status, length);
1849 		} while (status == B_OK && !operation.Finish());
1850 
1851 		if (status == B_OK && operation.Status() != B_OK) {
1852 			TRACE_ALWAYS("I/O succeeded but IOOperation failed!\n");
1853 			status = operation.Status();
1854 		}
1855 
1856 		request->OperationFinished(&operation);
1857 		dmaResource->RecycleBuffer(operation.Buffer());
1858 
1859 		TRACE("%p: status %s, remaining bytes %" B_PRIuGENADDR "\n", request,
1860 			strerror(status), request->RemainingBytes());
1861 		if (status != B_OK)
1862 			break;
1863 	}
1864 
1865 	return status;
1866 }
1867 
1868 
1869 static status_t
1870 usb_disk_direct_io(device_lun *lun, io_request *request)
1871 {
1872 	generic_io_vec* genericVecs = request->Buffer()->Vecs();
1873 	const uint32 count = request->Buffer()->VecCount();
1874 	BStackOrHeapArray<iovec, 16> vecs(count);
1875 	for (uint32 i = 0; i < count; i++) {
1876 		vecs[i].iov_base = (void*)genericVecs[i].base;
1877 		vecs[i].iov_len = genericVecs[i].length;
1878 	}
1879 	struct transfer_data data;
1880 	data.vecs = vecs;
1881 	data.vec_count = count;
1882 
1883 	size_t length = request->Length();
1884 	const uint64 blockPosition = request->Offset() / lun->block_size;
1885 	const size_t blockCount = length / lun->block_size;
1886 
1887 	status_t status;
1888 	if (request->IsWrite()) {
1889 		 status = usb_disk_block_write(lun,
1890 			blockPosition, blockCount, data, &length);
1891 	} else {
1892 		status = usb_disk_block_read(lun,
1893 			blockPosition, blockCount, data, &length);
1894 	}
1895 
1896 	request->SetTransferredBytes(length != request->Length(), length);
1897 	return status;
1898 }
1899 
1900 
1901 static status_t
1902 usb_disk_io(void *cookie, io_request *request)
1903 {
1904 	TRACE("io(%p)\n", request);
1905 
1906 	device_lun *lun = (device_lun *)cookie;
1907 	disk_device *device = lun->device;
1908 
1909 	RecursiveLocker ioLocker(device->io_lock);
1910 	MutexLocker deviceLocker(device->lock);
1911 
1912 	if (device->removed)
1913 		return B_DEV_NOT_READY;
1914 
1915 	status_t status;
1916 	if (!usb_disk_needs_bounce(lun, request)) {
1917 		status = usb_disk_direct_io(lun, request);
1918 	} else {
1919 		status = usb_disk_bounced_io(lun, request);
1920 	}
1921 
1922 	deviceLocker.Unlock();
1923 	ioLocker.Unlock();
1924 
1925 	if (request->Status() > 0)
1926 		request->SetStatusAndNotify(status);
1927 	else
1928 		request->NotifyFinished();
1929 	return status;
1930 }
1931 
1932 
1933 //	#pragma mark - driver module API
1934 
1935 
1936 static float
1937 usb_disk_supports_device(device_node *parent)
1938 {
1939 	CALLED();
1940 	const char *bus;
1941 
1942 	// make sure parent is really the usb bus manager
1943 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
1944 		return -1;
1945 	if (strcmp(bus, "usb") != 0)
1946 		return 0.0;
1947 
1948 	usb_device device;
1949 	if (gDeviceManager->get_attr_uint32(parent, USB_DEVICE_ID_ITEM, &device, true) != B_OK)
1950 		return -1;
1951 
1952 	const usb_configuration_info *configuration = gUSBModule->get_configuration(device);
1953 	if (configuration == NULL)
1954 		return -1;
1955 
1956 	static usb_support_descriptor supportedDevices[] = {
1957 		{ USB_MASS_STORAGE_DEVICE_CLASS, 0x06 /* SCSI */, 0x50 /* bulk */, 0, 0 },
1958 		{ USB_MASS_STORAGE_DEVICE_CLASS, 0x02 /* ATAPI */, 0x50 /* bulk */, 0, 0 },
1959 		{ USB_MASS_STORAGE_DEVICE_CLASS, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 },
1960 		{ USB_MASS_STORAGE_DEVICE_CLASS, 0x04 /* UFI */, 0x00, 0, 0 }
1961 	};
1962 
1963 	for (size_t i = 0; i < configuration->interface_count; i++) {
1964 		usb_interface_info *interface = configuration->interface[i].active;
1965 		if (interface == NULL)
1966 			continue;
1967 
1968 		for (size_t i = 0; i < B_COUNT_OF(supportedDevices); i++) {
1969 			if (interface->descr->interface_class != supportedDevices[i].dev_class)
1970 				continue;
1971 			if (interface->descr->interface_subclass != supportedDevices[i].dev_subclass)
1972 				continue;
1973 			if (interface->descr->interface_protocol != supportedDevices[i].dev_protocol)
1974 				continue;
1975 
1976 			TRACE("USB disk device found!\n");
1977 			return 0.6;
1978 		}
1979 	}
1980 
1981 	return 0.0;
1982 }
1983 
1984 
1985 static status_t
1986 usb_disk_register_device(device_node *node)
1987 {
1988 	CALLED();
1989 
1990 	device_attr attrs[] = {
1991 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "USB Disk"} },
1992 		{ NULL }
1993 	};
1994 
1995 	return gDeviceManager->register_node(node, USB_DISK_DRIVER_MODULE_NAME,
1996 		attrs, NULL, NULL);
1997 }
1998 
1999 
2000 static status_t
2001 usb_disk_init_driver(device_node *node, void **cookie)
2002 {
2003 	CALLED();
2004 
2005 	usb_device usb_device;
2006 	if (gDeviceManager->get_attr_uint32(node, USB_DEVICE_ID_ITEM, &usb_device, true) != B_OK)
2007 		return B_BAD_VALUE;
2008 
2009 	return usb_disk_attach(node, usb_device, cookie);
2010 }
2011 
2012 
2013 static void
2014 usb_disk_uninit_driver(void *_cookie)
2015 {
2016 	CALLED();
2017 	// Nothing to do.
2018 }
2019 
2020 
2021 static status_t
2022 usb_disk_register_child_devices(void* _cookie)
2023 {
2024 	CALLED();
2025 	disk_device *device = (disk_device *)_cookie;
2026 
2027 	device->number = gDeviceManager->create_id(USB_DISK_DEVICE_ID_GENERATOR);
2028 	if (device->number < 0)
2029 		return device->number;
2030 
2031 	status_t status = B_OK;
2032 	for (uint8 i = 0; i < device->lun_count; i++) {
2033 		sprintf(device->luns[i]->name, DEVICE_NAME, device->number, i);
2034 		status = gDeviceManager->publish_device(device->node, device->luns[i]->name,
2035 			USB_DISK_DEVICE_MODULE_NAME);
2036 	}
2037 
2038 	return status;
2039 }
2040 
2041 
2042 //	#pragma mark -
2043 
2044 
2045 module_dependency module_dependencies[] = {
2046 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
2047 	{ B_USB_MODULE_NAME, (module_info**)&gUSBModule},
2048 	{ NULL }
2049 };
2050 
2051 struct device_module_info sUsbDiskDevice = {
2052 	{
2053 		USB_DISK_DEVICE_MODULE_NAME,
2054 		0,
2055 		NULL
2056 	},
2057 
2058 	usb_disk_init_device,
2059 	usb_disk_uninit_device,
2060 	usb_disk_device_removed,
2061 
2062 	usb_disk_open,
2063 	usb_disk_close,
2064 	usb_disk_free,
2065 	NULL,	// read
2066 	NULL,	// write
2067 	usb_disk_io,
2068 	usb_disk_ioctl,
2069 
2070 	NULL,	// select
2071 	NULL,	// deselect
2072 };
2073 
2074 struct driver_module_info sUsbDiskDriver = {
2075 	{
2076 		USB_DISK_DRIVER_MODULE_NAME,
2077 		0,
2078 		NULL
2079 	},
2080 
2081 	usb_disk_supports_device,
2082 	usb_disk_register_device,
2083 	usb_disk_init_driver,
2084 	usb_disk_uninit_driver,
2085 	usb_disk_register_child_devices,
2086 	NULL,	// rescan
2087 	NULL,	// removed
2088 };
2089 
2090 module_info* modules[] = {
2091 	(module_info*)&sUsbDiskDriver,
2092 	(module_info*)&sUsbDiskDevice,
2093 	NULL
2094 };
2095