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