1#include <sys/cdefs.h>
2/*-
3 * SPDX-License-Identifier: BSD-2-Clause
4 *
5 * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>,
6 *		      Nick Hibma <n_hibma@FreeBSD.org>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *	$NetBSD: umass.c,v 1.28 2000/04/02 23:46:53 augustss Exp $
30 */
31
32/* Also already merged from NetBSD:
33 *	$NetBSD: umass.c,v 1.67 2001/11/25 19:05:22 augustss Exp $
34 *	$NetBSD: umass.c,v 1.90 2002/11/04 19:17:33 pooka Exp $
35 *	$NetBSD: umass.c,v 1.108 2003/11/07 17:03:25 wiz Exp $
36 *	$NetBSD: umass.c,v 1.109 2003/12/04 13:57:31 keihan Exp $
37 */
38
39/*
40 * Universal Serial Bus Mass Storage Class specs:
41 * http://www.usb.org/developers/devclass_docs/usb_msc_overview_1.2.pdf
42 * http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
43 * http://www.usb.org/developers/devclass_docs/usb_msc_cbi_1.1.pdf
44 * http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf
45 */
46
47/*
48 * Ported to NetBSD by Lennart Augustsson <augustss@NetBSD.org>.
49 * Parts of the code written by Jason R. Thorpe <thorpej@shagadelic.org>.
50 */
51
52/*
53 * The driver handles 3 Wire Protocols
54 * - Command/Bulk/Interrupt (CBI)
55 * - Command/Bulk/Interrupt with Command Completion Interrupt (CBI with CCI)
56 * - Mass Storage Bulk-Only (BBB)
57 *   (BBB refers Bulk/Bulk/Bulk for Command/Data/Status phases)
58 *
59 * Over these wire protocols it handles the following command protocols
60 * - SCSI
61 * - UFI (floppy command set)
62 * - 8070i (ATAPI)
63 *
64 * UFI and 8070i (ATAPI) are transformed versions of the SCSI command set. The
65 * sc->sc_transform method is used to convert the commands into the appropriate
66 * format (if at all necessary). For example, UFI requires all commands to be
67 * 12 bytes in length amongst other things.
68 *
69 * The source code below is marked and can be split into a number of pieces
70 * (in this order):
71 *
72 * - probe/attach/detach
73 * - generic transfer routines
74 * - BBB
75 * - CBI
76 * - CBI_I (in addition to functions from CBI)
77 * - CAM (Common Access Method)
78 * - SCSI
79 * - UFI
80 * - 8070i (ATAPI)
81 *
82 * The protocols are implemented using a state machine, for the transfers as
83 * well as for the resets. The state machine is contained in umass_t_*_callback.
84 * The state machine is started through either umass_command_start() or
85 * umass_reset().
86 *
87 * The reason for doing this is a) CAM performs a lot better this way and b) it
88 * avoids using tsleep from interrupt context (for example after a failed
89 * transfer).
90 */
91
92/*
93 * The SCSI related part of this driver has been derived from the
94 * dev/ppbus/vpo.c driver, by Nicolas Souchu (nsouch@FreeBSD.org).
95 *
96 * The CAM layer uses so called actions which are messages sent to the host
97 * adapter for completion. The actions come in through umass_cam_action. The
98 * appropriate block of routines is called depending on the transport protocol
99 * in use. When the transfer has finished, these routines call
100 * umass_cam_cb again to complete the CAM command.
101 */
102
103#include <driver.h>
104#include <disk.h>
105
106#include "implementation/global_implementation.h"
107#include "scsi_all.h"
108#include "scsi.h"
109#if USB_HAVE_DEVICE_TOPOLOGY
110#include "implementation/usb_btree.h"
111#endif
112#include "user_copy.h"
113
114#ifdef LOSCFG_USB_DEBUG
115#define	DIF(m, x)				\
116  do {						\
117    if (umass_debug & (m)) { x ; }		\
118  } while (0)
119
120#define	DPRINTF_UMASS(sc, m, fmt, ...)			\
121  do {							\
122	if (umass_debug & (m)) {				\
123		PRINTK("%s:%s: " fmt,				\
124		    (sc) ? (const char *)(sc)->sc_name :	\
125		    (const char *)"umassX",			\
126		    __FUNCTION__ ,## __VA_ARGS__);		\
127	}							\
128  } while (0)
129
130#define	UDMASS_GEN	0x00010000	/* general */
131#define	UDMASS_SCSI	0x00020000	/* scsi */
132#define	UDMASS_UFI	0x00040000	/* ufi command set */
133#define	UDMASS_ATAPI	0x00080000	/* 8070i command set */
134#define	UDMASS_CMD	(UDMASS_SCSI|UDMASS_UFI|UDMASS_ATAPI)
135#define	UDMASS_USB	0x00100000	/* USB general */
136#define	UDMASS_BBB	0x00200000	/* Bulk-Only transfers */
137#define	UDMASS_CBI	0x00400000	/* CBI transfers */
138#define	UDMASS_WIRE	(UDMASS_BBB|UDMASS_CBI)
139#define	UDMASS_ALL	0xffff0000	/* all of the above */
140static int umass_debug = 0; 	/* UDMASS_ALL; */
141static int umass_throttle;
142
143void
144umass_debug_func(int level)
145{
146	switch(level) {
147		case 0:
148			umass_debug = 0;
149			PRINTK("Close the umass debug\n");
150			break;
151		case UDMASS_GEN:
152		case UDMASS_SCSI:
153		case UDMASS_UFI:
154		case UDMASS_ATAPI:
155		case UDMASS_CMD:
156		case UDMASS_USB:
157		case UDMASS_BBB:
158		case UDMASS_CBI:
159		case UDMASS_WIRE:
160		case UDMASS_ALL:
161			umass_debug = level;
162			PRINTK("The level of umass debug is %x\n", level);
163			break;
164		default:
165			PRINT_ERR("The level of umass debug is invalid, please refer to umass.c\n");
166			break;
167	}
168}
169DEBUG_MODULE(umass, umass_debug_func);
170#else
171#define	DIF(...) do { } while (0)
172#define	DPRINTF_UMASS(...) do { } while (0)
173#endif
174
175#define	UMASS_BULK_SIZE (1 << 17)
176#define	UMASS_CBI_DIAGNOSTIC_CMDLEN 12	/* bytes */
177#define	UMASS_MAX_CMDLEN MAX(12, CBWCDBLENGTH)	/* bytes */
178
179/* USB transfer definitions */
180
181#define	UMASS_T_BBB_RESET1		0	/* Bulk-Only */
182#define	UMASS_T_BBB_RESET2		1
183#define	UMASS_T_BBB_RESET3		2
184#define	UMASS_T_BBB_COMMAND		3
185#define	UMASS_T_BBB_DATA_READ	4
186#define	UMASS_T_BBB_DATA_RD_CS	5
187#define	UMASS_T_BBB_DATA_WRITE	6
188#define	UMASS_T_BBB_DATA_WR_CS	7
189#define	UMASS_T_BBB_STATUS		8
190#define	UMASS_T_BBB_MAX			9
191
192#define	UMASS_T_CBI_RESET1		0	/* CBI */
193#define	UMASS_T_CBI_RESET2		1
194#define	UMASS_T_CBI_RESET3		2
195#define	UMASS_T_CBI_COMMAND		3
196#define	UMASS_T_CBI_DATA_READ	4
197#define	UMASS_T_CBI_DATA_RD_CS	5
198#define	UMASS_T_CBI_DATA_WRITE	6
199#define	UMASS_T_CBI_DATA_WR_CS	7
200#define	UMASS_T_CBI_STATUS		8
201#define	UMASS_T_CBI_RESET4		9
202#define	UMASS_T_CBI_MAX			10
203
204#define	UMASS_T_MAX MAX(UMASS_T_CBI_MAX, UMASS_T_BBB_MAX)
205
206/* Generic definitions */
207
208/* Direction for transfer */
209#define	DIR_NONE	0
210#define	DIR_IN		1
211#define	DIR_OUT		2
212
213/* device name */
214#define	DEVNAME		"umass"
215#define	DEVNAME_SIM	"umass-sim"
216
217/* Approximate maximum transfer speeds (assumes 33% overhead). */
218#define	UMASS_FULL_TRANSFER_SPEED	1000
219#define	UMASS_HIGH_TRANSFER_SPEED	40000
220#define	UMASS_SUPER_TRANSFER_SPEED	400000
221#define	UMASS_FLOPPY_TRANSFER_SPEED	20
222
223#define	UMASS_TIMEOUT			20000	/* ms */
224
225/* CAM specific definitions */
226#define	UMASS_SCSIID_MAX	1	/* maximum number of drives expected */
227#define	UMASS_SCSIID_HOST	UMASS_SCSIID_MAX
228
229/* Bulk-Only features */
230#define	UR_BBB_RESET		0xff	/* Bulk-Only reset */
231#define	UR_BBB_GET_MAX_LUN	0xfe	/* Get maximum lun */
232
233#define UMASS_ATTACH_PRENAME		"/dev/sd"
234#define MASS_NAME		10
235#define MAX_DEVICE		5
236
237/*
238 * SCSI I/O Request CCB used for the XPT_SCSI_IO and XPT_CONT_TARGET_IO
239 * function codes.
240 */
241struct ccb_scsiio {
242	uint8_t *data_ptr;		/* Ptr to the data buf/SG list */
243	uint32_t dxfer_len;		/* Data transfer length */
244	uint32_t resid;			/* Transfer residual length: 2's comp */
245	int32_t  status;
246
247	struct	 scsi_sense_data sense_data;
248	uint8_t   sense_len;	/* Number of bytes to autosense */
249};
250
251union ccb {
252	struct	ccb_scsiio	csio;
253};
254
255
256/* Command Block Wrapper */
257typedef struct {
258	uDWord	dCBWSignature;
259#define	CBWSIGNATURE	0x43425355
260	uDWord	dCBWTag;
261	uDWord	dCBWDataTransferLength;
262	uByte	bCBWFlags;
263#define	CBWFLAGS_OUT	0x00
264#define	CBWFLAGS_IN		0x80
265	uByte	bCBWLUN;
266	uByte	bCDBLength;
267#define	CBWCDBLENGTH	16
268	uByte	CBWCDB[CBWCDBLENGTH];
269} __packed umass_bbb_cbw_t;
270
271#define	UMASS_BBB_CBW_SIZE	31
272
273/* Command Status Wrapper */
274typedef struct {
275	uDWord	dCSWSignature;
276#define	CSWSIGNATURE					0x53425355
277#define	CSWSIGNATURE_IMAGINATION_DBX1	0x43425355
278#define	CSWSIGNATURE_OLYMPUS_C1			0x55425355
279	uDWord	dCSWTag;
280	uDWord	dCSWDataResidue;
281	uByte	bCSWStatus;
282#define	CSWSTATUS_GOOD		0x0
283#define	CSWSTATUS_FAILED	0x1
284#define	CSWSTATUS_PHASE		0x2
285} __packed umass_bbb_csw_t;
286
287#define	UMASS_BBB_CSW_SIZE	13
288
289/* CBI features */
290
291#define	UR_CBI_ADSC	0x00
292
293typedef union {
294	struct {
295		uint8_t	type;
296#define	IDB_TYPE_CCI			0x00
297		uint8_t	value;
298#define	IDB_VALUE_PASS			0x00
299#define	IDB_VALUE_FAIL			0x01
300#define	IDB_VALUE_PHASE			0x02
301#define	IDB_VALUE_PERSISTENT	0x03
302#define	IDB_VALUE_STATUS_MASK	0x03
303	} __packed common;
304
305	struct {
306		uint8_t	asc;
307		uint8_t	ascq;
308	} __packed ufi;
309} __packed umass_cbi_sbl_t;
310
311struct umass_info {
312	uint32_t sectorsize;
313	uint64_t sectornum;
314};
315
316struct umass_softc;			/* see below */
317
318typedef void (umass_callback_t)(struct umass_softc *sc, union ccb *ccb,
319		uint32_t residue, uint8_t status);
320
321#define	STATUS_CMD_OK		0	/* everything ok */
322#define	STATUS_CMD_UNKNOWN	1	/* will have to fetch sense */
323#define	STATUS_CMD_FAILED	2	/* transfer was ok, command failed */
324#define	STATUS_WIRE_FAILED	3	/* couldn't even get command across */
325
326typedef uint8_t (umass_transform_t)(struct umass_softc *sc, uint8_t *cmd_ptr,
327	    uint8_t cmd_len);
328
329/* Wire and command protocol */
330#define	UMASS_PROTO_BBB		0x0001	/* USB wire protocol */
331#define	UMASS_PROTO_CBI		0x0002
332#define	UMASS_PROTO_CBI_I	0x0004
333#define	UMASS_PROTO_WIRE	0x00ff	/* USB wire protocol mask */
334#define	UMASS_PROTO_SCSI	0x0100	/* command protocol */
335#define	UMASS_PROTO_ATAPI	0x0200
336#define	UMASS_PROTO_UFI		0x0400
337#define	UMASS_PROTO_RBC		0x0800
338#define	UMASS_PROTO_COMMAND	0xff00	/* command protocol mask */
339
340/* Device specific quirks */
341#define	NO_QUIRKS			0x0000
342	/*
343	 * The drive does not support Test Unit Ready. Convert to Start Unit
344	 */
345#define	NO_TEST_UNIT_READY	0x0001
346	/*
347	 * The drive does not reset the Unit Attention state after REQUEST
348	 * SENSE has been sent. The INQUIRY command does not reset the UA
349	 * either, and so CAM runs in circles trying to retrieve the initial
350	 * INQUIRY data.
351	 */
352#define	RS_NO_CLEAR_UA		0x0002
353	/* The drive does not support START STOP.  */
354#define	NO_START_STOP		0x0004
355	/* Don't ask for full inquiry data (255b).  */
356#define	FORCE_SHORT_INQUIRY	0x0008
357	/* Needs to be initialised the Shuttle way */
358#define	SHUTTLE_INIT		0x0010
359	/* Drive needs to be switched to alternate iface 1 */
360#define	ALT_IFACE_1			0x0020
361	/* Drive does not do 1Mb/s, but just floppy speeds (20kb/s) */
362#define	FLOPPY_SPEED		0x0040
363	/* The device can't count and gets the residue of transfers wrong */
364#define	IGNORE_RESIDUE		0x0080
365	/* No GetMaxLun call */
366#define	NO_GETMAXLUN		0x0100
367	/* The device uses a weird CSWSIGNATURE. */
368#define	WRONG_CSWSIG		0x0200
369	/* Device cannot handle INQUIRY so fake a generic response */
370#define	NO_INQUIRY			0x0400
371	/* Device cannot handle INQUIRY EVPD, return CHECK CONDITION */
372#define	NO_INQUIRY_EVPD		0x0800
373	/* Pad all RBC requests to 12 bytes. */
374#define	RBC_PAD_TO_12		0x1000
375	/*
376	 * Device reports number of sectors from READ_CAPACITY, not max
377	 * sector number.
378	 */
379#define	READ_CAPACITY_OFFBY1	0x2000
380	/*
381	 * Device cannot handle a SCSI synchronize cache command.  Normally
382	 * this quirk would be handled in the cam layer, but for IDE bridges
383	 * we need to associate the quirk with the bridge and not the
384	 * underlying disk device.  This is handled by faking a success
385	 * result.
386	 */
387#define	NO_SYNCHRONIZE_CACHE	0x4000
388	/* Device does not support 'PREVENT/ALLOW MEDIUM REMOVAL'. */
389#define	NO_PREVENT_ALLOW		0x8000
390
391#if USB_HAVE_DEVICE_TOPOLOGY
392extern usbd_bt_tree hub_tree;
393#endif
394
395struct umass_softc {
396	union ccb *data_ccb;
397	struct scsi_sense cam_scsi_sense;
398	struct scsi_test_unit_ready cam_scsi_test_unit_ready;
399	struct mtx sc_mtx;
400	EVENT_CB_S sc_event;
401	struct {
402		uint8_t *data_ptr;
403		union ccb *ccb;
404		umass_callback_t *callback;
405
406		uint32_t data_len;		/* bytes */
407		uint32_t data_rem;		/* bytes */
408		uint32_t data_timeout;	/* ms */
409		uint32_t actlen;		/* bytes */
410
411		uint8_t	cmd_data[UMASS_MAX_CMDLEN];
412		uint8_t	cmd_len;		/* bytes */
413		uint8_t	dir;
414		uint8_t	lun;
415	}	sc_transfer;
416
417	struct umass_info info;
418
419	/* Bulk specific variables for transfers in progress */
420	umass_bbb_cbw_t cbw;		/* command block wrapper */
421	umass_bbb_csw_t csw;		/* command status wrapper */
422
423	/* CBI specific variables for transfers in progress */
424	umass_cbi_sbl_t sbl;		/* status block */
425
426	device_t sc_dev;
427	struct usb_device *sc_udev;
428	struct usb_xfer *sc_xfer[UMASS_T_MAX];
429
430	/*
431	 * The command transform function is used to convert the SCSI
432	 * commands into their derivatives, like UFI, ATAPI, and friends.
433	 */
434	umass_transform_t *sc_transform;
435
436	uint32_t sc_unit;
437	uint32_t sc_quirks;		/* they got it almost right */
438	uint32_t sc_proto;		/* wire and cmd protocol */
439
440	uint8_t	sc_name[16];
441	uint8_t	sc_iface_no;	/* interface number */
442	uint8_t	sc_maxlun;		/* maximum LUN number, inclusive */
443	uint8_t	sc_last_xfer_index;
444	uint8_t	sc_status_try;
445	BOOL	sc_detach_status;
446	BOOL	sc_super_disk;		/* TRUE: Disk is bigger than 2T; FALSE: Disk is less than 2T */
447	struct mtx sc_umass_mtx;	/* The mtx is used to prevent data read and write competition */
448};
449
450struct umass_probe_proto {
451	uint32_t quirks;
452	uint32_t proto;
453
454	int	error;
455};
456
457#if USB_SUPPORT_SD_HOT_PLUG
458struct umass_dev_info {
459	struct umass_softc *sc;
460	unsigned int dev_unit;
461	int used;			/* 0: not use; 1: in use */
462	int attached;		/* 0: not attach; 1: in attach */
463	struct mtx dev_mtx;	/* The mtx is used to prevent U disk insertion or extraction competition */
464};
465
466static struct umass_dev_info g_umass_dev_array[MAX_DEVICE] = {0};
467static void umass_task_check(int flag);
468static void umass_dev_delete(struct umass_softc *sc, unsigned int dev_unit);
469int umass_dev_is_attached(unsigned int dev_unit);
470static void umass_dev_attach_flag_set(int dev_unit);
471pthread_t   umass_taskid;
472#define	umass_dev_mtx_init(id, type) (void)mtx_init(&g_umass_dev_array[id].dev_mtx, NULL, NULL, type)
473#define	umass_dev_mtx_destroy(id)	 (void)mtx_destroy(&g_umass_dev_array[id].dev_mtx)
474#define	umass_dev_lock(id)			 (void)mtx_lock(&g_umass_dev_array[id].dev_mtx)
475#define	umass_dev_unlock(id)		 (void)mtx_unlock(&g_umass_dev_array[id].dev_mtx)
476#else
477#define	umass_dev_lock(id) (void)mtx_lock(NULL)
478#define	umass_dev_unlock(id) (void)mtx_unlock(NULL)
479#endif
480
481struct umass_softc *p_umsf = NULL;
482/* prototypes */
483
484static device_probe_t umass_probe;
485static device_attach_t umass_attach;
486static device_detach_t umass_detach;
487
488static usb_callback_t umass_tr_error;
489static usb_callback_t umass_t_bbb_reset1_callback;
490static usb_callback_t umass_t_bbb_reset2_callback;
491static usb_callback_t umass_t_bbb_reset3_callback;
492static usb_callback_t umass_t_bbb_command_callback;
493static usb_callback_t umass_t_bbb_data_read_callback;
494static usb_callback_t umass_t_bbb_data_rd_cs_callback;
495static usb_callback_t umass_t_bbb_data_write_callback;
496static usb_callback_t umass_t_bbb_data_wr_cs_callback;
497static usb_callback_t umass_t_bbb_status_callback;
498static usb_callback_t umass_t_cbi_reset1_callback;
499static usb_callback_t umass_t_cbi_reset2_callback;
500static usb_callback_t umass_t_cbi_reset3_callback;
501static usb_callback_t umass_t_cbi_reset4_callback;
502static usb_callback_t umass_t_cbi_command_callback;
503static usb_callback_t umass_t_cbi_data_read_callback;
504static usb_callback_t umass_t_cbi_data_rd_cs_callback;
505static usb_callback_t umass_t_cbi_data_write_callback;
506static usb_callback_t umass_t_cbi_data_wr_cs_callback;
507static usb_callback_t umass_t_cbi_status_callback;
508
509static void	umass_cancel_ccb(struct umass_softc *);
510static void	umass_init_shuttle(struct umass_softc *);
511static void	umass_t_bbb_data_clear_stall_callback(struct usb_xfer *,
512			uint8_t, uint8_t, usb_error_t);
513static int	umass_command_start(struct umass_softc *, uint8_t, void *,
514			uint32_t, uint32_t, umass_callback_t *, union ccb *);
515static uint8_t	umass_bbb_get_max_lun(struct umass_softc *);
516static void	umass_cbi_start_status(struct umass_softc *);
517static void	umass_t_cbi_data_clear_stall_callback(struct usb_xfer *,
518			uint8_t, uint8_t, usb_error_t);
519static void	umass_cam_cb(struct umass_softc *, union ccb *, uint32_t, uint8_t);
520static uint8_t	umass_scsi_transform(struct umass_softc *, uint8_t *, uint8_t);
521static uint8_t	umass_rbc_transform(struct umass_softc *, uint8_t *, uint8_t);
522static uint8_t	umass_ufi_transform(struct umass_softc *, uint8_t *, uint8_t);
523static uint8_t	umass_atapi_transform(struct umass_softc *, uint8_t *,
524			uint8_t);
525static uint8_t	umass_no_transform(struct umass_softc *, uint8_t *, uint8_t);
526
527#ifdef LOSCFG_USB_DEBUG
528static void	umass_bbb_dump_cbw(struct umass_softc *, umass_bbb_cbw_t *);
529static void	umass_bbb_dump_csw(struct umass_softc *, umass_bbb_csw_t *);
530static void	umass_cbi_dump_cmd(struct umass_softc *, void *, uint8_t);
531#endif
532
533static void devunit_to_devname(unsigned int dev_unit, char *devname);
534static int32_t umass_attach_dev(struct umass_softc *sc, unsigned int dev_unit);
535static void umass_detach_dev_sub(struct umass_softc *sc, int dev_unit, int flag);
536
537static struct usb_config umass_bbb_config[UMASS_T_BBB_MAX] = {
538	[UMASS_T_BBB_RESET1] = {
539		.type = UE_CONTROL,
540		.endpoint = 0x00,	/* Control pipe */
541		.direction = UE_DIR_ANY,
542		.bufsize = sizeof(struct usb_device_request),
543		.callback = &umass_t_bbb_reset1_callback,
544		.timeout = 5000,	/* 5 seconds */
545		.interval = 500,	/* 500 milliseconds */
546	},
547
548	[UMASS_T_BBB_RESET2] = {
549		.type = UE_CONTROL,
550		.endpoint = 0x00,	/* Control pipe */
551		.direction = UE_DIR_ANY,
552		.bufsize = sizeof(struct usb_device_request),
553		.callback = &umass_t_bbb_reset2_callback,
554		.timeout = 5000,	/* 5 seconds */
555		.interval = 50,	/* 50 milliseconds */
556	},
557
558	[UMASS_T_BBB_RESET3] = {
559		.type = UE_CONTROL,
560		.endpoint = 0x00,	/* Control pipe */
561		.direction = UE_DIR_ANY,
562		.bufsize = sizeof(struct usb_device_request),
563		.callback = &umass_t_bbb_reset3_callback,
564		.timeout = 5000,	/* 5 seconds */
565		.interval = 50,	/* 50 milliseconds */
566	},
567
568	[UMASS_T_BBB_COMMAND] = {
569		.type = UE_BULK,
570		.endpoint = UE_ADDR_ANY,
571		.direction = UE_DIR_OUT,
572		.bufsize = sizeof(umass_bbb_cbw_t),
573		.callback = &umass_t_bbb_command_callback,
574		.timeout = 5000,	/* 5 seconds */
575	},
576
577	[UMASS_T_BBB_DATA_READ] = {
578		.type = UE_BULK,
579		.endpoint = UE_ADDR_ANY,
580		.direction = UE_DIR_IN,
581		.bufsize = UMASS_BULK_SIZE,
582		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
583		.callback = &umass_t_bbb_data_read_callback,
584		.timeout = 0,	/* overwritten later */
585	},
586
587	[UMASS_T_BBB_DATA_RD_CS] = {
588		.type = UE_CONTROL,
589		.endpoint = 0x00,	/* Control pipe */
590		.direction = UE_DIR_ANY,
591		.bufsize = sizeof(struct usb_device_request),
592		.callback = &umass_t_bbb_data_rd_cs_callback,
593		.timeout = 5000,	/* 5 seconds */
594	},
595
596	[UMASS_T_BBB_DATA_WRITE] = {
597		.type = UE_BULK,
598		.endpoint = UE_ADDR_ANY,
599		.direction = UE_DIR_OUT,
600		.bufsize = UMASS_BULK_SIZE,
601		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
602		.callback = &umass_t_bbb_data_write_callback,
603		.timeout = 0,	/* overwritten later */
604	},
605
606	[UMASS_T_BBB_DATA_WR_CS] = {
607		.type = UE_CONTROL,
608		.endpoint = 0x00,	/* Control pipe */
609		.direction = UE_DIR_ANY,
610		.bufsize = sizeof(struct usb_device_request),
611		.callback = &umass_t_bbb_data_wr_cs_callback,
612		.timeout = 5000,	/* 5 seconds */
613	},
614
615	[UMASS_T_BBB_STATUS] = {
616		.type = UE_BULK,
617		.endpoint = UE_ADDR_ANY,
618		.direction = UE_DIR_IN,
619		.bufsize = sizeof(umass_bbb_csw_t),
620		.flags = {.short_xfer_ok = 1,},
621		.callback = &umass_t_bbb_status_callback,
622		.timeout = 5000,	/* ms */
623	},
624};
625
626static struct usb_config umass_cbi_config[UMASS_T_CBI_MAX] = {
627	[UMASS_T_CBI_RESET1] = {
628		.type = UE_CONTROL,
629		.endpoint = 0x00,	/* Control pipe */
630		.direction = UE_DIR_ANY,
631		.bufsize = (sizeof(struct usb_device_request) +
632		    UMASS_CBI_DIAGNOSTIC_CMDLEN),
633		.callback = &umass_t_cbi_reset1_callback,
634		.timeout = 5000,	/* 5 seconds */
635		.interval = 500,	/* 500 milliseconds */
636	},
637
638	[UMASS_T_CBI_RESET2] = {
639		.type = UE_CONTROL,
640		.endpoint = 0x00,	/* Control pipe */
641		.direction = UE_DIR_ANY,
642		.bufsize = sizeof(struct usb_device_request),
643		.callback = &umass_t_cbi_reset2_callback,
644		.timeout = 5000,	/* 5 seconds */
645		.interval = 50,	/* 50 milliseconds */
646	},
647
648	[UMASS_T_CBI_RESET3] = {
649		.type = UE_CONTROL,
650		.endpoint = 0x00,	/* Control pipe */
651		.direction = UE_DIR_ANY,
652		.bufsize = sizeof(struct usb_device_request),
653		.callback = &umass_t_cbi_reset3_callback,
654		.timeout = 5000,	/* 5 seconds */
655		.interval = 50,	/* 50 milliseconds */
656	},
657
658	[UMASS_T_CBI_COMMAND] = {
659		.type = UE_CONTROL,
660		.endpoint = 0x00,	/* Control pipe */
661		.direction = UE_DIR_ANY,
662		.bufsize = (sizeof(struct usb_device_request) +
663		    UMASS_MAX_CMDLEN),
664		.callback = &umass_t_cbi_command_callback,
665		.timeout = 5000,	/* 5 seconds */
666	},
667
668	[UMASS_T_CBI_DATA_READ] = {
669		.type = UE_BULK,
670		.endpoint = UE_ADDR_ANY,
671		.direction = UE_DIR_IN,
672		.bufsize = UMASS_BULK_SIZE,
673		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
674		.callback = &umass_t_cbi_data_read_callback,
675		.timeout = 0,	/* overwritten later */
676	},
677
678	[UMASS_T_CBI_DATA_RD_CS] = {
679		.type = UE_CONTROL,
680		.endpoint = 0x00,	/* Control pipe */
681		.direction = UE_DIR_ANY,
682		.bufsize = sizeof(struct usb_device_request),
683		.callback = &umass_t_cbi_data_rd_cs_callback,
684		.timeout = 5000,	/* 5 seconds */
685	},
686
687	[UMASS_T_CBI_DATA_WRITE] = {
688		.type = UE_BULK,
689		.endpoint = UE_ADDR_ANY,
690		.direction = UE_DIR_OUT,
691		.bufsize = UMASS_BULK_SIZE,
692		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
693		.callback = &umass_t_cbi_data_write_callback,
694		.timeout = 0,	/* overwritten later */
695	},
696
697	[UMASS_T_CBI_DATA_WR_CS] = {
698		.type = UE_CONTROL,
699		.endpoint = 0x00,	/* Control pipe */
700		.direction = UE_DIR_ANY,
701		.bufsize = sizeof(struct usb_device_request),
702		.callback = &umass_t_cbi_data_wr_cs_callback,
703		.timeout = 5000,	/* 5 seconds */
704	},
705
706	[UMASS_T_CBI_STATUS] = {
707		.type = UE_INTERRUPT,
708		.endpoint = UE_ADDR_ANY,
709		.direction = UE_DIR_IN,
710		.flags = {.short_xfer_ok = 1,.no_pipe_ok = 1,},
711		.bufsize = sizeof(umass_cbi_sbl_t),
712		.callback = &umass_t_cbi_status_callback,
713		.timeout = 5000,	/* ms */
714	},
715
716	[UMASS_T_CBI_RESET4] = {
717		.type = UE_CONTROL,
718		.endpoint = 0x00,	/* Control pipe */
719		.direction = UE_DIR_ANY,
720		.bufsize = sizeof(struct usb_device_request),
721		.callback = &umass_t_cbi_reset4_callback,
722		.timeout = 5000,	/* ms */
723	},
724};
725
726#define	UFI_COMMAND_LENGTH	12	/* UFI commands are always 12 bytes */
727#define	ATAPI_COMMAND_LENGTH	12	/* ATAPI commands are always 12 bytes */
728
729static devclass_t umass_devclass;
730
731static device_method_t umass_methods[] = {
732	/* Device interface */
733	DEVMETHOD(device_probe, umass_probe),
734	DEVMETHOD(device_attach, umass_attach),
735	DEVMETHOD(device_detach, umass_detach),
736
737	DEVMETHOD_END
738};
739
740static driver_t umass_driver = {
741	.name = "umass",
742	.methods = umass_methods,
743	.size = sizeof(struct umass_softc),
744};
745
746#if USB_HAVE_DEVICE_TOPOLOGY
747UINT64 dev_quantity = 0;
748#endif
749
750DRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, NULL, 0);
751
752static uint16_t
753umass_get_proto(struct usb_interface *iface)
754{
755	struct usb_interface_descriptor *id;
756	uint16_t retval;
757
758	retval = 0;
759
760	/* Check for a standards compliant device */
761	id = usbd_get_interface_descriptor(iface);
762	if ((id == NULL) ||
763	    (id->bInterfaceClass != UICLASS_MASS)) {
764		goto done;
765	}
766	switch (id->bInterfaceSubClass) {
767	case UISUBCLASS_SCSI:
768		retval |= UMASS_PROTO_SCSI;
769		break;
770	case UISUBCLASS_UFI:
771		retval |= UMASS_PROTO_UFI;
772		break;
773	case UISUBCLASS_RBC:
774		retval |= UMASS_PROTO_RBC;
775		break;
776	case UISUBCLASS_SFF8020I:
777	case UISUBCLASS_SFF8070I:
778		retval |= UMASS_PROTO_ATAPI;
779		break;
780	default:
781		goto done;
782	}
783
784	switch (id->bInterfaceProtocol) {
785	case UIPROTO_MASS_CBI:
786		retval |= UMASS_PROTO_CBI;
787		break;
788	case UIPROTO_MASS_CBI_I:
789		retval |= UMASS_PROTO_CBI_I;
790		break;
791	case UIPROTO_MASS_BBB_OLD:
792	case UIPROTO_MASS_BBB:
793		retval |= UMASS_PROTO_BBB;
794		break;
795	default:
796		goto done;
797	}
798done:
799	return (retval);
800}
801
802/*
803 * Match the device we are seeing with the devices supported.
804 */
805static struct umass_probe_proto
806umass_probe_proto(device_t dev, struct usb_attach_arg *uaa)
807{
808	struct umass_probe_proto ret;
809	uint32_t quirks = NO_QUIRKS;
810	uint32_t proto = umass_get_proto(uaa->iface);
811
812	(void)memset_s(&ret, sizeof(ret), 0, sizeof(ret));
813	ret.error = BUS_PROBE_GENERIC;
814
815	/* Search for protocol enforcement */
816
817	if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_BBB)) {
818		proto &= ~UMASS_PROTO_WIRE;
819		proto |= UMASS_PROTO_BBB;
820	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_CBI)) {
821		proto &= ~UMASS_PROTO_WIRE;
822		proto |= UMASS_PROTO_CBI;
823	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_CBI_I)) {
824		proto &= ~UMASS_PROTO_WIRE;
825		proto |= UMASS_PROTO_CBI_I;
826	}
827
828	if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_SCSI)) {
829		proto &= ~UMASS_PROTO_COMMAND;
830		proto |= UMASS_PROTO_SCSI;
831	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_ATAPI)) {
832		proto &= ~UMASS_PROTO_COMMAND;
833		proto |= UMASS_PROTO_ATAPI;
834	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_UFI)) {
835		proto &= ~UMASS_PROTO_COMMAND;
836		proto |= UMASS_PROTO_UFI;
837	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_RBC)) {
838		proto &= ~UMASS_PROTO_COMMAND;
839		proto |= UMASS_PROTO_RBC;
840	}
841
842	/* Check if the protocol is invalid */
843
844	if ((proto & UMASS_PROTO_COMMAND) == 0) {
845		ret.error = ENXIO;
846		goto done;
847	}
848
849	if ((proto & UMASS_PROTO_WIRE) == 0) {
850		ret.error = ENXIO;
851		goto done;
852	}
853
854	/* Search for quirks */
855
856	if (usb_test_quirk(uaa, UQ_MSC_NO_TEST_UNIT_READY))
857		quirks |= NO_TEST_UNIT_READY;
858	if (usb_test_quirk(uaa, UQ_MSC_NO_RS_CLEAR_UA))
859		quirks |= RS_NO_CLEAR_UA;
860	if (usb_test_quirk(uaa, UQ_MSC_NO_START_STOP))
861		quirks |= NO_START_STOP;
862	if (usb_test_quirk(uaa, UQ_MSC_NO_GETMAXLUN))
863		quirks |= NO_GETMAXLUN;
864	if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY))
865		quirks |= NO_INQUIRY;
866	if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY_EVPD))
867		quirks |= NO_INQUIRY_EVPD;
868	if (usb_test_quirk(uaa, UQ_MSC_NO_PREVENT_ALLOW))
869		quirks |= NO_PREVENT_ALLOW;
870	if (usb_test_quirk(uaa, UQ_MSC_NO_SYNC_CACHE))
871		quirks |= NO_SYNCHRONIZE_CACHE;
872	if (usb_test_quirk(uaa, UQ_MSC_SHUTTLE_INIT))
873		quirks |= SHUTTLE_INIT;
874	if (usb_test_quirk(uaa, UQ_MSC_ALT_IFACE_1))
875		quirks |= ALT_IFACE_1;
876	if (usb_test_quirk(uaa, UQ_MSC_FLOPPY_SPEED))
877		quirks |= FLOPPY_SPEED;
878	if (usb_test_quirk(uaa, UQ_MSC_IGNORE_RESIDUE))
879		quirks |= IGNORE_RESIDUE;
880	if (usb_test_quirk(uaa, UQ_MSC_WRONG_CSWSIG))
881		quirks |= WRONG_CSWSIG;
882	if (usb_test_quirk(uaa, UQ_MSC_RBC_PAD_TO_12))
883		quirks |= RBC_PAD_TO_12;
884	if (usb_test_quirk(uaa, UQ_MSC_READ_CAP_OFFBY1))
885		quirks |= READ_CAPACITY_OFFBY1;
886	if (usb_test_quirk(uaa, UQ_MSC_FORCE_SHORT_INQ))
887		quirks |= FORCE_SHORT_INQUIRY;
888
889done:
890	ret.quirks = quirks;
891	ret.proto = proto;
892	return (ret);
893}
894
895static int
896umass_probe(device_t dev)
897{
898	struct usb_attach_arg *uaa =
899	    (struct usb_attach_arg *)device_get_ivars(dev);
900	struct umass_probe_proto temp;
901
902	if (uaa->usb_mode != USB_MODE_HOST) {
903		return (ENXIO);
904	}
905	temp = umass_probe_proto(dev, uaa);
906
907	return (temp.error);
908}
909
910static int
911umass_attach(device_t dev)
912{
913	struct umass_softc *sc =
914		(struct umass_softc *)device_get_softc(dev);
915	struct usb_attach_arg *uaa =
916		(struct usb_attach_arg *)device_get_ivars(dev);
917	struct umass_probe_proto temp = umass_probe_proto(dev, uaa);
918	struct usb_interface_descriptor *id;
919	usb_error_t err;
920
921	/*
922	 * NOTE: the softc struct is cleared in device_set_driver.
923	 * We can safely call umass_detach without specifically
924	 * initializing the struct.
925	 */
926
927	sc->sc_dev = dev;
928	sc->sc_udev = uaa->device;
929	sc->sc_proto = temp.proto;
930	sc->sc_quirks = temp.quirks;
931	sc->sc_unit = device_get_unit(dev);
932	sc->data_ccb = NULL;
933	sc->sc_detach_status = FALSE;
934	sc->sc_super_disk = FALSE;
935
936#if USB_HAVE_DEVICE_TOPOLOGY
937	dev_quantity |= 1ull << (unsigned int)device_get_unit(dev);
938#endif
939
940	(void)snprintf_s((char *)sc->sc_name, sizeof(sc->sc_name), sizeof(sc->sc_name) - 1,
941	    "%s", device_get_nameunit(dev));
942
943	device_set_usb_desc(dev);
944
945	mtx_init(&sc->sc_mtx, device_get_nameunit(dev),
946		    NULL, MTX_DEF | MTX_RECURSE);
947	mtx_init(&sc->sc_umass_mtx, device_get_nameunit(dev),
948		    NULL, MTX_DEF | MTX_RECURSE);
949
950	(void)LOS_EventInit(&sc->sc_event);
951
952	/* get interface index */
953
954	id = usbd_get_interface_descriptor(uaa->iface);
955	if (id == NULL) {
956		device_printf(dev, "failed to get "
957			"interface number\n");
958		goto detach;
959	}
960	sc->sc_iface_no = id->bInterfaceNumber;
961
962	device_printf(dev, " ");
963
964	switch (sc->sc_proto & UMASS_PROTO_COMMAND) {
965	case UMASS_PROTO_SCSI:
966		PRINTK("SCSI");
967		break;
968	case UMASS_PROTO_ATAPI:
969		PRINTK("8070i (ATAPI)");
970		break;
971	case UMASS_PROTO_UFI:
972		PRINTK("UFI");
973		break;
974	case UMASS_PROTO_RBC:
975		PRINTK("RBC");
976		break;
977	default:
978		PRINTK("(unknown 0x%02x)",
979		    sc->sc_proto & UMASS_PROTO_COMMAND);
980		break;
981	}
982
983	PRINTK(" over ");
984
985	switch (sc->sc_proto & UMASS_PROTO_WIRE) {
986	case UMASS_PROTO_BBB:
987		PRINTK("Bulk-Only");
988		break;
989	case UMASS_PROTO_CBI:		/* uses Comand/Bulk pipes */
990		PRINTK("CBI");
991		break;
992	case UMASS_PROTO_CBI_I:	/* uses Comand/Bulk/Interrupt pipes */
993		PRINTK("CBI with CCI");
994		break;
995	default:
996		PRINTK("(unknown 0x%02x)",
997		    sc->sc_proto & UMASS_PROTO_WIRE);
998	}
999
1000	PRINTK("; quirks = 0x%04x\n", sc->sc_quirks);
1001
1002	if (sc->sc_quirks & ALT_IFACE_1) {
1003		err = usbd_set_alt_interface_index
1004		    (uaa->device, uaa->info.bIfaceIndex, 1);
1005
1006		if (err) {
1007			DPRINTF_UMASS(sc, UDMASS_USB, "could not switch to "
1008			    "Alt Interface 1\n");
1009			goto detach;
1010		}
1011	}
1012	/* allocate all required USB transfers */
1013
1014	if (sc->sc_proto & UMASS_PROTO_BBB) {
1015		err = usbd_transfer_setup(uaa->device,
1016		    &uaa->info.bIfaceIndex, sc->sc_xfer, umass_bbb_config,
1017		    UMASS_T_BBB_MAX, sc, &sc->sc_mtx);
1018
1019		/* skip reset first time */
1020		sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
1021
1022	} else if (sc->sc_proto & (UMASS_PROTO_CBI | UMASS_PROTO_CBI_I)) {
1023		err = usbd_transfer_setup(uaa->device,
1024		    &uaa->info.bIfaceIndex, sc->sc_xfer, umass_cbi_config,
1025		    UMASS_T_CBI_MAX, sc, &sc->sc_mtx);
1026
1027		/* skip reset first time */
1028		sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
1029
1030	} else {
1031		err = USB_ERR_INVAL;
1032	}
1033
1034	if (err) {
1035		device_printf(dev, "could not setup required "
1036		    "transfers, %s\n", usbd_errstr(err));
1037		goto detach;
1038	}
1039#ifdef LOSCFG_USB_DEBUG
1040	if (umass_throttle > 0) {
1041		uint8_t x;
1042		int iv;
1043
1044		iv = umass_throttle;
1045
1046		if (iv < 1)
1047			iv = 1;
1048		else if (iv > 8000)
1049			iv = 8000;
1050
1051		for (x = 0; x != UMASS_T_MAX; x++) {
1052			if (sc->sc_xfer[x] != NULL)
1053				usbd_xfer_set_interval(sc->sc_xfer[x], iv);
1054		}
1055	}
1056#endif
1057	sc->sc_transform =
1058	    (sc->sc_proto & UMASS_PROTO_SCSI) ? &umass_scsi_transform :
1059	    (sc->sc_proto & UMASS_PROTO_UFI) ? &umass_ufi_transform :
1060	    (sc->sc_proto & UMASS_PROTO_ATAPI) ? &umass_atapi_transform :
1061	    (sc->sc_proto & UMASS_PROTO_RBC) ? &umass_rbc_transform :
1062	    &umass_no_transform;
1063
1064	/* from here onwards the device can be used. */
1065
1066	if (sc->sc_quirks & SHUTTLE_INIT) {
1067		umass_init_shuttle(sc);
1068	}
1069	/* get the maximum LUN supported by the device */
1070
1071	if (((sc->sc_proto & UMASS_PROTO_WIRE) == UMASS_PROTO_BBB) &&
1072	    !(sc->sc_quirks & NO_GETMAXLUN))
1073		sc->sc_maxlun = umass_bbb_get_max_lun(sc);
1074	else
1075		sc->sc_maxlun = 0;
1076
1077	/* Prepare the SCSI command block */
1078	sc->cam_scsi_sense.opcode = REQUEST_SENSE;
1079	sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY;
1080
1081#define	SOFT_CACHE_SIZE 0x40
1082	sc->data_ccb = (union ccb *)malloc(sizeof(union ccb));
1083	if (sc->data_ccb == NULL)
1084		goto detach;
1085	sc->data_ccb->csio.data_ptr = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(SOFT_CACHE_SIZE));
1086	if (sc->data_ccb->csio.data_ptr == NULL)
1087		goto detach;
1088	sc->data_ccb->csio.dxfer_len = SOFT_CACHE_SIZE;
1089
1090	DPRINTF_UMASS(sc, UDMASS_GEN, "Attach finished\n");
1091
1092	/* register the device*/
1093	if (umass_attach_dev(sc, device_get_unit(dev))) {
1094		goto detach;
1095	}
1096
1097	p_umsf = sc;
1098	return (0);			/* success */
1099
1100detach:
1101	(void)umass_detach(dev);
1102	return (ENXIO);			/* failure */
1103}
1104
1105static int
1106umass_detach(device_t dev)
1107{
1108	struct umass_softc *sc = (struct umass_softc *)device_get_softc(dev);
1109	unsigned int dev_unit = device_get_unit(dev);
1110
1111	DPRINTF_UMASS(sc, UDMASS_USB, "\n");
1112
1113	sc->sc_detach_status = TRUE;
1114
1115	/* teardown our statemachine */
1116	usbd_transfer_unsetup(sc->sc_xfer, UMASS_T_MAX);
1117
1118	mtx_lock(&sc->sc_mtx);
1119
1120	/* cancel any leftover CCB's */
1121	umass_cancel_ccb(sc);
1122
1123	mtx_lock(&sc->sc_umass_mtx);
1124	if (sc->data_ccb != NULL) {
1125		if (sc->data_ccb->csio.data_ptr != NULL) {
1126			free((void*)sc->data_ccb->csio.data_ptr);
1127			sc->data_ccb->csio.data_ptr = NULL;
1128		}
1129		free(sc->data_ccb);
1130		sc->data_ccb = NULL;
1131	}
1132	mtx_unlock(&sc->sc_umass_mtx);
1133
1134	umass_detach_dev_sub(sc, dev_unit, 0);
1135#if USB_SUPPORT_SD_HOT_PLUG
1136	umass_task_check(1);
1137#endif
1138
1139	mtx_unlock(&sc->sc_mtx);
1140	sc->sc_detach_status = FALSE;
1141	mtx_destroy(&sc->sc_mtx);
1142	mtx_destroy(&sc->sc_umass_mtx);
1143
1144	p_umsf = NULL;
1145	return (0);			/* success */
1146}
1147
1148static void
1149umass_init_shuttle(struct umass_softc *sc)
1150{
1151	struct usb_device_request req;
1152	usb_error_t err;
1153	uint8_t status[2] = {0, 0};
1154
1155	/*
1156	 * The Linux driver does this, but no one can tell us what the
1157	 * command does.
1158	 */
1159	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1160	req.bRequest = 1;	/* XXX unknown command */
1161	USETW(req.wValue, 0);
1162	req.wIndex[0] = sc->sc_iface_no;
1163	req.wIndex[1] = 0;
1164	USETW(req.wLength, sizeof(status));
1165	err = usbd_do_request(sc->sc_udev, NULL, &req, &status);
1166	if (err)
1167		DPRINTF_UMASS(sc, UDMASS_GEN, "request failed in %s %d, err=%d\n",
1168	    __FUNCTION__, __LINE__, err);
1169
1170	DPRINTF_UMASS(sc, UDMASS_GEN, "Shuttle init returned 0x%02x%02x\n",
1171	    status[0], status[1]);
1172}
1173
1174/*
1175 * Generic functions to handle transfers
1176 */
1177
1178static void
1179umass_transfer_start(struct umass_softc *sc, uint8_t xfer_index)
1180{
1181	DPRINTF_UMASS(sc, UDMASS_GEN, "transfer index = "
1182	    "%d\n", xfer_index);
1183
1184	if (sc->sc_xfer[xfer_index]) {
1185		sc->sc_last_xfer_index = xfer_index;
1186		usbd_transfer_start(sc->sc_xfer[xfer_index]);
1187	} else {
1188		umass_cancel_ccb(sc);
1189	}
1190}
1191
1192static void
1193umass_cancel_ccb(struct umass_softc *sc)
1194{
1195	union ccb *umass_ccb;
1196
1197	mtx_assert(&sc->sc_mtx, MA_OWNED);
1198
1199	umass_ccb = sc->sc_transfer.ccb;
1200	sc->sc_transfer.ccb = NULL;
1201	sc->sc_last_xfer_index = 0;
1202
1203	if (umass_ccb != NULL) {
1204		(sc->sc_transfer.callback)
1205		    (sc, umass_ccb, (sc->sc_transfer.data_len -
1206		    sc->sc_transfer.actlen), STATUS_WIRE_FAILED);
1207	}
1208}
1209
1210static void
1211umass_tr_error(struct usb_xfer *xfer, usb_error_t error)
1212{
1213	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1214
1215	if (error != USB_ERR_CANCELLED) {
1216		DPRINTF_UMASS(sc, UDMASS_GEN, "transfer error, %s -> "
1217		    "reset\n", usbd_errstr(error));
1218	}
1219	umass_cancel_ccb(sc);
1220}
1221
1222/*
1223 *return 0: find the corresponding LUN;
1224 *		 1: find the SBC Direct-access;
1225 *		 -1: did not find the LUN.
1226 */
1227static int
1228umass_scsi_inquiry_data(struct umass_softc *sc, void *data, int len)
1229{
1230	struct scsiresp_inquiry_s *cur_i;
1231	uint8_t pdt;
1232	uint8_t rmb;
1233	int is_dir;
1234	char *name;
1235
1236	if (len != SCSIRESP_INQUIRY_SIZEOF)
1237		return (-1);
1238
1239	is_dir = 0;
1240	cur_i = (struct scsiresp_inquiry_s *)data;
1241
1242	pdt = SCSI_GET_INQUIRY_PDT(cur_i->qualtype);
1243	rmb = SCSI_GET_INQUIRY_RMB(cur_i->flags1);
1244	switch (pdt) {
1245	case T_DIRECT:
1246		name = "SBC Direct-access";
1247		is_dir = 1;
1248		break;
1249	case T_CDROM:
1250		name = "CD-ROM";
1251		break;
1252	case T_OPTICAL:
1253		name = "Optical memory";
1254		break;
1255	case T_RBC:
1256		name = "RBC Direct-access";
1257		break;
1258	default:
1259		name = "PDT out of scope";
1260		break;
1261	}
1262	DPRINTF_UMASS(sc, UDMASS_BBB, "SCSI: LUN-%d %s %s\n", sc->sc_transfer.lun, name,
1263		    (rmb ? "Removable" : "Not Removable"));
1264
1265	(void)name;
1266	(void)rmb; /* this is for clearing warning */
1267	return (is_dir);
1268}
1269
1270/*
1271 * BBB protocol specific functions
1272 */
1273
1274static void
1275umass_t_bbb_reset1_callback(struct usb_xfer *xfer, usb_error_t error)
1276{
1277	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1278	struct usb_device_request req;
1279	struct usb_page_cache *pc;
1280
1281	switch (USB_GET_STATE(xfer)) {
1282	case USB_ST_TRANSFERRED:
1283		umass_transfer_start(sc, UMASS_T_BBB_RESET2);
1284		return;
1285
1286	case USB_ST_SETUP:
1287		/*
1288		 * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
1289		 *
1290		 * For Reset Recovery the host shall issue in the following order:
1291		 * a) a Bulk-Only Mass Storage Reset
1292		 * b) a Clear Feature HALT to the Bulk-In endpoint
1293		 * c) a Clear Feature HALT to the Bulk-Out endpoint
1294		 *
1295		 * This is done in 3 steps, using 3 transfers:
1296		 * UMASS_T_BBB_RESET1
1297		 * UMASS_T_BBB_RESET2
1298		 * UMASS_T_BBB_RESET3
1299		 */
1300
1301		DPRINTF_UMASS(sc, UDMASS_BBB, "BBB reset!\n");
1302
1303		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1304		req.bRequest = UR_BBB_RESET;	/* bulk only reset */
1305		USETW(req.wValue, 0);
1306		req.wIndex[0] = sc->sc_iface_no;
1307		req.wIndex[1] = 0;
1308		USETW(req.wLength, 0);
1309
1310		pc = usbd_xfer_get_frame(xfer, 0);
1311		usbd_copy_in(pc, 0, &req, sizeof(req));
1312
1313		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1314		usbd_xfer_set_frames(xfer, 1);
1315		usbd_transfer_submit(xfer);
1316		return;
1317
1318	default:			/* Error */
1319		umass_tr_error(xfer, error);
1320		return;
1321	}
1322}
1323
1324static void
1325umass_t_bbb_reset2_callback(struct usb_xfer *xfer, usb_error_t error)
1326{
1327	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_RESET3,
1328	    UMASS_T_BBB_DATA_READ, error);
1329}
1330
1331static void
1332umass_t_bbb_reset3_callback(struct usb_xfer *xfer, usb_error_t error)
1333{
1334	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_COMMAND,
1335	    UMASS_T_BBB_DATA_WRITE, error);
1336}
1337
1338static void
1339umass_t_bbb_data_clear_stall_callback(struct usb_xfer *xfer,
1340	uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error)
1341{
1342	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1343
1344	switch (USB_GET_STATE(xfer)) {
1345	case USB_ST_TRANSFERRED:
1346tr_transferred:
1347		umass_transfer_start(sc, next_xfer);
1348		return;
1349
1350	case USB_ST_SETUP:
1351		if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) {
1352			goto tr_transferred;
1353		}
1354		return;
1355
1356	default:			/* Error */
1357		umass_tr_error(xfer, error);
1358		return;
1359	}
1360}
1361
1362static void
1363umass_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
1364{
1365	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1366	struct usb_page_cache *pc;
1367	uint32_t tag;
1368	int ret;
1369
1370	switch (USB_GET_STATE(xfer)) {
1371	case USB_ST_TRANSFERRED:
1372		umass_transfer_start
1373		    (sc, ((sc->sc_transfer.dir == DIR_IN) ? UMASS_T_BBB_DATA_READ :
1374		    (sc->sc_transfer.dir == DIR_OUT) ? UMASS_T_BBB_DATA_WRITE :
1375		    UMASS_T_BBB_STATUS));
1376		return;
1377
1378	case USB_ST_SETUP:
1379
1380		sc->sc_status_try = 0;
1381
1382		/*
1383		 * the initial value is not important,
1384		 * as long as the values are unique:
1385		 */
1386		tag = UGETDW(sc->cbw.dCBWTag) + 1;
1387
1388		USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE);
1389		USETDW(sc->cbw.dCBWTag, tag);
1390
1391		/*
1392		* dCBWDataTransferLength:
1393		*   This field indicates the number of bytes of data that the host
1394		*   intends to transfer on the IN or OUT Bulk endpoint(as indicated by
1395		*   the Direction bit) during the execution of this command. If this
1396		*   field is set to 0, the device will expect that no data will be
1397		*   transferred IN or OUT during this command, regardless of the value
1398		*   of the Direction bit defined in dCBWFlags.
1399		*/
1400		USETDW(sc->cbw.dCBWDataTransferLength, sc->sc_transfer.data_len);
1401
1402		/*
1403		* dCBWFlags:
1404		* The bits of the Flags field are defined as follows:
1405		*	 Bits 0-6  reserved
1406		*	 Bit  7	Direction - this bit shall be ignored if the
1407		*						dCBWDataTransferLength field is zero.
1408		*				0 = data Out from host to device
1409		*				1 = data In from device to host
1410		*/
1411		sc->cbw.bCBWFlags = ((sc->sc_transfer.dir == DIR_IN) ?
1412		    CBWFLAGS_IN : CBWFLAGS_OUT);
1413		sc->cbw.bCBWLUN = sc->sc_transfer.lun;
1414
1415		if (sc->sc_transfer.cmd_len > sizeof(sc->cbw.CBWCDB)) {
1416			sc->sc_transfer.cmd_len = sizeof(sc->cbw.CBWCDB);
1417			DPRINTF_UMASS(sc, UDMASS_BBB, "Truncating long command!\n");
1418		}
1419		sc->cbw.bCDBLength = sc->sc_transfer.cmd_len;
1420
1421		/* copy SCSI command data */
1422		ret = memcpy_s(sc->cbw.CBWCDB, CBWCDBLENGTH,
1423			sc->sc_transfer.cmd_data, sc->sc_transfer.cmd_len);
1424		if (ret != EOK) {
1425			DPRINTF_UMASS(sc, UDMASS_BBB, "memcpy_s fail, %d\n", ret);
1426			return;
1427		}
1428
1429		/* clear remaining command area */
1430		(void)memset_s(sc->cbw.CBWCDB + sc->sc_transfer.cmd_len,
1431		    sizeof(sc->cbw.CBWCDB) - sc->sc_transfer.cmd_len, 0,
1432		    sizeof(sc->cbw.CBWCDB) - sc->sc_transfer.cmd_len);
1433
1434		DIF(UDMASS_BBB,  umass_bbb_dump_cbw(sc, &sc->cbw));
1435
1436		pc = usbd_xfer_get_frame(xfer, 0);
1437		usbd_copy_in(pc, 0, &sc->cbw, sizeof(sc->cbw));
1438		usbd_xfer_set_frame_len(xfer, 0, sizeof(sc->cbw));
1439
1440		usbd_transfer_submit(xfer);
1441
1442		return;
1443
1444	default:			/* Error */
1445		umass_tr_error(xfer, error);
1446		return;
1447	}
1448}
1449
1450static void
1451umass_t_bbb_data_callback(struct usb_xfer *xfer, usb_error_t error,
1452	uint8_t xfer_index)
1453{
1454	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1455	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1456	int actlen, sumlen;
1457
1458	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1459
1460	switch (USB_GET_STATE(xfer)) {
1461	case USB_ST_TRANSFERRED:
1462		sc->sc_transfer.data_rem -= actlen;
1463		sc->sc_transfer.data_ptr += actlen;
1464		sc->sc_transfer.actlen += actlen;
1465
1466		if (actlen < sumlen) {
1467			/* short transfer */
1468			sc->sc_transfer.data_rem = 0;
1469		}
1470	case USB_ST_SETUP:
1471		DPRINTF_UMASS(sc, UDMASS_BBB, "max_bulk=%u, data_rem=%u\n",
1472		    max_bulk, sc->sc_transfer.data_rem);
1473
1474		if (sc->sc_transfer.data_rem == 0) {
1475			umass_transfer_start(sc, UMASS_T_BBB_STATUS);
1476			return;
1477		}
1478		if (max_bulk > sc->sc_transfer.data_rem) {
1479			max_bulk = sc->sc_transfer.data_rem;
1480		}
1481		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1482
1483		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1484		    max_bulk);
1485
1486		usbd_transfer_submit(xfer);
1487		return;
1488
1489	default:			/* Error */
1490		if (error == USB_ERR_CANCELLED) {
1491			umass_tr_error(xfer, error);
1492		} else {
1493			umass_transfer_start(sc, xfer_index);
1494		}
1495		return;
1496	}
1497}
1498
1499static void
1500umass_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
1501{
1502	umass_t_bbb_data_callback(xfer, error, UMASS_T_BBB_DATA_RD_CS);
1503}
1504
1505static void
1506umass_t_bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1507{
1508	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS,
1509	    UMASS_T_BBB_DATA_READ, error);
1510}
1511
1512static void
1513umass_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
1514{
1515	umass_t_bbb_data_callback(xfer, error, UMASS_T_BBB_DATA_WR_CS);
1516}
1517
1518static void
1519umass_t_bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1520{
1521	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS,
1522	    UMASS_T_BBB_DATA_WRITE, error);
1523}
1524
1525static void
1526umass_t_bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
1527{
1528	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1529	union ccb *umass_ccb = sc->sc_transfer.ccb;
1530	struct usb_page_cache *pc;
1531	uint32_t residue;
1532	int actlen;
1533
1534	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1535
1536	switch (USB_GET_STATE(xfer)) {
1537	case USB_ST_TRANSFERRED:
1538
1539		/*
1540		 * Do a full reset if there is something wrong with the CSW:
1541		 */
1542		sc->sc_status_try = 1;
1543
1544		/* Zero missing parts of the CSW: */
1545
1546		if (actlen < (int)sizeof(sc->csw)) {
1547			(void)memset_s(&sc->csw, sizeof(sc->csw), 0, sizeof(sc->csw));
1548		}
1549
1550		pc = usbd_xfer_get_frame(xfer, 0);
1551
1552		usbd_copy_out(pc, 0, &sc->csw, actlen);
1553
1554		DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw));
1555
1556		residue = UGETDW(sc->csw.dCSWDataResidue);
1557
1558		if ((!residue) || (sc->sc_quirks & IGNORE_RESIDUE)) {
1559			residue = (sc->sc_transfer.data_len -
1560			    sc->sc_transfer.actlen);
1561		}
1562		if (residue > sc->sc_transfer.data_len) {
1563			DPRINTF_UMASS(sc, UDMASS_BBB, "truncating residue from %d "
1564			    "to %d bytes\n", residue, sc->sc_transfer.data_len);
1565			residue = sc->sc_transfer.data_len;
1566		}
1567		/* translate weird command-status signatures: */
1568		if (sc->sc_quirks & WRONG_CSWSIG) {
1569			uint32_t temp = UGETDW(sc->csw.dCSWSignature);
1570
1571			if ((temp == CSWSIGNATURE_OLYMPUS_C1) ||
1572			    (temp == CSWSIGNATURE_IMAGINATION_DBX1)) {
1573				USETDW(sc->csw.dCSWSignature, CSWSIGNATURE);
1574			}
1575		}
1576		/* check CSW and handle eventual error */
1577		if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) {
1578			DPRINTF_UMASS(sc, UDMASS_BBB, "bad CSW signature 0x%08x != 0x%08x\n",
1579			    UGETDW(sc->csw.dCSWSignature), CSWSIGNATURE);
1580			/*
1581			 * Invalid CSW: Wrong signature or wrong tag might
1582			 * indicate that we lost synchronization. Reset the
1583			 * device.
1584			 */
1585			goto tr_error;
1586		} else if (UGETDW(sc->csw.dCSWTag) != UGETDW(sc->cbw.dCBWTag)) {
1587			DPRINTF_UMASS(sc, UDMASS_BBB, "Invalid CSW: tag 0x%08x should be "
1588			    "0x%08x\n", UGETDW(sc->csw.dCSWTag),
1589			    UGETDW(sc->cbw.dCBWTag));
1590			goto tr_error;
1591		} else if (sc->csw.bCSWStatus > CSWSTATUS_PHASE) {
1592			DPRINTF_UMASS(sc, UDMASS_BBB, "Invalid CSW: status %d > %d\n",
1593			    sc->csw.bCSWStatus, CSWSTATUS_PHASE);
1594			goto tr_error;
1595		} else if (sc->csw.bCSWStatus == CSWSTATUS_PHASE) {
1596			DPRINTF_UMASS(sc, UDMASS_BBB, "Phase error, residue = "
1597			    "%d\n", residue);
1598			goto tr_error;
1599		} else if (sc->sc_transfer.actlen > sc->sc_transfer.data_len) {
1600			DPRINTF_UMASS(sc, UDMASS_BBB, "Buffer overrun %d > %d\n",
1601			    sc->sc_transfer.actlen, sc->sc_transfer.data_len);
1602			goto tr_error;
1603		} else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) {
1604			DPRINTF_UMASS(sc, UDMASS_BBB, "Command failed, residue = "
1605			    "%d\n", residue);
1606
1607			sc->sc_transfer.ccb = NULL;
1608
1609			sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
1610
1611			(sc->sc_transfer.callback)
1612			    (sc, umass_ccb, residue, STATUS_CMD_FAILED);
1613		} else {
1614			sc->sc_transfer.ccb = NULL;
1615
1616			sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
1617
1618			(sc->sc_transfer.callback)
1619			    (sc, umass_ccb, residue, STATUS_CMD_OK);
1620		}
1621		return;
1622
1623	case USB_ST_SETUP:
1624		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
1625		usbd_transfer_submit(xfer);
1626		return;
1627
1628	default:
1629tr_error:
1630		DPRINTF_UMASS(sc, UDMASS_BBB, "Failed to read CSW: %s, try %d\n",
1631		    usbd_errstr(error), sc->sc_status_try);
1632
1633		if ((error == USB_ERR_CANCELLED) ||
1634		    (sc->sc_status_try)) {
1635			umass_tr_error(xfer, error);
1636		} else {
1637			sc->sc_status_try = 1;
1638			umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS);
1639		}
1640		return;
1641	}
1642}
1643
1644static int
1645umass_command_start(struct umass_softc *sc, uint8_t dir,
1646    void *data_ptr, uint32_t data_len,
1647    uint32_t data_timeout, umass_callback_t *callback,
1648    union ccb *umass_ccb)
1649{
1650	if (sc->sc_detach_status)
1651	{
1652		PRINT_WARN("[%s][%d] usb is detaching\n",__FUNCTION__,__LINE__);
1653		return (-1);
1654	}
1655
1656	/*
1657	 * NOTE: assumes that "sc->sc_transfer.cmd_data" and
1658	 * "sc->sc_transfer.cmd_len" has been properly
1659	 * initialized.
1660	 */
1661
1662	sc->sc_transfer.dir = data_len ? dir : DIR_NONE;
1663	sc->sc_transfer.data_ptr = (uint8_t *)data_ptr;
1664	sc->sc_transfer.data_len = data_len;
1665	sc->sc_transfer.data_rem = data_len;
1666	sc->sc_transfer.data_timeout = (data_timeout + UMASS_TIMEOUT);
1667
1668	sc->sc_transfer.actlen = 0;
1669	sc->sc_transfer.callback = callback;
1670	sc->sc_transfer.ccb = umass_ccb;
1671
1672	if (sc->sc_xfer[sc->sc_last_xfer_index]) {
1673		usbd_transfer_start(sc->sc_xfer[sc->sc_last_xfer_index]);
1674	} else {
1675		umass_cancel_ccb(sc);
1676	}
1677
1678	(void)LOS_EventRead(&sc->sc_event, 0xFF,
1679	    LOS_WAITMODE_OR | LOS_WAITMODE_CLR, 10 * LOSCFG_BASE_CORE_TICK_PER_SECOND); /* 10 seconds. */
1680
1681	return (0);
1682}
1683
1684static uint8_t
1685umass_bbb_get_max_lun(struct umass_softc *sc)
1686{
1687	struct usb_device_request req;
1688	usb_error_t err;
1689	uint8_t buf = 0;
1690
1691	/* The Get Max Lun command is a class-specific request. */
1692	req.bmRequestType = UT_READ_CLASS_INTERFACE;
1693	req.bRequest = UR_BBB_GET_MAX_LUN;
1694	USETW(req.wValue, 0);
1695	req.wIndex[0] = sc->sc_iface_no;
1696	req.wIndex[1] = 0;
1697	USETW(req.wLength, 1);
1698
1699	err = usbd_do_request(sc->sc_udev, NULL, &req, &buf);
1700	if (err) {
1701		buf = 0;
1702
1703		/* Device doesn't support Get Max Lun request. */
1704		PRINTK("%s: Get Max Lun not supported (%s)\n",
1705		    sc->sc_name, usbd_errstr(err));
1706	}
1707	return (buf);
1708}
1709
1710/*
1711 * Command/Bulk/Interrupt (CBI) specific functions
1712 */
1713
1714static void
1715umass_cbi_start_status(struct umass_softc *sc)
1716{
1717	if (sc->sc_xfer[UMASS_T_CBI_STATUS]) {
1718		umass_transfer_start(sc, UMASS_T_CBI_STATUS);
1719	} else {
1720		union ccb *umass_ccb = sc->sc_transfer.ccb;
1721
1722		sc->sc_transfer.ccb = NULL;
1723
1724		sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
1725
1726		(sc->sc_transfer.callback)
1727		    (sc, umass_ccb, (sc->sc_transfer.data_len -
1728		    sc->sc_transfer.actlen), STATUS_CMD_UNKNOWN);
1729	}
1730}
1731
1732static void
1733umass_t_cbi_reset1_callback(struct usb_xfer *xfer, usb_error_t error)
1734{
1735	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1736	struct usb_device_request req;
1737	struct usb_page_cache *pc;
1738	uint8_t buf[UMASS_CBI_DIAGNOSTIC_CMDLEN];
1739
1740	uint8_t i;
1741
1742	switch (USB_GET_STATE(xfer)) {
1743	case USB_ST_TRANSFERRED:
1744		umass_transfer_start(sc, UMASS_T_CBI_RESET2);
1745		break;
1746
1747	case USB_ST_SETUP:
1748		/*
1749		 * Command Block Reset Protocol
1750		 *
1751		 * First send a reset request to the device. Then clear
1752		 * any possibly stalled bulk endpoints.
1753		 *
1754		 * This is done in 3 steps, using 3 transfers:
1755		 * UMASS_T_CBI_RESET1
1756		 * UMASS_T_CBI_RESET2
1757		 * UMASS_T_CBI_RESET3
1758		 * UMASS_T_CBI_RESET4 (only if there is an interrupt endpoint)
1759		 */
1760
1761		DPRINTF_UMASS(sc, UDMASS_CBI, "CBI reset!\n");
1762
1763		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1764		req.bRequest = UR_CBI_ADSC;
1765		USETW(req.wValue, 0);
1766		req.wIndex[0] = sc->sc_iface_no;
1767		req.wIndex[1] = 0;
1768		USETW(req.wLength, UMASS_CBI_DIAGNOSTIC_CMDLEN);
1769
1770		/*
1771		 * The 0x1d code is the SEND DIAGNOSTIC command. To
1772		 * distinguish between the two, the last 10 bytes of the CBL
1773		 * is filled with 0xff (section 2.2 of the CBI
1774		 * specification)
1775		 */
1776		buf[0] = 0x1d;		/* Command Block Reset */
1777		buf[1] = 0x04;
1778
1779		for (i = 2; i < UMASS_CBI_DIAGNOSTIC_CMDLEN; i++) {
1780			buf[i] = 0xff;
1781		}
1782
1783		pc = usbd_xfer_get_frame(xfer, 0);
1784		usbd_copy_in(pc, 0, &req, sizeof(req));
1785		pc = usbd_xfer_get_frame(xfer, 1);
1786		usbd_copy_in(pc, 0, buf, sizeof(buf));
1787
1788		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1789		usbd_xfer_set_frame_len(xfer, 1, sizeof(buf));
1790		usbd_xfer_set_frames(xfer, 2);
1791		usbd_transfer_submit(xfer);
1792		break;
1793
1794	default:			/* Error */
1795		if (error == USB_ERR_CANCELLED)
1796			umass_tr_error(xfer, error);
1797		else
1798			umass_transfer_start(sc, UMASS_T_CBI_RESET2);
1799		break;
1800	}
1801}
1802
1803static void
1804umass_t_cbi_reset2_callback(struct usb_xfer *xfer, usb_error_t error)
1805{
1806	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_RESET3,
1807	    UMASS_T_CBI_DATA_READ, error);
1808}
1809
1810static void
1811umass_t_cbi_reset3_callback(struct usb_xfer *xfer, usb_error_t error)
1812{
1813	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1814
1815	umass_t_cbi_data_clear_stall_callback
1816	    (xfer, (sc->sc_xfer[UMASS_T_CBI_RESET4] &&
1817	    sc->sc_xfer[UMASS_T_CBI_STATUS]) ?
1818	    UMASS_T_CBI_RESET4 : UMASS_T_CBI_COMMAND,
1819	    UMASS_T_CBI_DATA_WRITE, error);
1820}
1821
1822static void
1823umass_t_cbi_reset4_callback(struct usb_xfer *xfer, usb_error_t error)
1824{
1825	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_COMMAND,
1826	    UMASS_T_CBI_STATUS, error);
1827}
1828
1829static void
1830umass_t_cbi_data_clear_stall_callback(struct usb_xfer *xfer,
1831    uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error)
1832{
1833	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1834
1835	switch (USB_GET_STATE(xfer)) {
1836	case USB_ST_TRANSFERRED:
1837tr_transferred:
1838		if (next_xfer == UMASS_T_CBI_STATUS) {
1839			umass_cbi_start_status(sc);
1840		} else {
1841			umass_transfer_start(sc, next_xfer);
1842		}
1843		break;
1844
1845	case USB_ST_SETUP:
1846		if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) {
1847			goto tr_transferred;	/* should not happen */
1848		}
1849		break;
1850
1851	default:			/* Error */
1852		umass_tr_error(xfer, error);
1853		break;
1854	}
1855}
1856
1857static void
1858umass_t_cbi_command_callback(struct usb_xfer *xfer, usb_error_t error)
1859{
1860	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1861	union ccb *umass_ccb = sc->sc_transfer.ccb;
1862	struct usb_device_request req;
1863	struct usb_page_cache *pc;
1864
1865	switch (USB_GET_STATE(xfer)) {
1866	case USB_ST_TRANSFERRED:
1867
1868		if (sc->sc_transfer.dir == DIR_NONE) {
1869			umass_cbi_start_status(sc);
1870		} else {
1871			umass_transfer_start
1872			    (sc, (sc->sc_transfer.dir == DIR_IN) ?
1873			    UMASS_T_CBI_DATA_READ : UMASS_T_CBI_DATA_WRITE);
1874		}
1875		break;
1876
1877	case USB_ST_SETUP:
1878
1879		if (umass_ccb) {
1880			/*
1881				 * do a CBI transfer with cmd_len bytes from
1882				 * cmd_data, possibly a data phase of data_len
1883				 * bytes from/to the device and finally a status
1884				 * read phase.
1885				 */
1886
1887			req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1888			req.bRequest = UR_CBI_ADSC;
1889			USETW(req.wValue, 0);
1890			req.wIndex[0] = sc->sc_iface_no;
1891			req.wIndex[1] = 0;
1892			req.wLength[0] = sc->sc_transfer.cmd_len;
1893			req.wLength[1] = 0;
1894
1895			pc = usbd_xfer_get_frame(xfer, 0);
1896			usbd_copy_in(pc, 0, &req, sizeof(req));
1897			pc = usbd_xfer_get_frame(xfer, 1);
1898			usbd_copy_in(pc, 0, sc->sc_transfer.cmd_data,
1899			    sc->sc_transfer.cmd_len);
1900
1901			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1902			usbd_xfer_set_frame_len(xfer, 1, sc->sc_transfer.cmd_len);
1903			usbd_xfer_set_frames(xfer,
1904			    sc->sc_transfer.cmd_len ? 2 : 1);
1905
1906			DIF(UDMASS_CBI,
1907			    umass_cbi_dump_cmd(sc,
1908			    sc->sc_transfer.cmd_data,
1909			    sc->sc_transfer.cmd_len));
1910
1911			usbd_transfer_submit(xfer);
1912		}
1913		break;
1914
1915	default:			/* Error */
1916		/*
1917		 * STALL on the control pipe can be result of the command error.
1918		 * Attempt to clear this STALL same as for bulk pipe also
1919		 * results in command completion interrupt, but ASC/ASCQ there
1920		 * look like not always valid, so don't bother about it.
1921		 */
1922		if ((error == USB_ERR_STALLED) ||
1923		    (sc->sc_transfer.callback == &umass_cam_cb)) {
1924			sc->sc_transfer.ccb = NULL;
1925			(sc->sc_transfer.callback)
1926			    (sc, umass_ccb, sc->sc_transfer.data_len,
1927			    STATUS_CMD_UNKNOWN);
1928		} else {
1929			umass_tr_error(xfer, error);
1930			/* skip reset */
1931			sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
1932		}
1933		break;
1934	}
1935}
1936
1937static void
1938umass_t_cbi_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
1939{
1940	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1941	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1942	int actlen, sumlen;
1943
1944	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1945
1946	switch (USB_GET_STATE(xfer)) {
1947	case USB_ST_TRANSFERRED:
1948		sc->sc_transfer.data_rem -= actlen;
1949		sc->sc_transfer.data_ptr += actlen;
1950		sc->sc_transfer.actlen += actlen;
1951
1952		if (actlen < sumlen) {
1953			/* short transfer */
1954			sc->sc_transfer.data_rem = 0;
1955		}
1956	case USB_ST_SETUP:
1957		DPRINTF_UMASS(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n",
1958		    max_bulk, sc->sc_transfer.data_rem);
1959
1960		if (sc->sc_transfer.data_rem == 0) {
1961			umass_cbi_start_status(sc);
1962			break;
1963		}
1964		if (max_bulk > sc->sc_transfer.data_rem) {
1965			max_bulk = sc->sc_transfer.data_rem;
1966		}
1967		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1968
1969		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1970		    max_bulk);
1971
1972		usbd_transfer_submit(xfer);
1973		break;
1974
1975	default:			/* Error */
1976		if ((error == USB_ERR_CANCELLED) ||
1977		    (sc->sc_transfer.callback != &umass_cam_cb)) {
1978			umass_tr_error(xfer, error);
1979		} else {
1980			umass_transfer_start(sc, UMASS_T_CBI_DATA_RD_CS);
1981		}
1982		break;
1983	}
1984}
1985
1986static void
1987umass_t_cbi_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1988{
1989	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS,
1990	    UMASS_T_CBI_DATA_READ, error);
1991}
1992
1993static void
1994umass_t_cbi_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
1995{
1996	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
1997	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1998	int actlen, sumlen;
1999
2000	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
2001
2002	switch (USB_GET_STATE(xfer)) {
2003	case USB_ST_TRANSFERRED:
2004		sc->sc_transfer.data_rem -= actlen;
2005		sc->sc_transfer.data_ptr += actlen;
2006		sc->sc_transfer.actlen += actlen;
2007
2008		if (actlen < sumlen) {
2009			/* short transfer */
2010			sc->sc_transfer.data_rem = 0;
2011		}
2012	case USB_ST_SETUP:
2013		DPRINTF_UMASS(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n",
2014		    max_bulk, sc->sc_transfer.data_rem);
2015
2016		if (sc->sc_transfer.data_rem == 0) {
2017			umass_cbi_start_status(sc);
2018			break;
2019		}
2020		if (max_bulk > sc->sc_transfer.data_rem) {
2021			max_bulk = sc->sc_transfer.data_rem;
2022		}
2023		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
2024
2025		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
2026		    max_bulk);
2027
2028		usbd_transfer_submit(xfer);
2029		break;
2030
2031	default:			/* Error */
2032		if ((error == USB_ERR_CANCELLED) ||
2033		    (sc->sc_transfer.callback != &umass_cam_cb)) {
2034			umass_tr_error(xfer, error);
2035		} else {
2036			umass_transfer_start(sc, UMASS_T_CBI_DATA_WR_CS);
2037		}
2038		break;
2039	}
2040}
2041
2042static void
2043umass_t_cbi_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
2044{
2045	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS,
2046	    UMASS_T_CBI_DATA_WRITE, error);
2047}
2048
2049static void
2050umass_t_cbi_status_callback(struct usb_xfer *xfer, usb_error_t error)
2051{
2052	struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer);
2053	union ccb *umass_ccb = sc->sc_transfer.ccb;
2054	struct usb_page_cache *pc;
2055	uint32_t residue;
2056	uint8_t status;
2057	int actlen;
2058
2059	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
2060
2061	switch (USB_GET_STATE(xfer)) {
2062	case USB_ST_TRANSFERRED:
2063
2064		if (actlen < (int)sizeof(sc->sbl)) {
2065			goto tr_setup;
2066		}
2067		pc = usbd_xfer_get_frame(xfer, 0);
2068		usbd_copy_out(pc, 0, &sc->sbl, sizeof(sc->sbl));
2069
2070		residue = (sc->sc_transfer.data_len -
2071		    sc->sc_transfer.actlen);
2072
2073		/* dissect the information in the buffer */
2074
2075		if (sc->sc_proto & UMASS_PROTO_UFI) {
2076			/*
2077			 * Section 3.4.3.1.3 specifies that the UFI command
2078			 * protocol returns an ASC and ASCQ in the interrupt
2079			 * data block.
2080			 */
2081
2082			DPRINTF_UMASS(sc, UDMASS_CBI, "UFI CCI, ASC = 0x%02x, "
2083			    "ASCQ = 0x%02x\n", sc->sbl.ufi.asc,
2084			    sc->sbl.ufi.ascq);
2085
2086			status = (((sc->sbl.ufi.asc == 0) &&
2087			    (sc->sbl.ufi.ascq == 0)) ?
2088			    STATUS_CMD_OK : STATUS_CMD_FAILED);
2089
2090			sc->sc_transfer.ccb = NULL;
2091
2092			sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
2093
2094			(sc->sc_transfer.callback)
2095			    (sc, umass_ccb, residue, status);
2096
2097			break;
2098
2099		} else {
2100			/* Command Interrupt Data Block */
2101
2102			DPRINTF_UMASS(sc, UDMASS_CBI, "type=0x%02x, value=0x%02x\n",
2103			    sc->sbl.common.type, sc->sbl.common.value);
2104
2105			if (sc->sbl.common.type == IDB_TYPE_CCI) {
2106				status = (sc->sbl.common.value & IDB_VALUE_STATUS_MASK);
2107
2108				status = ((status == IDB_VALUE_PASS) ? STATUS_CMD_OK :
2109				    (status == IDB_VALUE_FAIL) ? STATUS_CMD_FAILED :
2110				    (status == IDB_VALUE_PERSISTENT) ? STATUS_CMD_FAILED :
2111				    STATUS_WIRE_FAILED);
2112
2113				sc->sc_transfer.ccb = NULL;
2114
2115				sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
2116
2117				(sc->sc_transfer.callback)
2118				    (sc, umass_ccb, residue, status);
2119
2120				break;
2121			}
2122		}
2123
2124		/* fallthrough */
2125
2126	case USB_ST_SETUP:
2127tr_setup:
2128		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
2129		usbd_transfer_submit(xfer);
2130		break;
2131
2132	default:			/* Error */
2133		DPRINTF_UMASS(sc, UDMASS_CBI, "Failed to read CSW: %s\n",
2134		    usbd_errstr(error));
2135		umass_tr_error(xfer, error);
2136		break;
2137	}
2138}
2139
2140/* umass_cam_cb
2141 *	finalise a completed CAM command
2142 */
2143
2144static void
2145umass_cam_cb(struct umass_softc *sc, union ccb *umass_ccb, uint32_t residue,
2146	uint8_t status)
2147{
2148	umass_ccb->csio.resid = residue;
2149	umass_ccb->csio.status = status;
2150
2151	switch (status) {
2152	case STATUS_CMD_OK:
2153		(void)LOS_EventWrite(&sc->sc_event, 0x01);
2154		break;
2155
2156	case STATUS_CMD_UNKNOWN:
2157	case STATUS_CMD_FAILED:
2158		/* fetch sense data */
2159		(void)LOS_EventWrite(&sc->sc_event, 0x02);
2160		break;
2161
2162	default:
2163		(void)LOS_EventWrite(&sc->sc_event, 0x04);
2164		break;
2165	}
2166}
2167
2168/*
2169 * SCSI specific functions
2170 */
2171
2172static uint8_t
2173umass_scsi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
2174	uint8_t cmd_len)
2175{
2176	int ret;
2177
2178	if ((cmd_len == 0) ||
2179		(cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2180		DPRINTF_UMASS(sc, UDMASS_SCSI, "Invalid command "
2181		    "length: %d bytes\n", cmd_len);
2182		return (0);		/* failure */
2183	}
2184	sc->sc_transfer.cmd_len = cmd_len;
2185
2186	switch (cmd_ptr[0]) {
2187	case TEST_UNIT_READY:
2188		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
2189			DPRINTF_UMASS(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY "
2190			    "to START_UNIT\n");
2191			ret = memset_s(sc->sc_transfer.cmd_data, sizeof(sc->sc_transfer.cmd_data), 0, cmd_len);
2192			if (ret != EOK) {
2193				usb_err("memset_s failed!, ret:%d\n", ret);
2194				return (0);
2195			}
2196			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
2197			sc->sc_transfer.cmd_data[4] = SSS_START;
2198			return (1);
2199		}
2200		break;
2201
2202	case INQUIRY:
2203		/*
2204		 * some drives wedge when asked for full inquiry
2205		 * information.
2206		 */
2207		if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
2208			ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len);
2209			if (ret != EOK) {
2210				usb_err("memcpy_s failed!, ret:%d\n", ret);
2211				return (0);
2212			}
2213			sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
2214			return (1);
2215		}
2216		break;
2217	}
2218
2219	ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len);
2220	if (ret != EOK) {
2221		usb_err("memcpy_s failed!, ret:%d\n", ret);
2222		return (0);
2223	}
2224
2225	return (1);
2226}
2227
2228static uint8_t
2229umass_rbc_transform(struct umass_softc *sc, uint8_t *cmd_ptr, uint8_t cmd_len)
2230{
2231	int ret;
2232
2233	if ((cmd_len == 0) ||
2234		(cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2235		DPRINTF_UMASS(sc, UDMASS_SCSI, "Invalid command "
2236		    "length: %d bytes\n", cmd_len);
2237		return (0);		/* failure */
2238	}
2239	switch (cmd_ptr[0]) {
2240	/* these commands are defined in RBC: */
2241	case READ_10:
2242	case READ_CAPACITY:
2243	case START_STOP_UNIT:
2244	case SYNCHRONIZE_CACHE:
2245	case WRITE_10:
2246	case 0x2f:			/* VERIFY_10 is absent from * scsi_all.h??? */
2247	case INQUIRY:
2248	case MODE_SELECT_10:
2249	case MODE_SENSE_10:
2250	case TEST_UNIT_READY:
2251	case WRITE_BUFFER:
2252		/*
2253		 * The following commands are not listed in my copy of the
2254		 * RBC specs. CAM however seems to want those, and at least
2255		 * the Sony DSC device appears to support those as well
2256		 */
2257	case REQUEST_SENSE:
2258	case PREVENT_ALLOW:
2259
2260		ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len);
2261		if (ret != EOK) {
2262			usb_err("memcpy_s failed!, ret:%d\n", ret);
2263			return (0);
2264		}
2265
2266		if ((sc->sc_quirks & RBC_PAD_TO_12) && (cmd_len < 12)) {
2267			ret = memset_s(sc->sc_transfer.cmd_data + cmd_len,
2268			    (size_t)(UMASS_MAX_CMDLEN - cmd_len), 0, (size_t)(12 - cmd_len));
2269			if (ret != EOK){
2270				usb_err("memset_s failed!, ret:%d\n", ret);
2271				return (0);
2272			}
2273			cmd_len = 12;
2274		}
2275		sc->sc_transfer.cmd_len = cmd_len;
2276		return (1);		/* sucess */
2277
2278		/* All other commands are not legal in RBC */
2279	default:
2280		DPRINTF_UMASS(sc, UDMASS_SCSI, "Unsupported RBC "
2281		    "command 0x%02x\n", cmd_ptr[0]);
2282		return (0);		/* failure */
2283	}
2284}
2285
2286static uint8_t
2287umass_ufi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
2288    uint8_t cmd_len)
2289{
2290	int ret;
2291
2292	if ((cmd_len == 0) ||
2293		(cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2294		DPRINTF_UMASS(sc, UDMASS_SCSI, "Invalid command "
2295		    "length: %d bytes\n", cmd_len);
2296		return (0);		/* failure */
2297	}
2298	/* An UFI command is always 12 bytes in length */
2299	sc->sc_transfer.cmd_len = UFI_COMMAND_LENGTH;
2300
2301	/* Zero the command data */
2302	ret = memset_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, 0, UFI_COMMAND_LENGTH);
2303	if (ret != EOK) {
2304		usb_err("memset_s failed!, ret:%d\n", ret);
2305		return (0);
2306	}
2307
2308	switch (cmd_ptr[0]) {
2309		/*
2310		 * Commands of which the format has been verified. They
2311		 * should work. Copy the command into the (zeroed out)
2312		 * destination buffer.
2313		 */
2314	case TEST_UNIT_READY:
2315		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
2316			/*
2317			 * Some devices do not support this command. Start
2318			 * Stop Unit should give the same results
2319			 */
2320			DPRINTF_UMASS(sc, UDMASS_UFI, "Converted TEST_UNIT_READY "
2321			    "to START_UNIT\n");
2322
2323			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
2324			sc->sc_transfer.cmd_data[4] = SSS_START;
2325			return (1);
2326		}
2327		break;
2328
2329	case REZERO_UNIT:
2330	case REQUEST_SENSE:
2331	case FORMAT_UNIT:
2332	case INQUIRY:
2333	case START_STOP_UNIT:
2334	case SEND_DIAGNOSTIC:
2335	case PREVENT_ALLOW:
2336	case READ_CAPACITY:
2337	case READ_10:
2338	case WRITE_10:
2339	case POSITION_TO_ELEMENT:	/* SEEK_10 */
2340	case WRITE_AND_VERIFY:
2341	case VERIFIED:
2342	case MODE_SELECT_10:
2343	case MODE_SENSE_10:
2344	case READ_12:
2345	case WRITE_12:
2346	case READ_FORMAT_CAPACITIES:
2347		break;
2348
2349		/*
2350		 * SYNCHRONIZE_CACHE isn't supported by UFI, nor should it be
2351		 * required for UFI devices, so it is appropriate to fake
2352		 * success.
2353		 */
2354	case SYNCHRONIZE_CACHE:
2355		return (2);
2356
2357	default:
2358		DPRINTF_UMASS(sc, UDMASS_SCSI, "Unsupported UFI "
2359		    "command 0x%02x\n", cmd_ptr[0]);
2360		return (0);		/* failure */
2361	}
2362
2363	ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len);
2364	if (ret != EOK) {
2365		usb_err("memcpy_s failed!, ret:%d\n", ret);
2366		return (0);
2367	}
2368
2369	return (1);			/* success */
2370}
2371
2372/*
2373 * 8070i (ATAPI) specific functions
2374 */
2375static uint8_t
2376umass_atapi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
2377    uint8_t cmd_len)
2378{
2379	int ret;
2380
2381	if ((cmd_len == 0) ||
2382		(cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2383		DPRINTF_UMASS(sc, UDMASS_SCSI, "Invalid command "
2384		    "length: %d bytes\n", cmd_len);
2385		return (0);		/* failure */
2386	}
2387	/* An ATAPI command is always 12 bytes in length. */
2388	sc->sc_transfer.cmd_len = ATAPI_COMMAND_LENGTH;
2389
2390	/* Zero the command data */
2391	ret = memset_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, 0, ATAPI_COMMAND_LENGTH);
2392	if (ret != EOK) {
2393		usb_err("memset_s failed!, ret:%d\n", ret);
2394		return (0);
2395	}
2396
2397	switch (cmd_ptr[0]) {
2398		/*
2399		 * Commands of which the format has been verified. They
2400		 * should work. Copy the command into the destination
2401		 * buffer.
2402		 */
2403	case INQUIRY:
2404		/*
2405		 * some drives wedge when asked for full inquiry
2406		 * information.
2407		 */
2408		if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
2409			ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len);
2410			if (ret != EOK) {
2411				usb_err("memcpy_s failed!, ret:%d\n", ret);
2412				return (0);
2413			}
2414			sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
2415			return (1);
2416		}
2417		break;
2418
2419	case TEST_UNIT_READY:
2420		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
2421			DPRINTF_UMASS(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY "
2422			    "to START_UNIT\n");
2423			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
2424			sc->sc_transfer.cmd_data[4] = SSS_START;
2425			return (1);
2426		}
2427		break;
2428
2429	case REZERO_UNIT:
2430	case REQUEST_SENSE:
2431	case START_STOP_UNIT:
2432	case SEND_DIAGNOSTIC:
2433	case PREVENT_ALLOW:
2434	case READ_CAPACITY:
2435	case READ_10:
2436	case WRITE_10:
2437	case POSITION_TO_ELEMENT:	/* SEEK_10 */
2438	case SYNCHRONIZE_CACHE:
2439	case MODE_SELECT_10:
2440	case MODE_SENSE_10:
2441	case READ_BUFFER:
2442	case 0x42:			/* READ_SUBCHANNEL */
2443	case 0x43:			/* READ_TOC */
2444	case 0x44:			/* READ_HEADER */
2445	case 0x47:			/* PLAY_MSF (Play Minute/Second/Frame) */
2446	case 0x48:			/* PLAY_TRACK */
2447	case 0x49:			/* PLAY_TRACK_REL */
2448	case 0x4b:			/* PAUSE */
2449	case 0x51:			/* READ_DISK_INFO */
2450	case 0x52:			/* READ_TRACK_INFO */
2451	case 0x54:			/* SEND_OPC */
2452	case 0x59:			/* READ_MASTER_CUE */
2453	case 0x5b:			/* CLOSE_TR_SESSION */
2454	case 0x5c:			/* READ_BUFFER_CAP */
2455	case 0x5d:			/* SEND_CUE_SHEET */
2456	case 0xa1:			/* BLANK */
2457	case 0xa5:			/* PLAY_12 */
2458	case 0xa6:			/* EXCHANGE_MEDIUM */
2459	case 0xad:			/* READ_DVD_STRUCTURE */
2460	case 0xbb:			/* SET_CD_SPEED */
2461	case 0xe5:			/* READ_TRACK_INFO_PHILIPS */
2462		break;
2463
2464	case READ_12:
2465	case WRITE_12:
2466	default:
2467		DPRINTF_UMASS(sc, UDMASS_SCSI, "Unsupported ATAPI "
2468		    "command 0x%02x - trying anyway\n",
2469		    cmd_ptr[0]);
2470		break;
2471	}
2472
2473	ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len);
2474	if (ret != EOK) {
2475		usb_err("memcpy_s failed!, ret:%d\n", ret);
2476		return (0);
2477	}
2478
2479	return (1);			/* success */
2480}
2481
2482static uint8_t
2483umass_no_transform(struct umass_softc *sc, uint8_t *cmd,
2484	uint8_t cmdlen)
2485{
2486	return (0);			/* failure */
2487}
2488
2489#ifdef LOSCFG_USB_DEBUG
2490static void
2491umass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw)
2492{
2493	uint8_t *c = cbw->CBWCDB;
2494
2495	uint32_t dlen = UGETDW(cbw->dCBWDataTransferLength);
2496	uint32_t tag = UGETDW(cbw->dCBWTag);
2497
2498	uint8_t clen = cbw->bCDBLength;
2499	uint8_t flags = cbw->bCBWFlags;
2500	uint8_t lun = cbw->bCBWLUN;
2501
2502	DPRINTF_UMASS(sc, UDMASS_BBB, "CBW %d: cmd = %db "
2503	    "(0x%02x%02x%02x%02x%02x%02x%s), "
2504	    "data = %db, lun = %d, dir = %s\n",
2505	    tag, clen,
2506	    c[0], c[1], c[2], c[3], c[4], c[5], (clen > 6 ? "..." : ""),
2507	    dlen, lun, (flags == CBWFLAGS_IN ? "in" :
2508	    (flags == CBWFLAGS_OUT ? "out" : "<invalid>")));
2509}
2510
2511static void
2512umass_bbb_dump_csw(struct umass_softc *sc, umass_bbb_csw_t *csw)
2513{
2514	uint32_t sig = UGETDW(csw->dCSWSignature);
2515	uint32_t tag = UGETDW(csw->dCSWTag);
2516	uint32_t res = UGETDW(csw->dCSWDataResidue);
2517	uint8_t status = csw->bCSWStatus;
2518
2519	DPRINTF_UMASS(sc, UDMASS_BBB, "CSW %d: sig = 0x%08x (%s), tag = 0x%08x, "
2520	    "res = %d, status = 0x%02x (%s)\n",
2521	    tag, sig, (sig == CSWSIGNATURE ? "valid" : "invalid"),
2522	    tag, res,
2523	    status, (status == CSWSTATUS_GOOD ? "good" :
2524	    (status == CSWSTATUS_FAILED ? "failed" :
2525	    (status == CSWSTATUS_PHASE ? "phase" : "<invalid>"))));
2526}
2527
2528static void
2529umass_cbi_dump_cmd(struct umass_softc *sc, void *cmd, uint8_t cmdlen)
2530{
2531	uint8_t *c = cmd;
2532	uint8_t dir = sc->sc_transfer.dir;
2533
2534	DPRINTF_UMASS(sc, UDMASS_BBB, "cmd = %db "
2535	    "(0x%02x%02x%02x%02x%02x%02x%s), "
2536	    "data = %db, dir = %s\n",
2537	    cmdlen,
2538	    c[0], c[1], c[2], c[3], c[4], c[5], (cmdlen > 6 ? "..." : ""),
2539	    sc->sc_transfer.data_len,
2540	    (dir == DIR_IN ? "in" :
2541	    (dir == DIR_OUT ? "out" :
2542	    (dir == DIR_NONE ? "no data phase" : "<invalid>"))));
2543}
2544
2545#endif
2546
2547#define	SCSI_INQ_LEN	0x24
2548
2549static uint8_t scsi_test_unit_ready[] = {
2550	0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2551};
2552static uint8_t scsi_inquiry[] = {
2553	0x12, 0x00, 0x00, 0x00, SCSI_INQ_LEN, 0x00
2554};
2555static uint8_t scsi_request_sense[] = {
2556	0x03, 0x00, 0x00, 0x00, 0x12, 0x00,
2557	0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2558};
2559static uint8_t scsi_read_capacity[] = {
2560	0x25, 0x00, 0x00, 0x00, 0x00,
2561	0x00, 0x00, 0x00, 0x00, 0x00
2562};
2563
2564static uint8_t scsi_read_capacity_16[] = {
2565	0x9e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2566	0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00
2567};
2568
2569/* Description: Get a (possibly unaligned) 16-bit big endian value. */
2570static inline uint16_t
2571usbhost_getbe16(const uint8_t *val)
2572{
2573	return ((uint16_t)val[0] << 8 | (uint16_t)val[1]);
2574}
2575
2576/* Description: Put a (possibly unaligned) 16-bit little endian value. */
2577void
2578usbhost_putle16(uint8_t *dest, uint16_t val)
2579{
2580	dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
2581	dest[1] = val >> 8;
2582}
2583
2584/* Description: Put a (possibly unaligned) 16-bit big endian value. */
2585void
2586usbhost_putbe16(uint8_t *dest, uint16_t val)
2587{
2588	dest[0] = val >> 8; /* Big endian means MS byte first in byte stream */
2589	dest[1] = val & 0xff;
2590}
2591
2592/* Description: Get a (possibly unaligned) 32-bit big endian value. */
2593uint32_t
2594usbhost_getbe32(const uint8_t *val)
2595{
2596	/* Big endian means MS halfword first in byte stream */
2597	return ((uint32_t)usbhost_getbe16(val) << 16 |
2598	    (uint32_t)usbhost_getbe16(&val[2]));
2599}
2600
2601/* Description: Get a (possibly unaligned) 64-bit big endian value. */
2602uint64_t
2603usbhost_getbe64(const uint8_t *val)
2604{
2605	/* Big endian means MS halfword first in byte stream */
2606	return ((uint64_t)usbhost_getbe32(val) << 32 |
2607	    (uint64_t)usbhost_getbe32(&val[4]));
2608}
2609
2610/* Description: Put a (possibly unaligned) 32-bit little endian value. */
2611void
2612usbhost_putle32(uint8_t *dest, uint32_t val)
2613{
2614	/* Little endian means LS halfword first in byte stream  */
2615	usbhost_putle16(dest, (uint16_t)(val & 0xffff));
2616	usbhost_putle16(dest+2, (uint16_t)(val >> 16));
2617}
2618
2619/* Put a (possibly unaligned) 32-bit big endian value. */
2620void
2621usbhost_putbe32(uint8_t *dest, uint32_t val)
2622{
2623	/* Big endian means MS halfword first in byte stream */
2624	usbhost_putbe16(dest, (uint16_t)(val >> 16));
2625	usbhost_putbe16(dest+2, (uint16_t)(val & 0xffff));
2626}
2627
2628/* Put a (possibly unaligned) 64-bit big endian value. */
2629void
2630usbhost_putbe64(uint8_t *dest, uint64_t val)
2631{
2632	/* Big endian means MS halfword first in byte stream */
2633	usbhost_putbe32(dest, (uint32_t)(val >> 32));
2634	usbhost_putbe32(dest+4, (uint32_t)(val & 0xffffffff));
2635}
2636
2637void
2638usbhost_readcdb16(uint64_t startsector, uint16_t blocksize,
2639    unsigned int nsectors, struct scsicmd_read16_s *cdb)
2640{
2641	struct scsicmd_read16_s *rd16 = (struct scsicmd_read16_s *)cdb;
2642
2643	/* Format the CDB */
2644	rd16->opcode = SCSI_CMD_READ16;
2645	usbhost_putbe64(rd16->lba, startsector);
2646	usbhost_putbe32(rd16->xfrlen, nsectors);
2647}
2648
2649void
2650usbhost_readcdb10(size_t startsector, uint16_t blocksize,
2651    unsigned int nsectors, struct scsicmd_read10_s *cdb)
2652{
2653	struct scsicmd_read10_s *rd10 = (struct scsicmd_read10_s *)cdb;
2654
2655	/* Format the CDB */
2656	rd10->opcode = SCSI_CMD_READ10;
2657	usbhost_putbe32(rd10->lba, startsector);
2658	usbhost_putbe16(rd10->xfrlen, nsectors);
2659}
2660
2661void
2662usbhost_writecbw16(uint64_t startsector, uint16_t blocksize,
2663    unsigned int nsectors, struct scsicmd_write16_s *cdb)
2664{
2665	struct scsicmd_write16_s *wr16 = (struct scsicmd_write16_s *)cdb;
2666
2667	wr16->opcode = SCSI_CMD_WRITE16;
2668	usbhost_putbe64(wr16->lba, startsector);
2669	usbhost_putbe32(wr16->xfrlen, nsectors);
2670}
2671
2672void
2673usbhost_writecbw10(size_t startsector, uint16_t blocksize,
2674    unsigned int nsectors, struct scsicmd_write10_s *cdb)
2675{
2676	struct scsicmd_write10_s *wr10 = (struct scsicmd_write10_s *)cdb;
2677
2678	wr10->opcode = SCSI_CMD_WRITE10;
2679	usbhost_putbe32(wr10->lba, startsector);
2680	usbhost_putbe16(wr10->xfrlen, nsectors);
2681}
2682
2683int
2684umass_test_unit_ready(struct umass_softc *sc)
2685{
2686	uint32_t status;
2687	int32_t res;
2688
2689	if((sc == NULL) || (sc->data_ccb == NULL)) {
2690		return (-1);
2691	}
2692
2693	(void)umass_scsi_transform(sc, scsi_test_unit_ready, SCSICMD_TESTUNITREADY8_SIZEOF);
2694	res = umass_command_start(sc, DIR_NONE, NULL, 0, 1000, umass_cam_cb, sc->data_ccb);
2695	if (STATUS_CMD_OK != res) {
2696		return (-1);
2697	}
2698
2699	status = sc->data_ccb->csio.status;
2700	if (status != STATUS_CMD_OK) {
2701		return (-1);
2702	}
2703
2704	return (0);
2705}
2706
2707int
2708umass_read_capacity_16(struct umass_softc *sc)
2709{
2710	struct scsiresp_readcapacity16_s resp;
2711	uint32_t res;
2712	int ret;
2713
2714	(void)umass_scsi_transform(sc, scsi_read_capacity_16, SCSICMD_READCAPACITY16_SIZEOF);
2715	res = (uint32_t)umass_command_start(sc, DIR_IN, sc->data_ccb->csio.data_ptr,
2716	    (uint32_t)SCSIRESP_READCAPACITY16_SIZEOF,
2717	    (uint32_t)1000, umass_cam_cb, sc->data_ccb);
2718	if (STATUS_CMD_OK != res) {
2719		return (-1);
2720	}
2721
2722	ret = memcpy_s((void *)&resp, sizeof(resp), sc->data_ccb->csio.data_ptr,
2723	    SCSIRESP_READCAPACITY16_SIZEOF);
2724	if (ret != EOK) {
2725		usb_err("memcpy_s failed, %d\n", ret);
2726		return (-1);
2727	}
2728
2729	sc->info.sectornum= usbhost_getbe64(resp.lba) + 1;
2730	sc->info.sectorsize= usbhost_getbe32(resp.blklen);
2731
2732	return (0);
2733}
2734
2735int
2736umass_read_capacity(struct umass_softc *sc)
2737{
2738	struct scsiresp_readcapacity10_s resp;
2739	int32_t ret;
2740
2741	if ((sc == NULL) || (sc->data_ccb == NULL)) {
2742		return (-1);
2743	}
2744
2745	(void)umass_scsi_transform(sc, scsi_read_capacity, SCSICMD_READCAPACITY10_SIZEOF);
2746	ret = umass_command_start(sc, DIR_IN, sc->data_ccb->csio.data_ptr,
2747	    SCSIRESP_READCAPACITY10_SIZEOF,
2748	    1000, umass_cam_cb, sc->data_ccb);
2749	if (STATUS_CMD_OK != ret) {
2750		return (-1);
2751	}
2752
2753	ret = memcpy_s((void *)&resp, sizeof(resp), sc->data_ccb->csio.data_ptr,
2754	    SCSIRESP_READCAPACITY10_SIZEOF);
2755	if (ret != EOK) {
2756		usb_err("memcpy_s failed, %d\n", ret);
2757		return (-1);
2758	}
2759
2760	/* The disk Capacity is bigger than 2T */
2761	if (usbhost_getbe32(resp.lba) == 0xffffffff) {
2762		ret = umass_read_capacity_16(sc);
2763		if (ret != 0) {
2764			usb_err("Read Capacity failed, %d\n", ret);
2765			return (-1);
2766		}
2767		sc->sc_super_disk = TRUE;
2768
2769		return (0);
2770	}
2771
2772	sc->info.sectornum= usbhost_getbe32(resp.lba) + 1;
2773	sc->info.sectorsize= usbhost_getbe32(resp.blklen);
2774	sc->sc_super_disk = FALSE;
2775
2776	return (0);
2777}
2778
2779int
2780umass_read10(struct umass_softc *sc, size_t startsector, uint16_t blocksize,
2781    unsigned int nsectors, unsigned char *buf)
2782{
2783	struct scsicmd_read10_s cdb;
2784	uint8_t *data_buf = buf;
2785	uint32_t status;
2786	int32_t ret;
2787	uint32_t flag = 0;
2788
2789	if ((sc == NULL) || (sc->data_ccb == NULL)) {
2790		return (-1);
2791	}
2792
2793	if ((sc->info.sectornum < (startsector + nsectors)) || (sc->info.sectorsize < blocksize))
2794		return (-1);
2795
2796	if (((uintptr_t)data_buf & (USB_CACHE_ALIGN_SIZE - 1)) != 0)
2797	{
2798		data_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(nsectors * blocksize));
2799		if (data_buf == NULL) {
2800			PRINT_ERR("Malloc failed!->%s %d\n", __FUNCTION__, __LINE__);
2801			return (-1);
2802		}
2803		flag = 1;
2804	}
2805
2806	(void)memset_s(&cdb, sizeof(struct scsicmd_read10_s), 0, sizeof(struct scsicmd_read10_s));
2807	usbhost_readcdb10(startsector, blocksize, nsectors, &cdb);
2808	(void)umass_scsi_transform(sc, (uint8_t *)&cdb, SCSICMD_READ10_SIZEOF);
2809	ret = umass_command_start(sc, DIR_IN, (void *)data_buf, blocksize * nsectors, 0,
2810	    umass_cam_cb, sc->data_ccb);
2811	if (ret != STATUS_CMD_OK) {
2812		if (flag == 1)
2813			free(data_buf);
2814		return (-1);
2815	}
2816
2817	if (flag == 1) {
2818		if (!LOS_IsUserAddressRange((vaddr_t)buf, blocksize * nsectors - sc->data_ccb->csio.resid)) {
2819			ret = memcpy_s(buf, nsectors * blocksize, data_buf, blocksize * nsectors - sc->data_ccb->csio.resid);
2820		} else {
2821			ret = ((nsectors * blocksize >= blocksize * nsectors - sc->data_ccb->csio.resid) ?
2822				LOS_ArchCopyToUser(buf, data_buf, blocksize * nsectors - sc->data_ccb->csio.resid) : ERANGE_AND_RESET);
2823		}
2824		free(data_buf);
2825		if (ret != EOK) {
2826			return (-1);
2827		}
2828	}
2829
2830	status = sc->data_ccb->csio.status;
2831	if (status != STATUS_CMD_OK) {
2832		return (-1);
2833	}
2834
2835	return (0);
2836}
2837
2838int
2839umass_read16(struct umass_softc *sc, uint64_t startsector, uint16_t blocksize,
2840    unsigned int nsectors, unsigned char *buf)
2841{
2842	struct scsicmd_read16_s cdb;
2843	uint8_t *data_buf = buf;
2844	uint32_t status;
2845	uint32_t res;
2846	uint32_t flag = 0;
2847	int ret;
2848
2849	if ((sc == NULL) || (sc->data_ccb == NULL)) {
2850		return (-1);
2851	}
2852
2853	if ((sc->info.sectornum < (startsector + nsectors)) || (sc->info.sectorsize < blocksize))
2854		return (-1);
2855
2856	if (((uintptr_t)data_buf & (USB_CACHE_ALIGN_SIZE - 1)) != 0) {
2857		data_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(nsectors * blocksize));
2858		if (data_buf == NULL) {
2859			PRINT_ERR("Malloc failed!->%s %d\n", __FUNCTION__, __LINE__);
2860			return (-1);
2861		}
2862		flag = 1;
2863	}
2864
2865	(void)memset_s(&cdb, sizeof(struct scsicmd_read16_s), 0, sizeof(struct scsicmd_read16_s));
2866	usbhost_readcdb16(startsector, blocksize, nsectors, &cdb);
2867	(void)umass_scsi_transform(sc, (uint8_t *)&cdb, SCSICMD_READ16_SIZEOF);
2868	res = umass_command_start(sc, DIR_IN, (void *)data_buf, blocksize * nsectors, 0,
2869	    umass_cam_cb, sc->data_ccb);
2870	if (STATUS_CMD_OK != res) {
2871		if (flag == 1)
2872			free(data_buf);
2873		return (-1);
2874	}
2875
2876	if (flag == 1) {
2877		if (!LOS_IsUserAddressRange((vaddr_t)buf, blocksize * nsectors - sc->data_ccb->csio.resid)) {
2878			ret = memcpy_s(buf, nsectors * blocksize, data_buf, blocksize * nsectors - sc->data_ccb->csio.resid);
2879		} else {
2880			ret = ((nsectors * blocksize >= blocksize * nsectors - sc->data_ccb->csio.resid) ?
2881				LOS_ArchCopyToUser(buf, data_buf, blocksize * nsectors - sc->data_ccb->csio.resid) : ERANGE_AND_RESET);
2882		}
2883		free(data_buf);
2884		if (ret != EOK) {
2885			return (-1);
2886		}
2887	}
2888
2889	status = sc->data_ccb->csio.status;
2890	if (status != STATUS_CMD_OK) {
2891		return (-1);
2892	}
2893
2894	return (0);
2895}
2896
2897int
2898umass_write10(struct umass_softc *sc, size_t startsector, uint16_t blocksize,
2899    unsigned int nsectors, const unsigned char *buf)
2900{
2901	struct scsicmd_write10_s cdb;
2902	uint8_t *data_buf = (uint8_t *)buf;
2903	uint32_t status;
2904	int32_t ret;
2905	uint32_t flag = 0;
2906
2907	if((sc == NULL) || (sc->data_ccb == NULL)) {
2908		return (-1);
2909	}
2910
2911	if ((sc->info.sectornum < (startsector + nsectors)) || (sc->info.sectorsize < blocksize))
2912		return (-1);
2913
2914	if (((uintptr_t)data_buf & (USB_CACHE_ALIGN_SIZE - 1)) != 0) {
2915		data_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(nsectors * blocksize));
2916		if (data_buf == NULL) {
2917			PRINT_ERR("Malloc failed!->%s %d\n", __FUNCTION__, __LINE__);
2918			return (-1);
2919		}
2920
2921		if (!LOS_IsUserAddressRange((vaddr_t)buf, blocksize * nsectors)) {
2922			(void)memcpy_s(data_buf, blocksize * nsectors, buf, blocksize * nsectors);
2923		} else {
2924			ret = LOS_ArchCopyFromUser(data_buf, buf, blocksize * nsectors);
2925			if (ret != 0) {
2926				free(data_buf);
2927				PRINT_ERR("copy failed!->%s %d\n", __FUNCTION__, __LINE__);
2928				return (-1);
2929			}
2930		}
2931		flag = 1;
2932	}
2933
2934	(void)memset_s(&cdb, sizeof(struct scsicmd_write10_s), 0, sizeof(struct scsicmd_write10_s));
2935	usbhost_writecbw10(startsector, blocksize, nsectors, &cdb);
2936	(void)umass_scsi_transform(sc, (uint8_t *)&cdb, SCSICMD_WRITE10_SIZEOF);
2937	ret = umass_command_start(sc, DIR_OUT, (void *)data_buf, blocksize * nsectors, 1000,
2938	    umass_cam_cb, sc->data_ccb);
2939
2940	if (flag == 1) {
2941		free(data_buf);
2942	}
2943
2944	status = sc->data_ccb->csio.status;
2945	if ((ret != STATUS_CMD_OK) || (status != STATUS_CMD_OK)) {
2946		return (-1);
2947	}
2948
2949	return (0);
2950}
2951
2952int
2953umass_write16(struct umass_softc *sc, uint64_t startsector, uint16_t blocksize,
2954    unsigned int nsectors, const unsigned char *buf)
2955{
2956	struct scsicmd_write16_s cdb;
2957	uint8_t *data_buf = (uint8_t *)buf;
2958	uint32_t status;
2959	int32_t  res;
2960	int32_t ret;
2961	uint32_t flag = 0;
2962
2963	if((sc == NULL) || (sc->data_ccb == NULL)) {
2964		return (-1);
2965	}
2966
2967	if ((sc->info.sectornum < (startsector + nsectors)) || (sc->info.sectorsize < blocksize)) {
2968		return (-1);
2969	}
2970
2971	if (((uintptr_t)data_buf & (USB_CACHE_ALIGN_SIZE - 1)) != 0)
2972	{
2973		data_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(nsectors * blocksize));
2974		if (data_buf == NULL) {
2975			PRINT_ERR("Malloc failed!->%s %d\n", __FUNCTION__, __LINE__);
2976			return (-1);
2977		}
2978
2979		if (!LOS_IsUserAddressRange((vaddr_t)buf, blocksize * nsectors)) {
2980			(void)memcpy_s(data_buf, blocksize * nsectors, buf, blocksize * nsectors);
2981		} else {
2982			ret = LOS_ArchCopyFromUser(data_buf, buf, blocksize * nsectors);
2983			if (ret != 0) {
2984				free(data_buf);
2985				PRINT_ERR("copy failed!->%s %d\n", __FUNCTION__, __LINE__);
2986				return (-1);
2987			}
2988		}
2989		flag = 1;
2990	}
2991
2992	(void)memset_s(&cdb, sizeof(struct scsicmd_write16_s), 0, sizeof(struct scsicmd_write16_s));
2993	usbhost_writecbw16(startsector, blocksize, nsectors, &cdb);
2994	(void)umass_scsi_transform(sc, (uint8_t *)&cdb, SCSICMD_WRITE16_SIZEOF);
2995	res = umass_command_start(sc, DIR_OUT, (void *)data_buf, blocksize * nsectors, 1000,
2996	    umass_cam_cb, sc->data_ccb);
2997
2998	if (flag == 1)
2999	{
3000		free(data_buf);
3001	}
3002
3003	status = sc->data_ccb->csio.status;
3004	if ((res != STATUS_CMD_OK) || (status != STATUS_CMD_OK)) {
3005		return (-1);
3006	}
3007
3008	return (0);
3009}
3010
3011int
3012umass_inquiry(struct umass_softc *sc)
3013{
3014	uint32_t status;
3015	int32_t ret;
3016
3017	if ((sc == NULL) || (sc->data_ccb == NULL)) {
3018		goto error;
3019	}
3020
3021	(void)umass_scsi_transform(sc, scsi_inquiry, SCSICMD_INQUIRY_SIZEOF);
3022	ret = umass_command_start(sc, DIR_IN, sc->data_ccb->csio.data_ptr, SCSIRESP_INQUIRY_SIZEOF,
3023	    1000, umass_cam_cb, sc->data_ccb);
3024	if (ret != STATUS_CMD_OK) {
3025		goto error;
3026	}
3027
3028	status = sc->data_ccb->csio.status;
3029	if (status != STATUS_CMD_OK) {
3030		PRINT_WARN("Failed to get the inquiry_status [status=%d].\n", status);
3031		goto error;
3032	}
3033
3034	ret = umass_scsi_inquiry_data(sc, sc->data_ccb->csio.data_ptr, SCSIRESP_INQUIRY_SIZEOF);
3035	if (ret == -1){
3036		PRINT_WARN("Failed to get the scsi_inquiry data .\n");
3037		goto error;
3038	}else if (ret == 1) {
3039		/* find Direct-access LUN */
3040		return (0);
3041	}
3042
3043error:
3044	return (-1);
3045}
3046
3047int
3048umass_request_sense(struct umass_softc *sc)
3049{
3050	uint32_t status;
3051	int32_t ret;
3052	if ((sc == NULL) || (sc->data_ccb == NULL)) {
3053		return (-1);
3054	}
3055
3056	(void)umass_scsi_transform(sc, scsi_request_sense, SCSICMD_REQUESTSENSE_SIZEOF);
3057	ret = umass_command_start(sc, DIR_IN, sc->data_ccb->csio.data_ptr, SCSIRESP_FIXEDSENSEDATA_SIZEOF,
3058	    1000, umass_cam_cb, sc->data_ccb);
3059	if (ret != STATUS_CMD_OK) {
3060		return (-1);
3061	}
3062
3063	status = sc->data_ccb->csio.status;
3064	if (status != STATUS_CMD_OK) {
3065		return (-1);
3066	}
3067
3068	return (0);
3069}
3070
3071void *
3072umass_bind(void)
3073{
3074	return ((void*)p_umsf);
3075}
3076
3077void
3078umass_status(void)
3079{
3080	struct umass_softc *sc = p_umsf;
3081	UINT8 cmd;
3082	UINT8 lun;
3083	UINT8 max;
3084	UINT8 speed;
3085	UINT8 phase;
3086	UINT8 state;
3087	UINT16 vid;
3088	UINT16 pid;
3089	UINT32 tag, residuce;
3090
3091	if (sc == NULL) {
3092		return;
3093	}
3094
3095	cmd = sc->sc_transfer.cmd_data[0];
3096	lun = sc->sc_transfer.lun;
3097	max = sc->sc_maxlun + 1;
3098	speed = sc->sc_udev->speed;
3099	phase = sc->sc_last_xfer_index;
3100	state = USB_GET_STATE(sc->sc_xfer[phase]);
3101	vid = UGETW(sc->sc_udev->ddesc.idVendor);
3102	pid = UGETW(sc->sc_udev->ddesc.idProduct);
3103	tag = UGETDW(sc->cbw.dCBWTag);
3104	residuce = UGETDW(sc->csw.dCSWDataResidue);
3105
3106	dprintf("VID:%04X/PID:%04X/SPD:%02d",vid,pid,speed);
3107	if (sc->sc_transfer.ccb) {
3108		dprintf("/ST:%02d ",state);
3109		if (state == USB_ST_SETUP) {
3110			dprintf("[SP]");
3111		} else if (state == USB_ST_TRANSFERRED) {
3112			dprintf("[TD]");
3113		}
3114		dprintf("/cPHASE:%02d ",phase);
3115	} else {
3116		dprintf("/nPHASE:%02d ",phase);
3117	}
3118	if (phase == UMASS_T_BBB_COMMAND) {
3119		dprintf("[CBW]");
3120	} else if (phase == UMASS_T_BBB_DATA_READ) {
3121		dprintf("[DATA]");
3122	} else if (phase == UMASS_T_BBB_DATA_WRITE) {
3123		dprintf("[DATA]");
3124	} else if (phase == UMASS_T_BBB_STATUS) {
3125		dprintf("[CSW]");
3126	} else if (phase == UMASS_T_BBB_DATA_RD_CS) {
3127		dprintf("[STAL]");
3128	} else if (phase == UMASS_T_BBB_DATA_WR_CS) {
3129		dprintf("[STAL]");
3130	}
3131	dprintf("\n");
3132
3133	dprintf("CL:%d/ML:%d/TG:%08X/RDU:%d/CMD:%X ",lun,max,tag,residuce,cmd);
3134	if (cmd == SCSI_CMD_READ10) {
3135		dprintf("[RD]\n");
3136	} else if (cmd == SCSI_CMD_WRITE10) {
3137		dprintf("[WR]\n");
3138	} else if (cmd == SCSI_CMD_INQUIRY) {
3139		dprintf("[INQ]\n");
3140	} else if (cmd == SCSI_CMD_TESTUNITREADY) {
3141		dprintf("[TUR]\n");
3142	} else if (cmd == SCSI_CMD_REQUESTSENSE) {
3143		dprintf("[RS]\n");
3144	} else if (cmd == SCSI_CMD_READCAPACITY10) {
3145		dprintf("[RC]\n");
3146	} else {
3147		dprintf("\n");
3148	}
3149}
3150
3151static int
3152umass_open(struct Vnode *filep)
3153{
3154	(void)filep;
3155	return (0);
3156}
3157
3158static int
3159umass_close(struct Vnode *filep)
3160{
3161	(void)filep;
3162	return (0);
3163}
3164
3165static ssize_t
3166umass_read(struct Vnode *umass_inode, unsigned char *buffer,
3167		    uint64_t start_sector, unsigned int nsectors)
3168{
3169	int status;
3170	struct umass_softc *sc = (struct umass_softc *)((struct drv_data*)umass_inode->data)->priv;
3171
3172	mtx_lock(&sc->sc_umass_mtx);
3173	if (sc->sc_super_disk == TRUE) {
3174		status = umass_read16(sc, start_sector, (uint16_t)sc->info.sectorsize, nsectors, buffer);
3175	} else {
3176		status = umass_read10(sc, (size_t)start_sector, (uint16_t)sc->info.sectorsize, nsectors, buffer);
3177	}
3178	mtx_unlock(&sc->sc_umass_mtx);
3179
3180	if(status)
3181		return (-1);
3182	else
3183		return ((ssize_t)nsectors);
3184}
3185
3186static ssize_t
3187umass_write(struct Vnode *umass_inode, const unsigned char *buffer,
3188		    uint64_t start_sector, unsigned int nsectors)
3189{
3190	int status;
3191	struct umass_softc *sc = (struct umass_softc *)((struct drv_data*)umass_inode->data)->priv;
3192
3193	mtx_lock(&sc->sc_umass_mtx);
3194	if (sc->sc_super_disk == TRUE) {
3195		status = umass_write16(sc, start_sector, (uint16_t)sc->info.sectorsize, nsectors, buffer);
3196	} else {
3197		status = umass_write10(sc, (size_t)start_sector, (uint16_t)sc->info.sectorsize, nsectors, buffer);
3198	}
3199	mtx_unlock(&sc->sc_umass_mtx);
3200
3201	if(status)
3202		return (-1);
3203	else
3204		return ((ssize_t)nsectors);
3205}
3206
3207static int
3208umass_geometry(struct Vnode *umass_inode, struct geometry *ugeometry)
3209{
3210	struct umass_softc *sc;
3211
3212	if ((ugeometry == NULL) || (umass_inode == NULL))
3213		return (-1);
3214
3215	sc = (struct umass_softc *)(struct umass_softc *)((struct drv_data*)umass_inode->data)->priv;
3216
3217	if (sc == NULL)
3218		return (-1);
3219
3220	mtx_lock(&sc->sc_umass_mtx);
3221	ugeometry->geo_available	= true;
3222	ugeometry->geo_mediachanged = false;
3223	ugeometry->geo_writeenabled = true;
3224	ugeometry->geo_nsectors	 = sc->info.sectornum;
3225	ugeometry->geo_sectorsize   = sc->info.sectorsize;
3226	mtx_unlock(&sc->sc_umass_mtx);
3227
3228	return (0);
3229}
3230
3231static int
3232umass_ioctl(struct Vnode *umass_inode, int cmd, unsigned long arg)
3233{
3234	(void)umass_inode;
3235	(void)cmd;
3236	(void)arg;
3237	return (0);
3238}
3239
3240const struct block_operations g_dev_umass_ops = {
3241	.open  = umass_open,
3242	.close = umass_close,
3243	.read  = umass_read,
3244	.write = umass_write,
3245	.geometry = umass_geometry,
3246	.ioctl = umass_ioctl,
3247	.unlink = NULL
3248};
3249
3250static int
3251umass_dev_is_ready(struct umass_softc *sc)
3252{
3253	int lun;
3254	int ret;
3255	uint8_t valid_lun;
3256
3257	mtx_lock(&sc->sc_umass_mtx);
3258	for (lun = 0; lun <= sc->sc_maxlun; lun++) {
3259		sc->sc_transfer.lun = lun;
3260		if (umass_inquiry(sc) < 0)
3261			continue;
3262
3263		valid_lun = lun;
3264		ret = umass_test_unit_ready(sc);
3265		if(ret == 0) {
3266			sc->sc_transfer.lun = valid_lun;
3267			ret = umass_read_capacity(sc);
3268			if (ret < 0) {
3269				mtx_unlock(&sc->sc_umass_mtx);
3270				PRINT_ERR("umass read capacity fail!\n");
3271				return (0);
3272			}
3273			mtx_unlock(&sc->sc_umass_mtx);
3274			return (1);
3275		}
3276
3277		ret = umass_request_sense(sc);
3278		if(ret < 0) {
3279			PRINT_ERR("Request sense fail!\n");
3280			mtx_unlock(&sc->sc_umass_mtx);
3281			return (0);
3282		}
3283	}
3284	mtx_unlock(&sc->sc_umass_mtx);
3285	return (0);
3286}
3287
3288static int
3289umass_attach_dev_sub(struct umass_softc *sc, unsigned int dev_unit)
3290{
3291	int ret;
3292	int disk_id;
3293	char devname[MASS_NAME]= {0};
3294#if USB_HAVE_DEVICE_TOPOLOGY
3295	device_t dev;
3296	struct usb_device *udev;
3297	usbd_bt_node *cur_node;
3298	struct node_info parent_info;
3299	struct node_info cur_info;
3300#endif
3301
3302	umass_dev_lock(dev_unit);
3303
3304#if USB_HAVE_DEVICE_TOPOLOGY
3305	dev = sc->sc_dev;
3306	udev = sc->sc_udev;
3307	dev_quantity |= 1ull << (unsigned int)device_get_unit(dev);
3308#endif
3309
3310#if USB_SUPPORT_SD_HOT_PLUG
3311	if (!umass_dev_is_attached(dev_unit))
3312#endif
3313	{
3314		devunit_to_devname(dev_unit, devname);
3315		disk_id = los_alloc_diskid_byname(devname);
3316		OsSetUsbStatus(disk_id);
3317		ret = los_disk_init(devname, &g_dev_umass_ops, (void *)sc, disk_id, NULL);
3318		if (ret) {
3319			PRINT_ERR("umass_attach_dev : los_disk_init fail!\n");
3320			goto error;
3321		}
3322	}
3323#if USB_SUPPORT_SD_HOT_PLUG
3324	umass_dev_attach_flag_set(dev_unit);
3325#endif
3326
3327#if USB_HAVE_DEVICE_TOPOLOGY
3328	cur_info.nameunit = device_get_nameunit(dev);
3329	cur_info.port_no = udev->port_no;
3330	cur_node = usbd_create_bt_node(&cur_info);
3331	if (cur_node == NULL) {
3332		goto error;
3333	}
3334
3335	parent_info.nameunit = device_get_nameunit(device_get_parent(dev));
3336	parent_info.port_no = udev->port_no;
3337
3338	(void)usbd_insert_bt_node(cur_node, hub_tree, &parent_info);
3339#endif
3340
3341	umass_dev_unlock(dev_unit);
3342	return (0);
3343
3344error:
3345	umass_dev_unlock(dev_unit);
3346	return (-1);
3347}
3348
3349static void
3350umass_detach_dev_sub(struct umass_softc *sc, int dev_unit, int flag)
3351{
3352	int disk_id;
3353	char devname[MASS_NAME]= {0};
3354#if USB_HAVE_DEVICE_TOPOLOGY
3355	struct node_info cur_info;
3356	struct node_info parent_info;
3357	device_t dev = NULL;
3358	struct usb_device *udev = NULL;
3359#endif
3360
3361	umass_dev_lock(dev_unit);
3362
3363#if USB_HAVE_DEVICE_TOPOLOGY
3364	dev = sc->sc_dev;
3365	udev = sc->sc_udev;
3366#if USB_SUPPORT_SD_HOT_PLUG
3367	if (umass_dev_is_attached(dev_unit))
3368#endif
3369	{
3370		parent_info.nameunit = device_get_nameunit(device_get_parent(dev));
3371		parent_info.port_no = udev->port_no;
3372
3373		cur_info.nameunit = device_get_nameunit(dev);
3374		cur_info.port_no = udev->port_no;
3375		(void)usbd_remove_bt_node(hub_tree, &parent_info, &cur_info);
3376	}
3377#endif
3378
3379#if USB_SUPPORT_SD_HOT_PLUG
3380	if (umass_dev_is_attached(dev_unit))
3381#endif
3382	{
3383		devunit_to_devname(dev_unit, devname);
3384		disk_id = los_get_diskid_byname(devname);
3385		(void)los_disk_deinit(disk_id);
3386		(void)OsClearUsbStatus(disk_id);
3387	}
3388
3389	if (flag == 0) { /* 0: This interface is called from umass_detach, or is called elsewhere. */
3390#if USB_SUPPORT_SD_HOT_PLUG
3391		umass_dev_delete(sc, dev_unit);
3392#endif
3393	}
3394
3395#if USB_HAVE_DEVICE_TOPOLOGY
3396	dev_quantity &= ~(1ull << (unsigned int)device_get_unit(dev));
3397#endif
3398
3399	umass_dev_unlock(dev_unit);
3400}
3401
3402#if USB_SUPPORT_SD_HOT_PLUG
3403void
3404umass_dev_status_check(UINTPTR arg)
3405{
3406	(void)arg;
3407	int ret;
3408	int i;
3409	struct umass_dev_info *dev = g_umass_dev_array;
3410	struct umass_softc *sc;
3411
3412	while(1) {
3413		for (i = 0; i < MAX_DEVICE; i++) {
3414			umass_dev_lock(i);
3415			if (dev[i].used == 1) {
3416				sc = dev[i].sc;
3417				ret = umass_dev_is_ready(sc);
3418				if (ret == 0) {
3419					if (dev[i].attached == 1) {
3420						umass_detach_dev_sub(sc, dev[i].dev_unit, 1);
3421						dev[i].attached = 0;
3422					}
3423					umass_dev_unlock(i);
3424					continue;
3425				}
3426
3427				if (dev[i].attached == 1) {
3428					umass_dev_unlock(i);
3429					continue;
3430				}
3431
3432				ret = umass_attach_dev_sub(sc, dev[i].dev_unit);
3433				if (ret< 0) {
3434					umass_dev_unlock(i);
3435					PRINT_ERR("umass attach device sub failed!\n");
3436					continue;
3437				}
3438			}
3439			umass_dev_unlock(i);
3440		}
3441		(void)LOS_Msleep(1000);
3442	}
3443}
3444
3445int
3446umass_dev_is_attached(unsigned int dev_unit)
3447{
3448	if (dev_unit >= MAX_DEVICE) {
3449		PRINT_ERR("%s %d, The device unit is wrong!\n", __FUNCTION__, __LINE__);
3450		return (-1);
3451	}
3452
3453	return (g_umass_dev_array[dev_unit].attached);
3454}
3455
3456static void
3457umass_dev_add(struct umass_softc *sc, int dev_unit)
3458{
3459	int id = dev_unit;
3460
3461	if (g_umass_dev_array[id].used == 1) {
3462		PRINT_ERR("The id of umass device array is used!, id=%d\n", dev_unit);
3463		return;
3464	}
3465
3466	g_umass_dev_array[id].sc = sc;
3467	g_umass_dev_array[id].dev_unit = dev_unit;
3468	g_umass_dev_array[id].used = 1;
3469	umass_dev_mtx_init(id, MTX_DEF | MTX_RECURSE);
3470}
3471
3472static void
3473umass_dev_delete(struct umass_softc *sc, unsigned int dev_unit)
3474{
3475	unsigned int id = dev_unit;
3476
3477	if (g_umass_dev_array[id].used == 0) {
3478		PRINT_ERR("The id of umass device array is not used!\n");
3479		return;
3480	}
3481
3482	if (g_umass_dev_array[id].dev_unit == dev_unit &&
3483		g_umass_dev_array[id].sc == sc) {
3484		g_umass_dev_array[id].used = 0;
3485		g_umass_dev_array[id].sc = NULL;
3486		g_umass_dev_array[id].attached = 0;
3487		umass_dev_mtx_destroy(id);
3488	} else {
3489		PRINT_ERR("Can not find the umass device!\n");
3490	}
3491}
3492
3493static void
3494umass_dev_attach_flag_set(int dev_unit)
3495{
3496	g_umass_dev_array[dev_unit].attached = 1;
3497}
3498
3499static void
3500umass_task_check(int flag)
3501{
3502	int i;
3503	int ret;
3504
3505	for (i = 0; i < MAX_DEVICE; i++) {
3506		if (g_umass_dev_array[i].used)
3507			break;
3508	}
3509
3510	if (i == MAX_DEVICE) {
3511		if (flag == 0) { /* create task */
3512			ret = usb_os_task_creat(&umass_taskid, (TSK_ENTRY_FUNC)umass_dev_status_check,
3513			    LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO, "umass_task", 0);
3514			if (ret) {
3515				PRINT_ERR("Create umass task fail!\n");
3516				return;
3517			}
3518		} else if (flag == 1) { /* delete task */
3519			ret = usb_os_task_delete(umass_taskid);
3520			if (ret) {
3521				PRINT_ERR("Delete umass task fail!\n");
3522				return;
3523			}
3524		} else {
3525			PRINT_ERR("%s flag error!\n", __FUNCTION__);
3526		}
3527	}
3528}
3529#endif
3530
3531static void
3532devunit_to_devname(unsigned int dev_unit, char *devname)
3533{
3534	char name_suf;
3535	int ret;
3536
3537#if USB_HAVE_DEVICE_TOPOLOGY
3538	if (!(0x1 & (dev_quantity >> dev_unit)))
3539#else
3540	if (dev_unit >= MAX_DEVICE)
3541#endif
3542	{
3543		dprintf("sorry, we don't support so many devices\n");
3544		return;
3545	}
3546
3547	name_suf = 'a' + dev_unit;
3548	ret = snprintf_s(devname, MASS_NAME, MASS_NAME - 1, "%s%c", UMASS_ATTACH_PRENAME, name_suf);
3549	if (ret < 0) {
3550		usb_err("snprintf_s failed!, ret:%d\n", ret);
3551		return;
3552	}
3553}
3554static int32_t
3555umass_attach_dev(struct umass_softc *sc, unsigned int dev_unit)
3556{
3557	int ret;
3558
3559	if (dev_unit >= MAX_DEVICE) {
3560		PRINT_ERR("sorry, we don't support so many devices\n");
3561		return (-1);
3562	}
3563#if USB_SUPPORT_SD_HOT_PLUG
3564	umass_task_check(0);
3565	umass_dev_add(sc, dev_unit);
3566#endif
3567
3568	ret = umass_dev_is_ready(sc);
3569	if (ret) {
3570		ret = umass_attach_dev_sub(sc, dev_unit);
3571		if (ret < 0) {
3572#if USB_SUPPORT_SD_HOT_PLUG
3573			umass_dev_delete(sc, dev_unit);
3574#endif
3575			PRINT_ERR("umass attach device fail!\n");
3576			return (-1);
3577		}
3578	}
3579
3580	return (0);
3581}
3582
3583#if USB_HAVE_DEVICE_TOPOLOGY
3584int
3585umass_medium_probe(uint8_t medium, char *devname)
3586{
3587	struct usbd_bt_node *node;
3588	uint8_t dev_unit;
3589
3590	if ((devname == NULL) || strlen(devname) > 7) { /* /dev/sd* */
3591		return (-1);
3592	}
3593
3594	if ((medium < 1) || (medium > usbd_get_hub_quantity())) {
3595		return (-1);
3596	}
3597
3598	node = usbd_per_order_probe(hub_tree, "umass", &medium);
3599	if (node != NULL) {
3600		dev_unit = usbd_atoi(node->info.nameunit + 5); /* 5 = umass */
3601		devunit_to_devname(dev_unit, devname);
3602	} else {
3603		return (-1);
3604	}
3605	return (0);
3606}
3607#endif
3608
3609