xref: /haiku/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp (revision 06ed40580339e21f65c24b3d210c880dcf2ec739)
1 /*
2  * Copyright 2008-2012, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 
10 #include "usb_disk.h"
11 
12 #include <ByteOrder.h>
13 #include <Drivers.h>
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include <fs/devfs.h>
20 
21 #include "scsi_sense.h"
22 #include "usb_disk_scsi.h"
23 
24 
25 #define DRIVER_NAME			"usb_disk"
26 #define DEVICE_NAME_BASE	"disk/usb/"
27 #define DEVICE_NAME			DEVICE_NAME_BASE"%" B_PRIu32 "/%d/raw"
28 
29 
30 //#define TRACE_USB_DISK
31 #ifdef TRACE_USB_DISK
32 #define TRACE(x...)			dprintf(DRIVER_NAME ": " x)
33 #define TRACE_ALWAYS(x...)	dprintf(DRIVER_NAME ": " x)
34 #else
35 #define TRACE(x...)			/* nothing */
36 #define TRACE_ALWAYS(x...)	dprintf(DRIVER_NAME ": " x)
37 #endif
38 
39 
40 int32 api_version = B_CUR_DRIVER_API_VERSION;
41 static usb_module_info *gUSBModule = NULL;
42 static disk_device *gDeviceList = NULL;
43 static uint32 gDeviceCount = 0;
44 static uint32 gLunCount = 0;
45 static mutex gDeviceListLock;
46 static char **gDeviceNames = NULL;
47 
48 static uint8 kDeviceIcon[] = {
49 	0x6e, 0x63, 0x69, 0x66, 0x0a, 0x04, 0x01, 0x73, 0x05, 0x01, 0x02, 0x01,
50 	0x06, 0x02, 0xb1, 0xf8, 0x5d, 0x3a, 0x2f, 0xbf, 0xbe, 0xdb, 0x67, 0xb6,
51 	0x98, 0x06, 0x4b, 0x22, 0x15, 0x47, 0x13, 0x02, 0x00, 0xed, 0xed, 0xed,
52 	0xff, 0xab, 0xbc, 0xc6, 0x02, 0x01, 0x06, 0x02, 0xb9, 0x82, 0x56, 0x32,
53 	0x7d, 0xfb, 0xb8, 0x06, 0x39, 0xbe, 0xd9, 0xb5, 0x4b, 0x7d, 0x31, 0x4a,
54 	0xa4, 0xe7, 0x00, 0xd1, 0xde, 0xe4, 0xff, 0x7a, 0x9c, 0xae, 0x02, 0x00,
55 	0x16, 0x02, 0x38, 0xe9, 0xaa, 0x3b, 0x7b, 0x1d, 0xbf, 0xb0, 0xa6, 0x3d,
56 	0x16, 0x76, 0x4b, 0x84, 0x81, 0x48, 0x37, 0x36, 0x00, 0x99, 0xff, 0x53,
57 	0x02, 0x00, 0x16, 0x02, 0xba, 0x38, 0x9a, 0xb8, 0xef, 0x79, 0x3e, 0x34,
58 	0x8b, 0xbf, 0x56, 0x52, 0x48, 0x2c, 0x61, 0x4c, 0x4e, 0xec, 0x00, 0x40,
59 	0xff, 0x01, 0x05, 0xff, 0x05, 0x46, 0x02, 0x01, 0x16, 0x02, 0x35, 0xc2,
60 	0x71, 0x3a, 0xf6, 0x84, 0xb9, 0xf3, 0x5b, 0x34, 0x81, 0xa0, 0x49, 0xc0,
61 	0x57, 0x49, 0x6e, 0x51, 0xff, 0xf3, 0x00, 0x52, 0x02, 0x01, 0x06, 0x02,
62 	0x38, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x80, 0x00,
63 	0x49, 0xa0, 0x00, 0x49, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x06,
64 	0xe3, 0x06, 0x0c, 0x06, 0x09, 0xab, 0xaa, 0x03, 0x3e, 0x5e, 0x3c, 0x5f,
65 	0x3e, 0x5e, 0x60, 0x4d, 0x5a, 0x4a, 0x60, 0x47, 0x56, 0x42, 0x50, 0x45,
66 	0x4c, 0x43, 0x2a, 0x54, 0x36, 0x5d, 0x36, 0x5d, 0x3a, 0x60, 0x06, 0x08,
67 	0xfb, 0xea, 0x27, 0x49, 0x26, 0x48, 0x27, 0x49, 0x32, 0x56, 0x37, 0x59,
68 	0x37, 0x59, 0x38, 0x5a, 0x3b, 0x59, 0x3a, 0x5a, 0x3b, 0x59, 0x58, 0x3c,
69 	0x52, 0x36, 0x43, 0x29, 0x27, 0x45, 0x27, 0x45, 0x26, 0x46, 0x06, 0x05,
70 	0xab, 0x03, 0x27, 0x49, 0x26, 0x48, 0x27, 0x49, 0x32, 0x56, 0x52, 0x36,
71 	0x43, 0x29, 0x27, 0x45, 0x27, 0x45, 0x26, 0x46, 0x0a, 0x05, 0xc2, 0x1c,
72 	0xb8, 0xf9, 0x4f, 0x25, 0xc9, 0x4c, 0xb7, 0xc4, 0x5a, 0x30, 0x51, 0x39,
73 	0x0a, 0x04, 0xc5, 0x50, 0xbb, 0xc0, 0xc2, 0x1c, 0xb8, 0xf9, 0x4f, 0x25,
74 	0xc9, 0x4c, 0xb7, 0xc4, 0x0a, 0x04, 0x51, 0x39, 0xc5, 0x50, 0xbb, 0xc0,
75 	0xc9, 0x4c, 0xb7, 0xc4, 0x5a, 0x30, 0x0a, 0x04, 0x4f, 0x2f, 0x51, 0x31,
76 	0x53, 0x2f, 0x51, 0x2d, 0x06, 0x04, 0xee, 0x4f, 0x35, 0x53, 0x30, 0x51,
77 	0x32, 0x55, 0x2e, 0x58, 0x2c, 0x54, 0x31, 0x56, 0x2f, 0x52, 0x33, 0x06,
78 	0x04, 0xee, 0x31, 0x58, 0x40, 0x47, 0x39, 0x4e, 0x47, 0x40, 0x50, 0x38,
79 	0x41, 0x48, 0x48, 0x41, 0x3a, 0x4f, 0x08, 0x02, 0x3a, 0x40, 0x3e, 0x3c,
80 	0x02, 0x04, 0x3e, 0x3a, 0xbe, 0x48, 0x3a, 0xbf, 0x9f, 0x3a, 0x41, 0x3d,
81 	0x41, 0xbd, 0xe2, 0x41, 0xbf, 0x39, 0x3e, 0x40, 0xbf, 0x9f, 0x40, 0xbe,
82 	0x48, 0x40, 0x3b, 0x3d, 0x3b, 0xbf, 0x39, 0x3b, 0xbd, 0xe2, 0x06, 0x05,
83 	0xbe, 0x02, 0x32, 0x56, 0x36, 0x5a, 0x36, 0x5a, 0x37, 0x5b, 0x3a, 0x5a,
84 	0x39, 0x5b, 0x3a, 0x5a, 0x58, 0x3c, 0x52, 0x36, 0x11, 0x0a, 0x00, 0x01,
85 	0x00, 0x00, 0x0a, 0x01, 0x01, 0x03, 0x12, 0x3f, 0xe9, 0x8e, 0xbb, 0x54,
86 	0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0x4d, 0xd9, 0x45, 0xc0,
87 	0xc5, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x02, 0x01, 0x04, 0x02, 0x3f,
88 	0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6,
89 	0x4d, 0xd9, 0x45, 0xc0, 0xc5, 0x0a, 0x03, 0x01, 0x05, 0x02, 0x3f, 0xe9,
90 	0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0x4d,
91 	0xd9, 0x45, 0xc0, 0xc5, 0x0a, 0x01, 0x01, 0x01, 0x12, 0x3f, 0xe9, 0x8e,
92 	0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0xb0, 0x64,
93 	0x46, 0x78, 0x3b, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x04, 0x01, 0x02,
94 	0x02, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9,
95 	0x8e, 0xc6, 0xb0, 0x64, 0x46, 0x78, 0x3b, 0x0a, 0x05, 0x01, 0x0b, 0x02,
96 	0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e,
97 	0xc6, 0xb0, 0x64, 0x46, 0x78, 0x3b, 0x0a, 0x01, 0x01, 0x06, 0x02, 0x3f,
98 	0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6,
99 	0x5b, 0x2d, 0x45, 0x43, 0x93, 0x0a, 0x01, 0x01, 0x06, 0x02, 0x3f, 0xe9,
100 	0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc7, 0x7d,
101 	0x8b, 0x44, 0x36, 0x9a, 0x0a, 0x06, 0x02, 0x07, 0x08, 0x02, 0x3f, 0xe9,
102 	0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0x4d,
103 	0xd9, 0x45, 0xc0, 0xc5, 0x0a, 0x01, 0x01, 0x09, 0x12, 0x3f, 0x6c, 0x5c,
104 	0xba, 0xea, 0x46, 0x3a, 0xea, 0x46, 0x3f, 0x6c, 0x5c, 0xc5, 0x19, 0x6c,
105 	0x46, 0x6b, 0x36, 0x01, 0x17, 0x8c, 0x22, 0x04, 0x0a, 0x07, 0x01, 0x09,
106 	0x12, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9,
107 	0x8e, 0xc6, 0x4d, 0xd9, 0x45, 0xc0, 0xc5, 0x01, 0x17, 0x88, 0x22, 0x04,
108 	0x0a, 0x08, 0x01, 0x09, 0x12, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b,
109 	0x54, 0xe2, 0x3f, 0xe9, 0x8e, 0xc6, 0x01, 0xed, 0x46, 0x11, 0xa8, 0x01,
110 	0x17, 0x85, 0x22, 0x04, 0x0a, 0x01, 0x01, 0x0a, 0x12, 0x3f, 0xe9, 0x8e,
111 	0xbb, 0x54, 0xe2, 0x3a, 0xaa, 0x52, 0x3f, 0x21, 0x43, 0xc6, 0x59, 0xd0,
112 	0x46, 0xdb, 0x8c, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x06, 0x01, 0x0a,
113 	0x02, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54, 0xe2, 0x3f, 0xe9,
114 	0x8e, 0xc6, 0x99, 0xc6, 0x45, 0x5e, 0x3a, 0x0a, 0x01, 0x01, 0x0a, 0x12,
115 	0x3f, 0x21, 0x43, 0xba, 0xaa, 0x52, 0x3a, 0xaa, 0x52, 0x3f, 0x21, 0x43,
116 	0xc7, 0xd2, 0xa7, 0x49, 0x5f, 0xed, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a,
117 	0x09, 0x01, 0x0a, 0x02, 0x3f, 0xe9, 0x8e, 0xbb, 0x54, 0xe2, 0x3b, 0x54,
118 	0xe2, 0x3f, 0xe9, 0x8e, 0xc8, 0xa5, 0xc8, 0x48, 0xeb, 0x05
119 };
120 
121 
122 //
123 //#pragma mark - Forward Declarations
124 //
125 
126 
127 static void	usb_disk_callback(void *cookie, status_t status, void *data,
128 				size_t actualLength);
129 
130 status_t	usb_disk_mass_storage_reset(disk_device *device);
131 uint8		usb_disk_get_max_lun(disk_device *device);
132 void		usb_disk_reset_recovery(disk_device *device);
133 status_t	usb_disk_transfer_data(disk_device *device, bool directionIn,
134 				void *data, size_t dataLength);
135 status_t	usb_disk_receive_csw(disk_device *device,
136 				command_status_wrapper *status);
137 status_t	usb_disk_operation(device_lun *lun, uint8 operation,
138 				uint8 opLength, uint32 logicalBlockAddress,
139 				uint16 transferLength, void *data, size_t *dataLength,
140 				bool directionIn, err_act *action = NULL);
141 
142 status_t	usb_disk_request_sense(device_lun *lun, err_act *action);
143 status_t	usb_disk_mode_sense(device_lun *lun);
144 status_t	usb_disk_test_unit_ready(device_lun *lun, err_act *action = NULL);
145 status_t	usb_disk_inquiry(device_lun *lun);
146 status_t	usb_disk_reset_capacity(device_lun *lun);
147 status_t	usb_disk_update_capacity(device_lun *lun);
148 status_t	usb_disk_synchronize(device_lun *lun, bool force);
149 
150 
151 //
152 //#pragma mark - Device Allocation Helper Functions
153 //
154 
155 
156 void
157 usb_disk_free_device_and_luns(disk_device *device)
158 {
159 	mutex_lock(&device->lock);
160 	mutex_destroy(&device->lock);
161 	delete_sem(device->notify);
162 	for (uint8 i = 0; i < device->lun_count; i++)
163 		free(device->luns[i]);
164 	free(device->luns);
165 	free(device);
166 }
167 
168 
169 //
170 //#pragma mark - Bulk-only Mass Storage Functions
171 //
172 
173 
174 status_t
175 usb_disk_mass_storage_reset(disk_device *device)
176 {
177 	return gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_OUT
178 		| USB_REQTYPE_CLASS, REQUEST_MASS_STORAGE_RESET, 0x0000,
179 		device->interface, 0, NULL, NULL);
180 }
181 
182 
183 uint8
184 usb_disk_get_max_lun(disk_device *device)
185 {
186 	uint8 result = 0;
187 	size_t actualLength = 0;
188 
189 	// devices that do not support multiple LUNs may stall this request
190 	if (gUSBModule->send_request(device->device, USB_REQTYPE_INTERFACE_IN
191 		| USB_REQTYPE_CLASS, REQUEST_GET_MAX_LUN, 0x0000, device->interface,
192 		1, &result, &actualLength) != B_OK || actualLength != 1)
193 		return 0;
194 
195 	if (result > MAX_LOGICAL_UNIT_NUMBER) {
196 		// invalid max lun
197 		return 0;
198 	}
199 
200 	return result;
201 }
202 
203 
204 void
205 usb_disk_reset_recovery(disk_device *device)
206 {
207 	usb_disk_mass_storage_reset(device);
208 	gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT);
209 	gUSBModule->clear_feature(device->bulk_out, USB_FEATURE_ENDPOINT_HALT);
210 }
211 
212 
213 status_t
214 usb_disk_transfer_data(disk_device *device, bool directionIn, void *data,
215 	size_t dataLength)
216 {
217 	status_t result = gUSBModule->queue_bulk(directionIn ? device->bulk_in
218 		: device->bulk_out, data, dataLength, usb_disk_callback, device);
219 	if (result != B_OK) {
220 		TRACE_ALWAYS("failed to queue data transfer: %s\n", strerror(result));
221 		return result;
222 	}
223 
224 	do {
225 		result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT,
226 			10 * 1000 * 1000);
227 		if (result == B_TIMED_OUT) {
228 			// Cancel the transfer and collect the sem that should now be
229 			// released through the callback on cancel. Handling of device
230 			// reset is done in usb_disk_operation() when it detects that
231 			// the transfer failed.
232 			gUSBModule->cancel_queued_transfers(directionIn ? device->bulk_in
233 				: device->bulk_out);
234 			acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 0);
235 		}
236 	} while (result == B_INTERRUPTED);
237 
238 	if (result != B_OK) {
239 		TRACE_ALWAYS("acquire_sem failed while waiting for data transfer: %s\n",
240 			strerror(result));
241 		return result;
242 	}
243 
244 	return B_OK;
245 }
246 
247 
248 status_t
249 usb_disk_receive_csw(disk_device *device, command_status_wrapper *status)
250 {
251 	status_t result = usb_disk_transfer_data(device, true, status,
252 		sizeof(command_status_wrapper));
253 	if (result != B_OK)
254 		return result;
255 
256 	if (device->status != B_OK
257 		|| device->actual_length != sizeof(command_status_wrapper)) {
258 		// receiving the command status wrapper failed
259 		return B_ERROR;
260 	}
261 
262 	return B_OK;
263 }
264 
265 
266 status_t
267 usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength,
268 	uint32 logicalBlockAddress, uint16 transferLength, void *data,
269 	size_t *dataLength, bool directionIn, err_act *_action)
270 {
271 	TRACE("operation: lun: %u; op: %u; oplen: %u; lba: %" B_PRIu32
272 		"; tlen: %u; data: %p; dlen: %p (%lu); in: %c\n",
273 		lun->logical_unit_number, operation, opLength, logicalBlockAddress,
274 		transferLength, data, dataLength, dataLength ? *dataLength : 0,
275 		directionIn ? 'y' : 'n');
276 
277 	disk_device *device = lun->device;
278 	command_block_wrapper command;
279 	command.signature = CBW_SIGNATURE;
280 	command.tag = device->current_tag++;
281 	command.data_transfer_length = (dataLength != NULL ? *dataLength : 0);
282 	command.flags = (directionIn ? CBW_DATA_INPUT : CBW_DATA_OUTPUT);
283 	command.lun = lun->logical_unit_number;
284 	command.command_block_length
285 		= device->is_atapi ? ATAPI_COMMAND_LENGTH : opLength;
286 	memset(command.command_block, 0, sizeof(command.command_block));
287 
288 	switch (opLength) {
289 		case 6:
290 		{
291 			scsi_command_6 *commandBlock
292 				= (scsi_command_6 *)command.command_block;
293 			commandBlock->operation = operation;
294 			commandBlock->lun = lun->logical_unit_number << 5;
295 			commandBlock->allocation_length = (uint8)transferLength;
296 			if (operation == SCSI_MODE_SENSE_6) {
297 				// we hijack the lba argument to transport the desired page
298 				commandBlock->reserved[1] = (uint8)logicalBlockAddress;
299 			}
300 			break;
301 		}
302 
303 		case 10:
304 		{
305 			scsi_command_10 *commandBlock
306 				= (scsi_command_10 *)command.command_block;
307 			commandBlock->operation = operation;
308 			commandBlock->lun_flags = lun->logical_unit_number << 5;
309 			commandBlock->logical_block_address = htonl(logicalBlockAddress);
310 			commandBlock->transfer_length = htons(transferLength);
311 			break;
312 		}
313 
314 		default:
315 			TRACE_ALWAYS("unsupported operation length %d\n", opLength);
316 			return B_BAD_VALUE;
317 	}
318 
319 	status_t result = usb_disk_transfer_data(device, false, &command,
320 		sizeof(command_block_wrapper));
321 	if (result != B_OK)
322 		return result;
323 
324 	if (device->status != B_OK ||
325 		device->actual_length != sizeof(command_block_wrapper)) {
326 		// sending the command block wrapper failed
327 		TRACE_ALWAYS("sending the command block wrapper failed: %s\n",
328 			strerror(device->status));
329 		usb_disk_reset_recovery(device);
330 		return B_ERROR;
331 	}
332 
333 	size_t transferedData = 0;
334 	if (data != NULL && dataLength != NULL && *dataLength > 0) {
335 		// we have data to transfer in a data stage
336 		result = usb_disk_transfer_data(device, directionIn, data,
337 			*dataLength);
338 		if (result != B_OK)
339 			return result;
340 
341 		transferedData = device->actual_length;
342 		if (device->status != B_OK || transferedData != *dataLength) {
343 			// sending or receiving of the data failed
344 			if (device->status == B_DEV_STALLED) {
345 				TRACE("stall while transfering data\n");
346 				gUSBModule->clear_feature(directionIn ? device->bulk_in
347 					: device->bulk_out, USB_FEATURE_ENDPOINT_HALT);
348 			} else {
349 				TRACE_ALWAYS("sending or receiving of the data failed: %s\n",
350 					strerror(device->status));
351 				usb_disk_reset_recovery(device);
352 				return B_ERROR;
353 			}
354 		}
355 	}
356 
357 	command_status_wrapper status;
358 	result =  usb_disk_receive_csw(device, &status);
359 	if (result != B_OK) {
360 		// in case of a stall or error clear the stall and try again
361 		gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT);
362 		result = usb_disk_receive_csw(device, &status);
363 	}
364 
365 	if (result != B_OK) {
366 		TRACE_ALWAYS("receiving the command status wrapper failed: %s\n",
367 			strerror(result));
368 		usb_disk_reset_recovery(device);
369 		return result;
370 	}
371 
372 	if (status.signature != CSW_SIGNATURE || status.tag != command.tag) {
373 		// the command status wrapper is not valid
374 		TRACE_ALWAYS("command status wrapper is not valid: %#" B_PRIx32 "\n",
375 			status.signature);
376 		usb_disk_reset_recovery(device);
377 		return B_ERROR;
378 	}
379 
380 	switch (status.status) {
381 		case CSW_STATUS_COMMAND_PASSED:
382 		case CSW_STATUS_COMMAND_FAILED:
383 		{
384 			// The residue from "status.data_residue" is not maintained
385 			// correctly by some devices, so calculate it instead.
386 			uint32 residue = command.data_transfer_length - transferedData;
387 
388 			if (dataLength != NULL) {
389 				*dataLength -= residue;
390 				if (transferedData < *dataLength) {
391 					TRACE_ALWAYS("less data transfered than indicated: %"
392 						B_PRIuSIZE " vs. %" B_PRIuSIZE "\n", transferedData,
393 						*dataLength);
394 					*dataLength = transferedData;
395 				}
396 			}
397 
398 			if (status.status == CSW_STATUS_COMMAND_PASSED) {
399 				// the operation is complete and has succeeded
400 				return B_OK;
401 			} else {
402 				if (operation == SCSI_REQUEST_SENSE_6)
403 					return B_ERROR;
404 
405 				// the operation is complete but has failed at the SCSI level
406 				if (operation != SCSI_TEST_UNIT_READY_6) {
407 					TRACE_ALWAYS("operation %#" B_PRIx8
408 						" failed at the SCSI level\n", operation);
409 				}
410 
411 				result = usb_disk_request_sense(lun, _action);
412 				return result == B_OK ? B_ERROR : result;
413 			}
414 		}
415 
416 		case CSW_STATUS_PHASE_ERROR:
417 		{
418 			// a protocol or device error occured
419 			TRACE_ALWAYS("phase error in operation %#" B_PRIx8 "\n", operation);
420 			usb_disk_reset_recovery(device);
421 			return B_ERROR;
422 		}
423 
424 		default:
425 		{
426 			// command status wrapper is not meaningful
427 			TRACE_ALWAYS("command status wrapper has invalid status\n");
428 			usb_disk_reset_recovery(device);
429 			return B_ERROR;
430 		}
431 	}
432 }
433 
434 
435 //
436 //#pragma mark - Helper/Convenience Functions
437 //
438 
439 
440 status_t
441 usb_disk_request_sense(device_lun *lun, err_act *_action)
442 {
443 	size_t dataLength = sizeof(scsi_request_sense_6_parameter);
444 	scsi_request_sense_6_parameter parameter;
445 	status_t result = usb_disk_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0,
446 		dataLength, &parameter, &dataLength, true);
447 	if (result != B_OK) {
448 		TRACE_ALWAYS("getting request sense data failed: %s\n",
449 			strerror(result));
450 		return result;
451 	}
452 
453 	const char *label = NULL;
454 	err_act action = err_act_fail;
455 	status_t status = B_ERROR;
456 	scsi_get_sense_asc_info((parameter.additional_sense_code << 8)
457 		| parameter.additional_sense_code_qualifier, &label, &action,
458 		&status);
459 
460 	if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY
461 		&& parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) {
462 		TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: "
463 			"0x%02x; %s\n", parameter.sense_key, parameter.additional_sense_code,
464 			parameter.additional_sense_code_qualifier,
465 			label ? label : "(unknown)");
466 	}
467 
468 	if ((parameter.additional_sense_code == 0
469 			&& parameter.additional_sense_code_qualifier == 0)
470 		|| label == NULL) {
471 		scsi_get_sense_key_info(parameter.sense_key, &label, &action, &status);
472 	}
473 
474 	if (status == B_DEV_MEDIA_CHANGED) {
475 		lun->media_changed = true;
476 		lun->media_present = true;
477 	} else if (parameter.sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION
478 		&& status != B_DEV_NO_MEDIA) {
479 		lun->media_present = true;
480 	} else if (status == B_DEV_NOT_READY) {
481 		lun->media_present = false;
482 		usb_disk_reset_capacity(lun);
483 	}
484 
485 	if (_action != NULL)
486 		*_action = action;
487 
488 	return status;
489 }
490 
491 
492 status_t
493 usb_disk_mode_sense(device_lun *lun)
494 {
495 	size_t dataLength = sizeof(scsi_mode_sense_6_parameter);
496 	scsi_mode_sense_6_parameter parameter;
497 	status_t result = usb_disk_operation(lun, SCSI_MODE_SENSE_6, 6,
498 		SCSI_MODE_PAGE_DEVICE_CONFIGURATION, dataLength, &parameter,
499 		&dataLength, true);
500 	if (result != B_OK) {
501 		TRACE_ALWAYS("getting mode sense data failed: %s\n", strerror(result));
502 		return result;
503 	}
504 
505 	lun->write_protected
506 		= (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT)
507 			!= 0;
508 	TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no");
509 	return B_OK;
510 }
511 
512 
513 status_t
514 usb_disk_test_unit_ready(device_lun *lun, err_act *_action)
515 {
516 	// if unsupported we assume the unit is fixed and therefore always ok
517 	if (!lun->device->tur_supported)
518 		return B_OK;
519 
520 	status_t result;
521 	if (lun->device->is_atapi) {
522 		result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 1,
523 			NULL, NULL, false, _action);
524 	} else {
525 		result = usb_disk_operation(lun, SCSI_TEST_UNIT_READY_6, 6, 0, 0,
526 			NULL, NULL, true, _action);
527 	}
528 
529 	if (result == B_DEV_INVALID_IOCTL) {
530 		lun->device->tur_supported = false;
531 		return B_OK;
532 	}
533 
534 	return result;
535 }
536 
537 
538 status_t
539 usb_disk_inquiry(device_lun *lun)
540 {
541 	size_t dataLength = sizeof(scsi_inquiry_6_parameter);
542 	scsi_inquiry_6_parameter parameter;
543 	status_t result = B_ERROR;
544 	err_act action = err_act_ok;
545 	for (uint32 tries = 0; tries < 3; tries++) {
546 		result = usb_disk_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength,
547 			&parameter, &dataLength, true, &action);
548 		if (result == B_OK || (action != err_act_retry
549 				&& action != err_act_many_retries)) {
550 			break;
551 		}
552 	}
553 	if (result != B_OK) {
554 		TRACE_ALWAYS("getting inquiry data failed: %s\n", strerror(result));
555 		lun->device_type = B_DISK;
556 		lun->removable = true;
557 		return result;
558 	}
559 
560 	TRACE("peripherial_device_type  0x%02x\n",
561 		parameter.peripherial_device_type);
562 	TRACE("peripherial_qualifier    0x%02x\n",
563 		parameter.peripherial_qualifier);
564 	TRACE("removable_medium         %s\n",
565 		parameter.removable_medium ? "yes" : "no");
566 	TRACE("version                  0x%02x\n", parameter.version);
567 	TRACE("response_data_format     0x%02x\n", parameter.response_data_format);
568 	TRACE_ALWAYS("vendor_identification    \"%.8s\"\n",
569 		parameter.vendor_identification);
570 	TRACE_ALWAYS("product_identification   \"%.16s\"\n",
571 		parameter.product_identification);
572 	TRACE_ALWAYS("product_revision_level   \"%.4s\"\n",
573 		parameter.product_revision_level);
574 
575 	memcpy(lun->vendor_name, parameter.vendor_identification,
576 		MIN(sizeof(lun->vendor_name), sizeof(parameter.vendor_identification)));
577 	memcpy(lun->product_name, parameter.product_identification,
578 		MIN(sizeof(lun->product_name),
579 			sizeof(parameter.product_identification)));
580 	memcpy(lun->product_revision, parameter.product_revision_level,
581 		MIN(sizeof(lun->product_revision),
582 			sizeof(parameter.product_revision_level)));
583 
584 	lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */
585 	lun->removable = (parameter.removable_medium == 1);
586 	return B_OK;
587 }
588 
589 
590 status_t
591 usb_disk_reset_capacity(device_lun *lun)
592 {
593 	lun->block_size = 512;
594 	lun->block_count = 0;
595 	return B_OK;
596 }
597 
598 
599 status_t
600 usb_disk_update_capacity(device_lun *lun)
601 {
602 	size_t dataLength = sizeof(scsi_read_capacity_10_parameter);
603 	scsi_read_capacity_10_parameter parameter;
604 	status_t result = B_ERROR;
605 	err_act action = err_act_ok;
606 
607 	// Retry reading the capacity up to three times. The first try might only
608 	// yield a unit attention telling us that the device or media status
609 	// changed, which is more or less expected if it is the first operation
610 	// on the device or the device only clears the unit atention for capacity
611 	// reads.
612 	for (int32 i = 0; i < 3; i++) {
613 		result = usb_disk_operation(lun, SCSI_READ_CAPACITY_10, 10, 0, 0,
614 			&parameter, &dataLength, true, &action);
615 		if (result == B_OK || (action != err_act_retry
616 				&& action != err_act_many_retries)) {
617 			break;
618 		}
619 	}
620 
621 	if (result != B_OK) {
622 		TRACE_ALWAYS("failed to update capacity: %s\n", strerror(result));
623 		lun->media_present = false;
624 		lun->media_changed = false;
625 		usb_disk_reset_capacity(lun);
626 		return result;
627 	}
628 
629 	lun->media_present = true;
630 	lun->media_changed = false;
631 	lun->block_size = ntohl(parameter.logical_block_length);
632 	lun->block_count = ntohl(parameter.last_logical_block_address) + 1;
633 	return B_OK;
634 }
635 
636 
637 status_t
638 usb_disk_synchronize(device_lun *lun, bool force)
639 {
640 	if (lun->device->sync_support == 0) {
641 		// this device reported an illegal request when syncing or repeatedly
642 		// returned an other error, it apparently does not support syncing...
643 		return B_UNSUPPORTED;
644 	}
645 
646 	if (!lun->should_sync && !force)
647 		return B_OK;
648 
649 	status_t result = usb_disk_operation(lun, SCSI_SYNCHRONIZE_CACHE_10, 10,
650 		0, 0, NULL, NULL, false);
651 
652 	if (result == B_OK) {
653 		lun->device->sync_support = SYNC_SUPPORT_RELOAD;
654 		lun->should_sync = false;
655 		return B_OK;
656 	}
657 
658 	if (result == B_DEV_INVALID_IOCTL)
659 		lun->device->sync_support = 0;
660 	else
661 		lun->device->sync_support--;
662 
663 	return result;
664 }
665 
666 
667 //
668 //#pragma mark - Device Attach/Detach Notifications and Callback
669 //
670 
671 
672 static void
673 usb_disk_callback(void *cookie, status_t status, void *data,
674 	size_t actualLength)
675 {
676 	//TRACE("callback()\n");
677 	disk_device *device = (disk_device *)cookie;
678 	device->status = status;
679 	device->actual_length = actualLength;
680 	release_sem(device->notify);
681 }
682 
683 
684 static status_t
685 usb_disk_device_added(usb_device newDevice, void **cookie)
686 {
687 	TRACE("device_added(0x%08" B_PRIx32 ")\n", newDevice);
688 	disk_device *device = (disk_device *)malloc(sizeof(disk_device));
689 	device->device = newDevice;
690 	device->removed = false;
691 	device->open_count = 0;
692 	device->interface = 0xff;
693 	device->current_tag = 0;
694 	device->sync_support = SYNC_SUPPORT_RELOAD;
695 	device->tur_supported = true;
696 	device->is_atapi = false;
697 	device->luns = NULL;
698 
699 	// scan through the interfaces to find our bulk-only data interface
700 	const usb_configuration_info *configuration
701 		= gUSBModule->get_configuration(newDevice);
702 	if (configuration == NULL) {
703 		free(device);
704 		return B_ERROR;
705 	}
706 
707 	for (size_t i = 0; i < configuration->interface_count; i++) {
708 		usb_interface_info *interface = configuration->interface[i].active;
709 		if (interface == NULL)
710 			continue;
711 
712 		if (interface->descr->interface_class == 0x08 /* mass storage */
713 			&& (interface->descr->interface_subclass == 0x06 /* SCSI */
714 				|| interface->descr->interface_subclass == 0x02 /* ATAPI */
715 				|| interface->descr->interface_subclass == 0x05 /* ATAPI */)
716 			&& interface->descr->interface_protocol == 0x50 /* bulk-only */) {
717 
718 			bool hasIn = false;
719 			bool hasOut = false;
720 			for (size_t j = 0; j < interface->endpoint_count; j++) {
721 				usb_endpoint_info *endpoint = &interface->endpoint[j];
722 				if (endpoint == NULL
723 					|| endpoint->descr->attributes != USB_ENDPOINT_ATTR_BULK)
724 					continue;
725 
726 				if (!hasIn && (endpoint->descr->endpoint_address
727 					& USB_ENDPOINT_ADDR_DIR_IN) != 0) {
728 					device->bulk_in = endpoint->handle;
729 					hasIn = true;
730 				} else if (!hasOut && (endpoint->descr->endpoint_address
731 					& USB_ENDPOINT_ADDR_DIR_IN) == 0) {
732 					device->bulk_out = endpoint->handle;
733 					hasOut = true;
734 				}
735 
736 				if (hasIn && hasOut)
737 					break;
738 			}
739 
740 			if (!(hasIn && hasOut))
741 				continue;
742 
743 			device->interface = interface->descr->interface_number;
744 			device->is_atapi = interface->descr->interface_subclass != 0x06;
745 			break;
746 		}
747 	}
748 
749 	if (device->interface == 0xff) {
750 		TRACE_ALWAYS("no valid bulk-only interface found\n");
751 		free(device);
752 		return B_ERROR;
753 	}
754 
755 	mutex_init(&device->lock, "usb_disk device lock");
756 
757 	device->notify = create_sem(0, "usb_disk callback notify");
758 	if (device->notify < B_OK) {
759 		mutex_destroy(&device->lock);
760 		status_t result = device->notify;
761 		free(device);
762 		return result;
763 	}
764 
765 	device->lun_count = usb_disk_get_max_lun(device) + 1;
766 	device->luns = (device_lun **)malloc(device->lun_count
767 		* sizeof(device_lun *));
768 	for (uint8 i = 0; i < device->lun_count; i++)
769 		device->luns[i] = NULL;
770 
771 	status_t result = B_OK;
772 
773 	TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count);
774 	for (uint8 i = 0; i < device->lun_count; i++) {
775 		// create the individual luns present on this device
776 		device_lun *lun = (device_lun *)malloc(sizeof(device_lun));
777 		if (lun == NULL) {
778 			result = B_NO_MEMORY;
779 			break;
780 		}
781 
782 		device->luns[i] = lun;
783 		lun->device = device;
784 		lun->logical_unit_number = i;
785 		lun->should_sync = false;
786 		lun->media_present = true;
787 		lun->media_changed = true;
788 
789 		memset(lun->vendor_name, 0, sizeof(lun->vendor_name));
790 		memset(lun->product_name, 0, sizeof(lun->product_name));
791 		memset(lun->product_revision, 0, sizeof(lun->product_revision));
792 
793 		usb_disk_reset_capacity(lun);
794 
795 		// initialize this lun
796 		result = usb_disk_inquiry(lun);
797 		err_act action = err_act_ok;
798 		for (uint32 tries = 0; tries < 8; tries++) {
799 			TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " begin\n",
800 				i, tries);
801 			status_t ready = usb_disk_test_unit_ready(lun, &action);
802 			if (ready == B_OK || ready == B_DEV_NO_MEDIA
803 				|| ready == B_DEV_MEDIA_CHANGED) {
804 				if (lun->device_type == B_CD)
805 					lun->write_protected = true;
806 				// TODO: check for write protection; disabled since some
807 				// devices lock up when getting the mode sense
808 				else if (/*usb_disk_mode_sense(lun) != B_OK*/true)
809 					lun->write_protected = false;
810 
811 				TRACE("usb lun %" B_PRIu8 " ready. write protected = %c%s\n", i,
812 					lun->write_protected ? 'y' : 'n',
813 					ready == B_DEV_NO_MEDIA ? " (no media inserted)" : "");
814 
815 				break;
816 			}
817 			TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " failed\n",
818 				i, tries);
819 			if (action != err_act_retry && action != err_act_many_retries)
820 				break;
821 			bigtime_t snoozeTime = 1000000 * tries;
822 			TRACE("snoozing %" B_PRIu64 " microseconds for usb lun\n",
823 				snoozeTime);
824 			snooze(snoozeTime);
825 		}
826 
827 		if (result != B_OK)
828 			break;
829 	}
830 
831 	if (result != B_OK) {
832 		TRACE_ALWAYS("failed to initialize logical units: %s\n",
833 			strerror(result));
834 		usb_disk_free_device_and_luns(device);
835 		return result;
836 	}
837 
838 	mutex_lock(&gDeviceListLock);
839 	device->device_number = 0;
840 	disk_device *other = gDeviceList;
841 	while (other != NULL) {
842 		if (other->device_number >= device->device_number)
843 			device->device_number = other->device_number + 1;
844 
845 		other = (disk_device *)other->link;
846 	}
847 
848 	device->link = (void *)gDeviceList;
849 	gDeviceList = device;
850 	gLunCount += device->lun_count;
851 	for (uint8 i = 0; i < device->lun_count; i++)
852 		sprintf(device->luns[i]->name, DEVICE_NAME, device->device_number, i);
853 	mutex_unlock(&gDeviceListLock);
854 
855 	TRACE("new device: 0x%p\n", device);
856 	*cookie = (void *)device;
857 	return B_OK;
858 }
859 
860 
861 static status_t
862 usb_disk_device_removed(void *cookie)
863 {
864 	TRACE("device_removed(0x%p)\n", cookie);
865 	disk_device *device = (disk_device *)cookie;
866 
867 	mutex_lock(&gDeviceListLock);
868 	if (gDeviceList == device) {
869 		gDeviceList = (disk_device *)device->link;
870 	} else {
871 		disk_device *element = gDeviceList;
872 		while (element) {
873 			if (element->link == device) {
874 				element->link = device->link;
875 				break;
876 			}
877 
878 			element = (disk_device *)element->link;
879 		}
880 	}
881 	gLunCount -= device->lun_count;
882 	gDeviceCount--;
883 
884 	device->removed = true;
885 	gUSBModule->cancel_queued_transfers(device->bulk_in);
886 	gUSBModule->cancel_queued_transfers(device->bulk_out);
887 	if (device->open_count == 0)
888 		usb_disk_free_device_and_luns(device);
889 
890 	mutex_unlock(&gDeviceListLock);
891 	return B_OK;
892 }
893 
894 
895 //
896 //#pragma mark - Partial Buffer Functions
897 //
898 
899 
900 static bool
901 usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length,
902 	uint32 &blockPosition, uint16 &blockCount)
903 {
904 	blockPosition = (uint32)(position / lun->block_size);
905 	if ((off_t)blockPosition * lun->block_size != position)
906 		return true;
907 
908 	blockCount = (uint16)(length / lun->block_size);
909 	if ((size_t)blockCount * lun->block_size != length)
910 		return true;
911 
912 	return false;
913 }
914 
915 
916 static status_t
917 usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount,
918 	void *buffer, size_t *length)
919 {
920 	status_t result = usb_disk_operation(lun, SCSI_READ_10, 10, blockPosition,
921 		blockCount, buffer, length, true);
922 	return result;
923 }
924 
925 
926 static status_t
927 usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount,
928 	void *buffer, size_t *length)
929 {
930 	status_t result = usb_disk_operation(lun, SCSI_WRITE_10, 10, blockPosition,
931 		blockCount, buffer, length, false);
932 	if (result == B_OK)
933 		lun->should_sync = true;
934 	return result;
935 }
936 
937 
938 static status_t
939 usb_disk_prepare_partial_buffer(device_lun *lun, off_t position, size_t length,
940 	void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition,
941 	uint16 &blockCount)
942 {
943 	blockPosition = (uint32)(position / lun->block_size);
944 	blockCount = (uint16)((uint32)((position + length + lun->block_size - 1)
945 		/ lun->block_size) - blockPosition);
946 	size_t blockLength = blockCount * lun->block_size;
947 	blockBuffer = malloc(blockLength);
948 	if (blockBuffer == NULL) {
949 		TRACE_ALWAYS("no memory to allocate partial buffer\n");
950 		return B_NO_MEMORY;
951 	}
952 
953 	status_t result = usb_disk_block_read(lun, blockPosition, blockCount,
954 		blockBuffer, &blockLength);
955 	if (result != B_OK) {
956 		TRACE_ALWAYS("block read failed when filling partial buffer: %s\n",
957 			strerror(result));
958 		free(blockBuffer);
959 		return result;
960 	}
961 
962 	off_t offset = position - (off_t)blockPosition * lun->block_size;
963 	partialBuffer = (uint8 *)blockBuffer + offset;
964 	return B_OK;
965 }
966 
967 
968 //
969 //#pragma mark - Driver Hooks
970 //
971 
972 
973 static status_t
974 usb_disk_open(const char *name, uint32 flags, void **cookie)
975 {
976 	TRACE("open(%s)\n", name);
977 	if (strncmp(name, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0)
978 		return B_NAME_NOT_FOUND;
979 
980 	int32 lastPart = 0;
981 	size_t nameLength = strlen(name);
982 	for (int32 i = nameLength - 1; i >= 0; i--) {
983 		if (name[i] == '/') {
984 			lastPart = i;
985 			break;
986 		}
987 	}
988 
989 	char rawName[nameLength + 4];
990 	strncpy(rawName, name, lastPart + 1);
991 	rawName[lastPart + 1] = 0;
992 	strcat(rawName, "raw");
993 	TRACE("opening raw device %s for %s\n", rawName, name);
994 
995 	mutex_lock(&gDeviceListLock);
996 	disk_device *device = gDeviceList;
997 	while (device) {
998 		for (uint8 i = 0; i < device->lun_count; i++) {
999 			device_lun *lun = device->luns[i];
1000 			if (strncmp(rawName, lun->name, 32) == 0) {
1001 				// found the matching device/lun
1002 				if (device->removed) {
1003 					mutex_unlock(&gDeviceListLock);
1004 					return B_ERROR;
1005 				}
1006 
1007 				device->open_count++;
1008 				*cookie = lun;
1009 				mutex_unlock(&gDeviceListLock);
1010 				return B_OK;
1011 			}
1012 		}
1013 
1014 		device = (disk_device *)device->link;
1015 	}
1016 
1017 	mutex_unlock(&gDeviceListLock);
1018 	return B_NAME_NOT_FOUND;
1019 }
1020 
1021 
1022 static status_t
1023 usb_disk_close(void *cookie)
1024 {
1025 	TRACE("close()\n");
1026 	device_lun *lun = (device_lun *)cookie;
1027 	disk_device *device = lun->device;
1028 
1029 	mutex_lock(&device->lock);
1030 	if (!device->removed)
1031 		usb_disk_synchronize(lun, false);
1032 	mutex_unlock(&device->lock);
1033 
1034 	return B_OK;
1035 }
1036 
1037 
1038 static status_t
1039 usb_disk_free(void *cookie)
1040 {
1041 	TRACE("free()\n");
1042 	mutex_lock(&gDeviceListLock);
1043 
1044 	device_lun *lun = (device_lun *)cookie;
1045 	disk_device *device = lun->device;
1046 	device->open_count--;
1047 	if (device->open_count == 0 && device->removed) {
1048 		// we can simply free the device here as it has been removed from
1049 		// the device list in the device removed notification hook
1050 		usb_disk_free_device_and_luns(device);
1051 	}
1052 
1053 	mutex_unlock(&gDeviceListLock);
1054 	return B_OK;
1055 }
1056 
1057 
1058 static inline void
1059 normalize_name(char *name, size_t nameLength)
1060 {
1061 	bool wasSpace = false;
1062 	size_t insertIndex = 0;
1063 	for (size_t i = 0; i < nameLength; i++) {
1064 		bool isSpace = name[i] == ' ';
1065 		if (isSpace && wasSpace)
1066 			continue;
1067 
1068 		name[insertIndex++] = name[i];
1069 		wasSpace = isSpace;
1070 	}
1071 
1072 	if (insertIndex > 0 && name[insertIndex - 1] == ' ')
1073 		insertIndex--;
1074 
1075 	name[insertIndex] = 0;
1076 }
1077 
1078 
1079 static status_t
1080 usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
1081 {
1082 	device_lun *lun = (device_lun *)cookie;
1083 	disk_device *device = lun->device;
1084 	mutex_lock(&device->lock);
1085 	if (device->removed) {
1086 		mutex_unlock(&device->lock);
1087 		return B_DEV_NOT_READY;
1088 	}
1089 
1090 	status_t result = B_DEV_INVALID_IOCTL;
1091 	switch (op) {
1092 		case B_GET_MEDIA_STATUS:
1093 		{
1094 			err_act action = err_act_ok;
1095 			for (uint32 tries = 0; tries < 3; tries++) {
1096 				status_t ready = usb_disk_test_unit_ready(lun, &action);
1097 				if (ready == B_OK || ready == B_DEV_NO_MEDIA
1098 					|| (action != err_act_retry
1099 						&& action != err_act_many_retries)) {
1100 					*(status_t *)buffer = ready;
1101 					break;
1102 				}
1103 				snooze(500000);
1104 			}
1105 			TRACE("B_GET_MEDIA_STATUS: 0x%08" B_PRIx32 "\n",
1106 				*(status_t *)buffer);
1107 			result = B_OK;
1108 			break;
1109 		}
1110 
1111 		case B_GET_GEOMETRY:
1112 		{
1113 			if (lun->media_changed) {
1114 				result = usb_disk_update_capacity(lun);
1115 				if (result != B_OK)
1116 					break;
1117 			}
1118 
1119 			device_geometry geometry;
1120 			devfs_compute_geometry_size(&geometry, lun->block_count,
1121 				lun->block_size);
1122 
1123 			geometry.device_type = lun->device_type;
1124 			geometry.removable = lun->removable;
1125 			geometry.read_only = lun->write_protected;
1126 			geometry.write_once = lun->device_type == B_WORM;
1127 			TRACE("B_GET_GEOMETRY: %" B_PRId32 " sectors at %" B_PRId32
1128 				" bytes per sector\n", geometry.cylinder_count,
1129 				geometry.bytes_per_sector);
1130 			result = user_memcpy(buffer, &geometry, sizeof(device_geometry));
1131 			break;
1132 		}
1133 
1134 		case B_FLUSH_DRIVE_CACHE:
1135 			TRACE("B_FLUSH_DRIVE_CACHE\n");
1136 			result = usb_disk_synchronize(lun, true);
1137 			break;
1138 
1139 		case B_EJECT_DEVICE:
1140 			result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 2,
1141 				NULL, NULL, false);
1142 			break;
1143 
1144 		case B_LOAD_MEDIA:
1145 			result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 3,
1146 				NULL, NULL, false);
1147 			break;
1148 
1149 #if HAIKU_TARGET_PLATFORM_HAIKU
1150 		case B_GET_ICON:
1151 			// We don't support this legacy ioctl anymore, but the two other
1152 			// icon ioctls below instead.
1153 			break;
1154 
1155 		case B_GET_ICON_NAME:
1156 			result = user_strlcpy((char *)buffer,
1157 				"devices/drive-removable-media-usb", B_FILE_NAME_LENGTH);
1158 			break;
1159 
1160 		case B_GET_VECTOR_ICON:
1161 		{
1162 			if (length != sizeof(device_icon)) {
1163 				result = B_BAD_VALUE;
1164 				break;
1165 			}
1166 
1167 			device_icon iconData;
1168 			if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) {
1169 				result = B_BAD_ADDRESS;
1170 				break;
1171 			}
1172 
1173 			if (iconData.icon_size >= (int32)sizeof(kDeviceIcon)) {
1174 				if (user_memcpy(iconData.icon_data, kDeviceIcon,
1175 						sizeof(kDeviceIcon)) != B_OK) {
1176 					result = B_BAD_ADDRESS;
1177 					break;
1178 				}
1179 			}
1180 
1181 			iconData.icon_size = sizeof(kDeviceIcon);
1182 			result = user_memcpy(buffer, &iconData, sizeof(device_icon));
1183 			break;
1184 		}
1185 
1186 		case B_GET_DEVICE_NAME:
1187 		{
1188 			size_t nameLength = sizeof(lun->vendor_name)
1189 				+ sizeof(lun->product_name) + sizeof(lun->product_revision) + 3;
1190 
1191 			char name[nameLength];
1192 			snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name,
1193 				lun->product_name, lun->product_revision);
1194 
1195 			normalize_name(name, nameLength);
1196 
1197 			result = user_strlcpy((char *)buffer, name, length);
1198 			if (result > 0)
1199 				result = B_OK;
1200 
1201 			TRACE_ALWAYS("got device name \"%s\": %s\n", name,
1202 				strerror(result));
1203 			break;
1204 		}
1205 #endif
1206 
1207 		default:
1208 			TRACE_ALWAYS("unhandled ioctl %" B_PRId32 "\n", op);
1209 			break;
1210 	}
1211 
1212 	mutex_unlock(&device->lock);
1213 	return result;
1214 }
1215 
1216 
1217 static status_t
1218 usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length)
1219 {
1220 	if (buffer == NULL || length == NULL)
1221 		return B_BAD_VALUE;
1222 
1223 	TRACE("read(%" B_PRIdOFF ", %ld)\n", position, *length);
1224 	device_lun *lun = (device_lun *)cookie;
1225 	disk_device *device = lun->device;
1226 	mutex_lock(&device->lock);
1227 	if (device->removed) {
1228 		*length = 0;
1229 		mutex_unlock(&device->lock);
1230 		return B_DEV_NOT_READY;
1231 	}
1232 
1233 	status_t result = B_ERROR;
1234 	uint32 blockPosition = 0;
1235 	uint16 blockCount = 0;
1236 	bool needsPartial = usb_disk_needs_partial_buffer(lun, position, *length,
1237 		blockPosition, blockCount);
1238 	if (needsPartial) {
1239 		void *partialBuffer = NULL;
1240 		void *blockBuffer = NULL;
1241 		result = usb_disk_prepare_partial_buffer(lun, position, *length,
1242 			partialBuffer, blockBuffer, blockPosition, blockCount);
1243 		if (result == B_OK) {
1244 			memcpy(buffer, partialBuffer, *length);
1245 			free(blockBuffer);
1246 		}
1247 	} else {
1248 		result = usb_disk_block_read(lun, blockPosition, blockCount, buffer,
1249 			length);
1250 	}
1251 
1252 	mutex_unlock(&device->lock);
1253 	if (result == B_OK) {
1254 		TRACE("read successful with %ld bytes\n", *length);
1255 		return B_OK;
1256 	}
1257 
1258 	*length = 0;
1259 	TRACE_ALWAYS("read failed: %s\n", strerror(result));
1260 	return result;
1261 }
1262 
1263 
1264 static status_t
1265 usb_disk_write(void *cookie, off_t position, const void *buffer,
1266 	size_t *length)
1267 {
1268 	if (buffer == NULL || length == NULL)
1269 		return B_BAD_VALUE;
1270 
1271 	TRACE("write(%" B_PRIdOFF", %ld)\n", position, *length);
1272 	device_lun *lun = (device_lun *)cookie;
1273 	disk_device *device = lun->device;
1274 	mutex_lock(&device->lock);
1275 	if (device->removed) {
1276 		*length = 0;
1277 		mutex_unlock(&device->lock);
1278 		return B_DEV_NOT_READY;
1279 	}
1280 
1281 	status_t result = B_ERROR;
1282 	uint32 blockPosition = 0;
1283 	uint16 blockCount = 0;
1284 	bool needsPartial = usb_disk_needs_partial_buffer(lun, position,
1285 		*length, blockPosition, blockCount);
1286 	if (needsPartial) {
1287 		void *partialBuffer = NULL;
1288 		void *blockBuffer = NULL;
1289 		result = usb_disk_prepare_partial_buffer(lun, position, *length,
1290 			partialBuffer, blockBuffer, blockPosition, blockCount);
1291 		if (result == B_OK) {
1292 			memcpy(partialBuffer, buffer, *length);
1293 			size_t blockLength = blockCount * lun->block_size;
1294 			result = usb_disk_block_write(lun, blockPosition, blockCount,
1295 				blockBuffer, &blockLength);
1296 			free(blockBuffer);
1297 		}
1298 	} else {
1299 		result = usb_disk_block_write(lun, blockPosition, blockCount,
1300 			(void *)buffer, length);
1301 	}
1302 
1303 	mutex_unlock(&device->lock);
1304 	if (result == B_OK) {
1305 		TRACE("write successful with %ld bytes\n", *length);
1306 		return B_OK;
1307 	}
1308 
1309 	*length = 0;
1310 	TRACE_ALWAYS("write failed: %s\n", strerror(result));
1311 	return result;
1312 }
1313 
1314 
1315 //
1316 //#pragma mark - Driver Entry Points
1317 //
1318 
1319 
1320 status_t
1321 init_hardware()
1322 {
1323 	TRACE("init_hardware()\n");
1324 	return B_OK;
1325 }
1326 
1327 
1328 status_t
1329 init_driver()
1330 {
1331 	TRACE("init_driver()\n");
1332 	static usb_notify_hooks notifyHooks = {
1333 		&usb_disk_device_added,
1334 		&usb_disk_device_removed
1335 	};
1336 
1337 	static usb_support_descriptor supportedDevices[] = {
1338 		{ 0x08 /* mass storage */, 0x06 /* SCSI */, 0x50 /* bulk */, 0, 0 },
1339 		{ 0x08 /* mass storage */, 0x02 /* ATAPI */, 0x50 /* bulk */, 0, 0 },
1340 		{ 0x08 /* mass storage */, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 }
1341 	};
1342 
1343 	gDeviceList = NULL;
1344 	gDeviceCount = 0;
1345 	gLunCount = 0;
1346 	mutex_init(&gDeviceListLock, "usb_disk device list lock");
1347 
1348 	TRACE("trying module %s\n", B_USB_MODULE_NAME);
1349 	status_t result = get_module(B_USB_MODULE_NAME,
1350 		(module_info **)&gUSBModule);
1351 	if (result < B_OK) {
1352 		TRACE_ALWAYS("getting module failed: %s\n", strerror(result));
1353 		mutex_destroy(&gDeviceListLock);
1354 		return result;
1355 	}
1356 
1357 	gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 3, NULL);
1358 	gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
1359 	return B_OK;
1360 }
1361 
1362 
1363 void
1364 uninit_driver()
1365 {
1366 	TRACE("uninit_driver()\n");
1367 	gUSBModule->uninstall_notify(DRIVER_NAME);
1368 	mutex_lock(&gDeviceListLock);
1369 
1370 	if (gDeviceNames) {
1371 		for (int32 i = 0; gDeviceNames[i]; i++)
1372 			free(gDeviceNames[i]);
1373 		free(gDeviceNames);
1374 		gDeviceNames = NULL;
1375 	}
1376 
1377 	mutex_destroy(&gDeviceListLock);
1378 	put_module(B_USB_MODULE_NAME);
1379 }
1380 
1381 
1382 const char **
1383 publish_devices()
1384 {
1385 	TRACE("publish_devices()\n");
1386 	if (gDeviceNames) {
1387 		for (int32 i = 0; gDeviceNames[i]; i++)
1388 			free(gDeviceNames[i]);
1389 		free(gDeviceNames);
1390 		gDeviceNames = NULL;
1391 	}
1392 
1393 	gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1));
1394 	if (gDeviceNames == NULL)
1395 		return NULL;
1396 
1397 	int32 index = 0;
1398 	mutex_lock(&gDeviceListLock);
1399 	disk_device *device = gDeviceList;
1400 	while (device) {
1401 		for (uint8 i = 0; i < device->lun_count; i++)
1402 			gDeviceNames[index++] = strdup(device->luns[i]->name);
1403 
1404 		device = (disk_device *)device->link;
1405 	}
1406 
1407 	gDeviceNames[index++] = NULL;
1408 	mutex_unlock(&gDeviceListLock);
1409 	return (const char **)gDeviceNames;
1410 }
1411 
1412 
1413 device_hooks *
1414 find_device(const char *name)
1415 {
1416 	TRACE("find_device()\n");
1417 	static device_hooks hooks = {
1418 		&usb_disk_open,
1419 		&usb_disk_close,
1420 		&usb_disk_free,
1421 		&usb_disk_ioctl,
1422 		&usb_disk_read,
1423 		&usb_disk_write,
1424 		NULL,
1425 		NULL,
1426 		NULL,
1427 		NULL
1428 	};
1429 
1430 	return &hooks;
1431 }
1432