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