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