xref: /haiku/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
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 
1248 	// At this point, open_count should always be 0 anyway.
1249 	if (device->open_count == 0)
1250 		usb_disk_free_device_and_luns(device);
1251 	else
1252 		mutex_unlock(&device->lock);
1253 }
1254 
1255 
1256 static bool
1257 usb_disk_needs_bounce(device_lun *lun, io_request *request)
1258 {
1259 	if (!request->Buffer()->IsVirtual())
1260 		return true;
1261 	if ((request->Offset() % lun->block_size) != 0)
1262 		return true;
1263 	if ((request->Length() % lun->block_size) != 0)
1264 		return true;
1265 	if (request->Length() > (lun->block_size * MAX_IO_BLOCKS))
1266 		return true;
1267 	return false;
1268 }
1269 
1270 
1271 static status_t
1272 usb_disk_block_read(device_lun *lun, uint64 blockPosition, size_t blockCount,
1273 	struct transfer_data data, size_t *length)
1274 {
1275 	uint8 commandBlock[16];
1276 	memset(commandBlock, 0, sizeof(commandBlock));
1277 	if (lun->device->is_ufi) {
1278 		commandBlock[0] = SCSI_READ_12;
1279 		commandBlock[1] = lun->logical_unit_number << 5;
1280 		commandBlock[2] = blockPosition >> 24;
1281 		commandBlock[3] = blockPosition >> 16;
1282 		commandBlock[4] = blockPosition >> 8;
1283 		commandBlock[5] = blockPosition;
1284 		commandBlock[6] = blockCount >> 24;
1285 		commandBlock[7] = blockCount >> 16;
1286 		commandBlock[8] = blockCount >> 8;
1287 		commandBlock[9] = blockCount;
1288 
1289 		status_t result = B_OK;
1290 		for (int tries = 0; tries < 5; tries++) {
1291 			result = usb_disk_operation(lun, commandBlock, 12, data,
1292 				length, true);
1293 			if (result == B_OK)
1294 				break;
1295 			else
1296 				snooze(10000);
1297 		}
1298 		return result;
1299 	} else if (blockPosition + blockCount < 0x100000000LL && blockCount <= 0x10000) {
1300 		commandBlock[0] = SCSI_READ_10;
1301 		commandBlock[1] = 0;
1302 		commandBlock[2] = blockPosition >> 24;
1303 		commandBlock[3] = blockPosition >> 16;
1304 		commandBlock[4] = blockPosition >> 8;
1305 		commandBlock[5] = blockPosition;
1306 		commandBlock[7] = blockCount >> 8;
1307 		commandBlock[8] = blockCount;
1308 		status_t result = usb_disk_operation(lun, commandBlock, 10,
1309 			data, length, true);
1310 		return result;
1311 	} else {
1312 		commandBlock[0] = SCSI_READ_16;
1313 		commandBlock[1] = 0;
1314 		commandBlock[2] = blockPosition >> 56;
1315 		commandBlock[3] = blockPosition >> 48;
1316 		commandBlock[4] = blockPosition >> 40;
1317 		commandBlock[5] = blockPosition >> 32;
1318 		commandBlock[6] = blockPosition >> 24;
1319 		commandBlock[7] = blockPosition >> 16;
1320 		commandBlock[8] = blockPosition >> 8;
1321 		commandBlock[9] = blockPosition;
1322 		commandBlock[10] = blockCount >> 24;
1323 		commandBlock[11] = blockCount >> 16;
1324 		commandBlock[12] = blockCount >> 8;
1325 		commandBlock[13] = blockCount;
1326 		status_t result = usb_disk_operation(lun, commandBlock, 16,
1327 			data, length, true);
1328 		return result;
1329 	}
1330 }
1331 
1332 
1333 static status_t
1334 usb_disk_block_write(device_lun *lun, uint64 blockPosition, size_t blockCount,
1335 	struct transfer_data data, size_t *length)
1336 {
1337 	uint8 commandBlock[16];
1338 	memset(commandBlock, 0, sizeof(commandBlock));
1339 
1340 	if (lun->device->is_ufi) {
1341 		commandBlock[0] = SCSI_WRITE_12;
1342 		commandBlock[1] = lun->logical_unit_number << 5;
1343 		commandBlock[2] = blockPosition >> 24;
1344 		commandBlock[3] = blockPosition >> 16;
1345 		commandBlock[4] = blockPosition >> 8;
1346 		commandBlock[5] = blockPosition;
1347 		commandBlock[6] = blockCount >> 24;
1348 		commandBlock[7] = blockCount >> 16;
1349 		commandBlock[8] = blockCount >> 8;
1350 		commandBlock[9] = blockCount;
1351 
1352 		status_t result;
1353 		result = usb_disk_operation(lun, commandBlock, 12,
1354 			data, length, false);
1355 
1356 		int retry = 10;
1357 		err_act action = err_act_ok;
1358 		while (result == B_DEV_NO_MEDIA && retry > 0) {
1359 			snooze(10000);
1360 			result = usb_disk_request_sense(lun, &action);
1361 			retry--;
1362 		}
1363 
1364 		if (result == B_OK)
1365 			lun->should_sync = true;
1366 		return result;
1367 	} else if (blockPosition + blockCount < 0x100000000LL && blockCount <= 0x10000) {
1368 		commandBlock[0] = SCSI_WRITE_10;
1369 		commandBlock[2] = blockPosition >> 24;
1370 		commandBlock[3] = blockPosition >> 16;
1371 		commandBlock[4] = blockPosition >> 8;
1372 		commandBlock[5] = blockPosition;
1373 		commandBlock[7] = blockCount >> 8;
1374 		commandBlock[8] = blockCount;
1375 		status_t result = usb_disk_operation(lun, commandBlock, 10,
1376 			data, length, false);
1377 		if (result == B_OK)
1378 			lun->should_sync = true;
1379 		return result;
1380 	} else {
1381 		commandBlock[0] = SCSI_WRITE_16;
1382 		commandBlock[1] = 0;
1383 		commandBlock[2] = blockPosition >> 56;
1384 		commandBlock[3] = blockPosition >> 48;
1385 		commandBlock[4] = blockPosition >> 40;
1386 		commandBlock[5] = blockPosition >> 32;
1387 		commandBlock[6] = blockPosition >> 24;
1388 		commandBlock[7] = blockPosition >> 16;
1389 		commandBlock[8] = blockPosition >> 8;
1390 		commandBlock[9] = blockPosition;
1391 		commandBlock[10] = blockCount >> 24;
1392 		commandBlock[11] = blockCount >> 16;
1393 		commandBlock[12] = blockCount >> 8;
1394 		commandBlock[13] = blockCount;
1395 		status_t result = usb_disk_operation(lun, commandBlock, 16,
1396 			data, length, false);
1397 		if (result == B_OK)
1398 			lun->should_sync = true;
1399 		return result;
1400 	}
1401 }
1402 
1403 
1404 //
1405 //#pragma mark - Driver Hooks
1406 //
1407 
1408 
1409 static status_t
1410 usb_disk_init_device(void* _info, void** _cookie)
1411 {
1412 	CALLED();
1413 	*_cookie = _info;
1414 	return B_OK;
1415 }
1416 
1417 
1418 static void
1419 usb_disk_uninit_device(void* _cookie)
1420 {
1421 	// Nothing to do.
1422 }
1423 
1424 
1425 static status_t
1426 usb_disk_open(void *deviceCookie, const char *path, int flags, void **_cookie)
1427 {
1428 	TRACE("open(%s)\n", path);
1429 	if (strncmp(path, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0)
1430 		return B_NAME_NOT_FOUND;
1431 
1432 	int32 lastPart = 0;
1433 	size_t nameLength = strlen(path);
1434 	for (int32 i = nameLength - 1; i >= 0; i--) {
1435 		if (path[i] == '/') {
1436 			lastPart = i;
1437 			break;
1438 		}
1439 	}
1440 
1441 	char rawName[nameLength + 4];
1442 	strncpy(rawName, path, lastPart + 1);
1443 	rawName[lastPart + 1] = 0;
1444 	strcat(rawName, "raw");
1445 
1446 	disk_device *device = (disk_device *)deviceCookie;
1447 	MutexLocker locker(device->lock);
1448 	for (uint8 i = 0; i < device->lun_count; i++) {
1449 		device_lun *lun = device->luns[i];
1450 		if (strncmp(rawName, lun->name, 32) == 0) {
1451 			// found the matching device/lun
1452 			if (device->removed)
1453 				return B_ERROR;
1454 
1455 			device->open_count++;
1456 			*_cookie = lun;
1457 			return B_OK;
1458 		}
1459 	}
1460 
1461 	return B_NAME_NOT_FOUND;
1462 }
1463 
1464 
1465 static status_t
1466 usb_disk_close(void *cookie)
1467 {
1468 	TRACE("close()\n");
1469 	device_lun *lun = (device_lun *)cookie;
1470 	disk_device *device = lun->device;
1471 
1472 	RecursiveLocker ioLocker(device->io_lock);
1473 	MutexLocker deviceLocker(device->lock);
1474 
1475 	if (!device->removed)
1476 		usb_disk_synchronize(lun, false);
1477 
1478 	return B_OK;
1479 }
1480 
1481 
1482 static status_t
1483 usb_disk_free(void *cookie)
1484 {
1485 	TRACE("free()\n");
1486 
1487 	device_lun *lun = (device_lun *)cookie;
1488 	disk_device *device = lun->device;
1489 	mutex_lock(&device->lock);
1490 
1491 	device->open_count--;
1492 	if (device->open_count == 0 && device->removed) {
1493 		// we can simply free the device here as it has been removed from
1494 		// the device list in the device removed notification hook
1495 		usb_disk_free_device_and_luns(device);
1496 	} else {
1497 		mutex_unlock(&device->lock);
1498 	}
1499 
1500 	return B_OK;
1501 }
1502 
1503 
1504 static inline void
1505 normalize_name(char *name, size_t nameLength)
1506 {
1507 	bool wasSpace = false;
1508 	size_t insertIndex = 0;
1509 	for (size_t i = 0; i < nameLength; i++) {
1510 		bool isSpace = name[i] == ' ';
1511 		if (isSpace && wasSpace)
1512 			continue;
1513 
1514 		name[insertIndex++] = name[i];
1515 		wasSpace = isSpace;
1516 	}
1517 
1518 	if (insertIndex > 0 && name[insertIndex - 1] == ' ')
1519 		insertIndex--;
1520 
1521 	name[insertIndex] = 0;
1522 }
1523 
1524 
1525 static status_t
1526 acquire_io_lock(disk_device *device, MutexLocker& locker, RecursiveLocker& ioLocker)
1527 {
1528 	locker.Unlock();
1529 	ioLocker.SetTo(device->io_lock, false, true);
1530 	locker.Lock();
1531 
1532 	if (!locker.IsLocked() || !ioLocker.IsLocked())
1533 		return B_ERROR;
1534 
1535 	if (device->removed)
1536 		return B_DEV_NOT_READY;
1537 
1538 	return B_OK;
1539 }
1540 
1541 
1542 static status_t
1543 handle_media_change(device_lun *lun, MutexLocker& locker)
1544 {
1545 	RecursiveLocker ioLocker;
1546 	status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1547 	if (result != B_OK)
1548 		return result;
1549 
1550 	// It may have been handled while we were waiting for locks.
1551 	if (lun->media_changed) {
1552 		result = usb_disk_update_capacity(lun);
1553 		if (result != B_OK)
1554 			return result;
1555 	}
1556 
1557 	return B_OK;
1558 }
1559 
1560 
1561 static status_t
1562 usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
1563 {
1564 	device_lun *lun = (device_lun *)cookie;
1565 	disk_device *device = lun->device;
1566 	MutexLocker locker(&device->lock);
1567 	if (device->removed)
1568 		return B_DEV_NOT_READY;
1569 	RecursiveLocker ioLocker;
1570 
1571 	switch (op) {
1572 		case B_GET_DEVICE_SIZE:
1573 		{
1574 			if (lun->media_changed) {
1575 				status_t result = handle_media_change(lun, locker);
1576 				if (result != B_OK)
1577 					return result;
1578 			}
1579 
1580 			size_t size = lun->block_size * lun->block_count;
1581 			return user_memcpy(buffer, &size, sizeof(size));
1582 		}
1583 
1584 		case B_GET_MEDIA_STATUS:
1585 		{
1586 			status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1587 			if (result != B_OK)
1588 				return result;
1589 
1590 			err_act action = err_act_ok;
1591 			status_t ready;
1592 			for (uint32 tries = 0; tries < 3; tries++) {
1593 				ready = usb_disk_test_unit_ready(lun, &action);
1594 				if (ready == B_OK || ready == B_DEV_NO_MEDIA
1595 					|| (action != err_act_retry
1596 						&& action != err_act_many_retries)) {
1597 					if (IS_USER_ADDRESS(buffer)) {
1598 						if (user_memcpy(buffer, &ready, sizeof(status_t)) != B_OK)
1599 							return B_BAD_ADDRESS;
1600 					} else if (is_called_via_syscall()) {
1601 						return B_BAD_ADDRESS;
1602 					} else
1603 						*(status_t *)buffer = ready;
1604 					break;
1605 				}
1606 				snooze(500000);
1607 			}
1608 			TRACE("B_GET_MEDIA_STATUS: 0x%08" B_PRIx32 "\n", ready);
1609 			return B_OK;
1610 		}
1611 
1612 		case B_GET_GEOMETRY:
1613 		{
1614 			if (buffer == NULL || length > sizeof(device_geometry))
1615 				return B_BAD_VALUE;
1616 			if (lun->media_changed) {
1617 				status_t result = handle_media_change(lun, locker);
1618 				if (result != B_OK)
1619 					return result;
1620 			}
1621 
1622 			device_geometry geometry;
1623 			devfs_compute_geometry_size(&geometry, lun->block_count,
1624 				lun->block_size);
1625 			geometry.bytes_per_physical_sector = lun->physical_block_size;
1626 
1627 			geometry.device_type = lun->device_type;
1628 			geometry.removable = lun->removable;
1629 			geometry.read_only = lun->write_protected;
1630 			geometry.write_once = lun->device_type == B_WORM;
1631 			TRACE("B_GET_GEOMETRY: %" B_PRId32 " sectors at %" B_PRId32
1632 				" bytes per sector\n", geometry.cylinder_count,
1633 				geometry.bytes_per_sector);
1634 			return user_memcpy(buffer, &geometry, length);
1635 		}
1636 
1637 		case B_FLUSH_DRIVE_CACHE:
1638 		{
1639 			TRACE("B_FLUSH_DRIVE_CACHE\n");
1640 
1641 			status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1642 			if (result != B_OK)
1643 				return result;
1644 
1645 			return usb_disk_synchronize(lun, true);
1646 		}
1647 
1648 		case B_EJECT_DEVICE:
1649 		{
1650 			status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1651 			if (result != B_OK)
1652 				return result;
1653 
1654 			uint8 commandBlock[12];
1655 			memset(commandBlock, 0, sizeof(commandBlock));
1656 
1657 			commandBlock[0] = SCSI_START_STOP_UNIT_6;
1658 			commandBlock[1] = lun->logical_unit_number << 5;
1659 			commandBlock[4] = 2;
1660 
1661 			return usb_disk_operation(lun, commandBlock, 6, NULL, NULL,
1662 				false);
1663 		}
1664 
1665 		case B_LOAD_MEDIA:
1666 		{
1667 			status_t result = acquire_io_lock(lun->device, locker, ioLocker);
1668 			if (result != B_OK)
1669 				return result;
1670 
1671 			uint8 commandBlock[12];
1672 			memset(commandBlock, 0, sizeof(commandBlock));
1673 
1674 			commandBlock[0] = SCSI_START_STOP_UNIT_6;
1675 			commandBlock[1] = lun->logical_unit_number << 5;
1676 			commandBlock[4] = 3;
1677 
1678 			return usb_disk_operation(lun, commandBlock, 6, NULL, NULL,
1679 				false);
1680 		}
1681 
1682 		case B_GET_ICON:
1683 			// We don't support this legacy ioctl anymore, but the two other
1684 			// icon ioctls below instead.
1685 			break;
1686 
1687 		case B_GET_ICON_NAME:
1688 		{
1689 			const char *iconName = "devices/drive-removable-media-usb";
1690 			char vendor[sizeof(lun->vendor_name)+1];
1691 			char product[sizeof(lun->product_name)+1];
1692 
1693 			if (device->is_ufi) {
1694 				iconName = "devices/drive-floppy-usb";
1695 			}
1696 
1697 			switch (lun->device_type) {
1698 				case B_CD:
1699 				case B_OPTICAL:
1700 					iconName = "devices/drive-optical";
1701 					break;
1702 				case B_TAPE:	// TODO
1703 				default:
1704 					snprintf(vendor, sizeof(vendor), "%.8s",
1705 						lun->vendor_name);
1706 					snprintf(product, sizeof(product), "%.16s",
1707 						lun->product_name);
1708 					for (int i = 0; kIconMatches[i].icon; i++) {
1709 						if (kIconMatches[i].vendor != NULL
1710 							&& strstr(vendor, kIconMatches[i].vendor) == NULL)
1711 							continue;
1712 						if (kIconMatches[i].product != NULL
1713 							&& strstr(product, kIconMatches[i].product) == NULL)
1714 							continue;
1715 						iconName = kIconMatches[i].name;
1716 					}
1717 					break;
1718 			}
1719 			return user_strlcpy((char *)buffer, iconName,
1720 				B_FILE_NAME_LENGTH);
1721 		}
1722 
1723 		case B_GET_VECTOR_ICON:
1724 		{
1725 			device_icon *icon = &kKeyIconData;
1726 			char vendor[sizeof(lun->vendor_name)+1];
1727 			char product[sizeof(lun->product_name)+1];
1728 
1729 			if (length != sizeof(device_icon))
1730 				return B_BAD_VALUE;
1731 
1732 			if (device->is_ufi) {
1733 				// UFI is specific for floppy drives
1734 				icon = &kFloppyIconData;
1735 			} else {
1736 				switch (lun->device_type) {
1737 					case B_CD:
1738 					case B_OPTICAL:
1739 						icon = &kCDIconData;
1740 						break;
1741 					case B_TAPE:	// TODO
1742 					default:
1743 						snprintf(vendor, sizeof(vendor), "%.8s",
1744 								lun->vendor_name);
1745 						snprintf(product, sizeof(product), "%.16s",
1746 								lun->product_name);
1747 						for (int i = 0; kIconMatches[i].icon; i++) {
1748 							if (kIconMatches[i].vendor != NULL
1749 									&& strstr(vendor,
1750 										kIconMatches[i].vendor) == NULL)
1751 								continue;
1752 							if (kIconMatches[i].product != NULL
1753 									&& strstr(product,
1754 										kIconMatches[i].product) == NULL)
1755 								continue;
1756 							icon = kIconMatches[i].icon;
1757 						}
1758 						break;
1759 				}
1760 			}
1761 
1762 			device_icon iconData;
1763 			if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK)
1764 				return B_BAD_ADDRESS;
1765 
1766 			if (iconData.icon_size >= icon->icon_size) {
1767 				if (user_memcpy(iconData.icon_data, icon->icon_data,
1768 						(size_t)icon->icon_size) != B_OK)
1769 					return B_BAD_ADDRESS;
1770 			}
1771 
1772 			iconData.icon_size = icon->icon_size;
1773 			return user_memcpy(buffer, &iconData, sizeof(device_icon));
1774 		}
1775 
1776 		case B_GET_DEVICE_NAME:
1777 		{
1778 			size_t nameLength = sizeof(lun->vendor_name)
1779 				+ sizeof(lun->product_name) + sizeof(lun->product_revision) + 3;
1780 
1781 			char name[nameLength];
1782 			snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name,
1783 				lun->product_name, lun->product_revision);
1784 
1785 			normalize_name(name, nameLength);
1786 
1787 			status_t result = user_strlcpy((char *)buffer, name, length);
1788 			if (result > 0)
1789 				result = B_OK;
1790 
1791 			TRACE_ALWAYS("got device name \"%s\": %s\n", name,
1792 				strerror(result));
1793 			return result;
1794 		}
1795 	}
1796 
1797 	TRACE_ALWAYS("unhandled ioctl %" B_PRId32 "\n", op);
1798 	return B_DEV_INVALID_IOCTL;
1799 }
1800 
1801 
1802 static status_t
1803 usb_disk_bounced_io(device_lun *lun, io_request *request)
1804 {
1805 	DMAResource* dmaResource = get_dma_resource(lun->device, lun->block_size);
1806 	if (dmaResource == NULL)
1807 		return B_NO_INIT;
1808 
1809 	if (!request->Buffer()->IsPhysical()) {
1810 		status_t status = request->Buffer()->LockMemory(request->TeamID(), request->IsWrite());
1811 		if (status != B_OK) {
1812 			TRACE_ALWAYS("failed to lock memory: %s\n", strerror(status));
1813 			return status;
1814 		}
1815 		// SetStatusAndNotify() takes care of unlocking memory if necessary.
1816 	}
1817 
1818 	status_t status = B_OK;
1819 	while (request->RemainingBytes() > 0) {
1820 		IOOperation operation;
1821 		status = dmaResource->TranslateNext(request, &operation, 0);
1822 		if (status != B_OK)
1823 			break;
1824 
1825 		do {
1826 			TRACE("%p: IOO offset: %" B_PRIdOFF ", length: %" B_PRIuGENADDR
1827 				", write: %s\n", request, operation.Offset(),
1828 				operation.Length(), operation.IsWrite() ? "yes" : "no");
1829 
1830 			struct transfer_data data;
1831 			data.physical = true;
1832 			data.phys_vecs = (physical_entry*)operation.Vecs();
1833 			data.vec_count = operation.VecCount();
1834 
1835 			size_t length = operation.Length();
1836 			const uint64 blockPosition = operation.Offset() / lun->block_size;
1837 			const size_t blockCount = length / lun->block_size;
1838 			if (operation.IsWrite()) {
1839 				status = usb_disk_block_write(lun,
1840 					blockPosition, blockCount, data, &length);
1841 			} else {
1842 				status = usb_disk_block_read(lun,
1843 					blockPosition, blockCount, data, &length);
1844 			}
1845 
1846 			operation.SetStatus(status, length);
1847 		} while (status == B_OK && !operation.Finish());
1848 
1849 		if (status == B_OK && operation.Status() != B_OK) {
1850 			TRACE_ALWAYS("I/O succeeded but IOOperation failed!\n");
1851 			status = operation.Status();
1852 		}
1853 
1854 		request->OperationFinished(&operation);
1855 		dmaResource->RecycleBuffer(operation.Buffer());
1856 
1857 		TRACE("%p: status %s, remaining bytes %" B_PRIuGENADDR "\n", request,
1858 			strerror(status), request->RemainingBytes());
1859 		if (status != B_OK)
1860 			break;
1861 	}
1862 
1863 	return status;
1864 }
1865 
1866 
1867 static status_t
1868 usb_disk_direct_io(device_lun *lun, io_request *request)
1869 {
1870 	generic_io_vec* genericVecs = request->Buffer()->Vecs();
1871 	const uint32 count = request->Buffer()->VecCount();
1872 	BStackOrHeapArray<iovec, 16> vecs(count);
1873 	for (uint32 i = 0; i < count; i++) {
1874 		vecs[i].iov_base = (void*)genericVecs[i].base;
1875 		vecs[i].iov_len = genericVecs[i].length;
1876 	}
1877 	struct transfer_data data;
1878 	data.vecs = vecs;
1879 	data.vec_count = count;
1880 
1881 	size_t length = request->Length();
1882 	const uint64 blockPosition = request->Offset() / lun->block_size;
1883 	const size_t blockCount = length / lun->block_size;
1884 
1885 	status_t status;
1886 	if (request->IsWrite()) {
1887 		 status = usb_disk_block_write(lun,
1888 			blockPosition, blockCount, data, &length);
1889 	} else {
1890 		status = usb_disk_block_read(lun,
1891 			blockPosition, blockCount, data, &length);
1892 	}
1893 
1894 	request->SetTransferredBytes(length != request->Length(), length);
1895 	return status;
1896 }
1897 
1898 
1899 static status_t
1900 usb_disk_io(void *cookie, io_request *request)
1901 {
1902 	TRACE("io(%p)\n", request);
1903 
1904 	device_lun *lun = (device_lun *)cookie;
1905 	disk_device *device = lun->device;
1906 
1907 	RecursiveLocker ioLocker(device->io_lock);
1908 	MutexLocker deviceLocker(device->lock);
1909 
1910 	if (device->removed)
1911 		return B_DEV_NOT_READY;
1912 
1913 	status_t status;
1914 	if (!usb_disk_needs_bounce(lun, request)) {
1915 		status = usb_disk_direct_io(lun, request);
1916 	} else {
1917 		status = usb_disk_bounced_io(lun, request);
1918 	}
1919 
1920 	deviceLocker.Unlock();
1921 	ioLocker.Unlock();
1922 
1923 	if (request->Status() > 0)
1924 		request->SetStatusAndNotify(status);
1925 	else
1926 		request->NotifyFinished();
1927 	return status;
1928 }
1929 
1930 
1931 //	#pragma mark - driver module API
1932 
1933 
1934 static float
1935 usb_disk_supports_device(device_node *parent)
1936 {
1937 	CALLED();
1938 	const char *bus;
1939 
1940 	// make sure parent is really the usb bus manager
1941 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
1942 		return -1;
1943 	if (strcmp(bus, "usb") != 0)
1944 		return 0.0;
1945 
1946 	usb_device device;
1947 	if (gDeviceManager->get_attr_uint32(parent, USB_DEVICE_ID_ITEM, &device, true) != B_OK)
1948 		return -1;
1949 
1950 	const usb_configuration_info *configuration = gUSBModule->get_configuration(device);
1951 	if (configuration == NULL)
1952 		return -1;
1953 
1954 	static usb_support_descriptor supportedDevices[] = {
1955 		{ USB_MASS_STORAGE_DEVICE_CLASS, 0x06 /* SCSI */, 0x50 /* bulk */, 0, 0 },
1956 		{ USB_MASS_STORAGE_DEVICE_CLASS, 0x02 /* ATAPI */, 0x50 /* bulk */, 0, 0 },
1957 		{ USB_MASS_STORAGE_DEVICE_CLASS, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 },
1958 		{ USB_MASS_STORAGE_DEVICE_CLASS, 0x04 /* UFI */, 0x00, 0, 0 }
1959 	};
1960 
1961 	for (size_t i = 0; i < configuration->interface_count; i++) {
1962 		usb_interface_info *interface = configuration->interface[i].active;
1963 		if (interface == NULL)
1964 			continue;
1965 
1966 		for (size_t i = 0; i < B_COUNT_OF(supportedDevices); i++) {
1967 			if (interface->descr->interface_class != supportedDevices[i].dev_class)
1968 				continue;
1969 			if (interface->descr->interface_subclass != supportedDevices[i].dev_subclass)
1970 				continue;
1971 			if (interface->descr->interface_protocol != supportedDevices[i].dev_protocol)
1972 				continue;
1973 
1974 			TRACE("USB disk device found!\n");
1975 			return 0.6;
1976 		}
1977 	}
1978 
1979 	return 0.0;
1980 }
1981 
1982 
1983 static status_t
1984 usb_disk_register_device(device_node *node)
1985 {
1986 	CALLED();
1987 
1988 	device_attr attrs[] = {
1989 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "USB Disk"} },
1990 		{ NULL }
1991 	};
1992 
1993 	return gDeviceManager->register_node(node, USB_DISK_DRIVER_MODULE_NAME,
1994 		attrs, NULL, NULL);
1995 }
1996 
1997 
1998 static status_t
1999 usb_disk_init_driver(device_node *node, void **cookie)
2000 {
2001 	CALLED();
2002 
2003 	usb_device usb_device;
2004 	if (gDeviceManager->get_attr_uint32(node, USB_DEVICE_ID_ITEM, &usb_device, true) != B_OK)
2005 		return B_BAD_VALUE;
2006 
2007 	return usb_disk_attach(node, usb_device, cookie);
2008 }
2009 
2010 
2011 static void
2012 usb_disk_uninit_driver(void *_cookie)
2013 {
2014 	CALLED();
2015 	// Nothing to do.
2016 }
2017 
2018 
2019 static status_t
2020 usb_disk_register_child_devices(void* _cookie)
2021 {
2022 	CALLED();
2023 	disk_device *device = (disk_device *)_cookie;
2024 
2025 	device->number = gDeviceManager->create_id(USB_DISK_DEVICE_ID_GENERATOR);
2026 	if (device->number < 0)
2027 		return device->number;
2028 
2029 	status_t status = B_OK;
2030 	for (uint8 i = 0; i < device->lun_count; i++) {
2031 		sprintf(device->luns[i]->name, DEVICE_NAME, device->number, i);
2032 		status = gDeviceManager->publish_device(device->node, device->luns[i]->name,
2033 			USB_DISK_DEVICE_MODULE_NAME);
2034 	}
2035 
2036 	return status;
2037 }
2038 
2039 
2040 //	#pragma mark -
2041 
2042 
2043 module_dependency module_dependencies[] = {
2044 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
2045 	{ B_USB_MODULE_NAME, (module_info**)&gUSBModule},
2046 	{ NULL }
2047 };
2048 
2049 struct device_module_info sUsbDiskDevice = {
2050 	{
2051 		USB_DISK_DEVICE_MODULE_NAME,
2052 		0,
2053 		NULL
2054 	},
2055 
2056 	usb_disk_init_device,
2057 	usb_disk_uninit_device,
2058 	usb_disk_device_removed,
2059 
2060 	usb_disk_open,
2061 	usb_disk_close,
2062 	usb_disk_free,
2063 	NULL,	// read
2064 	NULL,	// write
2065 	usb_disk_io,
2066 	usb_disk_ioctl,
2067 
2068 	NULL,	// select
2069 	NULL,	// deselect
2070 };
2071 
2072 struct driver_module_info sUsbDiskDriver = {
2073 	{
2074 		USB_DISK_DRIVER_MODULE_NAME,
2075 		0,
2076 		NULL
2077 	},
2078 
2079 	usb_disk_supports_device,
2080 	usb_disk_register_device,
2081 	usb_disk_init_driver,
2082 	usb_disk_uninit_driver,
2083 	usb_disk_register_child_devices,
2084 	NULL,	// rescan
2085 	NULL,	// removed
2086 };
2087 
2088 module_info* modules[] = {
2089 	(module_info*)&sUsbDiskDriver,
2090 	(module_info*)&sUsbDiskDevice,
2091 	NULL
2092 };
2093