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