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