umass.c revision 199675
1184610Salfred#include <sys/cdefs.h>
2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/storage/umass.c 199675 2009-11-22 21:21:22Z thompsa $");
3184610Salfred
4184610Salfred/*-
5184610Salfred * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>,
6189002Sed *		      Nick Hibma <n_hibma@FreeBSD.org>
7184610Salfred * All rights reserved.
8184610Salfred *
9184610Salfred * Redistribution and use in source and binary forms, with or without
10184610Salfred * modification, are permitted provided that the following conditions
11184610Salfred * are met:
12184610Salfred * 1. Redistributions of source code must retain the above copyright
13184610Salfred *    notice, this list of conditions and the following disclaimer.
14184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
15184610Salfred *    notice, this list of conditions and the following disclaimer in the
16184610Salfred *    documentation and/or other materials provided with the distribution.
17184610Salfred *
18184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28184610Salfred * SUCH DAMAGE.
29184610Salfred *
30184610Salfred *	$FreeBSD: head/sys/dev/usb/storage/umass.c 199675 2009-11-22 21:21:22Z thompsa $
31184610Salfred *	$NetBSD: umass.c,v 1.28 2000/04/02 23:46:53 augustss Exp $
32184610Salfred */
33184610Salfred
34184610Salfred/* Also already merged from NetBSD:
35184610Salfred *	$NetBSD: umass.c,v 1.67 2001/11/25 19:05:22 augustss Exp $
36184610Salfred *	$NetBSD: umass.c,v 1.90 2002/11/04 19:17:33 pooka Exp $
37184610Salfred *	$NetBSD: umass.c,v 1.108 2003/11/07 17:03:25 wiz Exp $
38184610Salfred *	$NetBSD: umass.c,v 1.109 2003/12/04 13:57:31 keihan Exp $
39184610Salfred */
40184610Salfred
41184610Salfred/*
42184610Salfred * Universal Serial Bus Mass Storage Class specs:
43184610Salfred * http://www.usb.org/developers/devclass_docs/usb_msc_overview_1.2.pdf
44184610Salfred * http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
45184610Salfred * http://www.usb.org/developers/devclass_docs/usb_msc_cbi_1.1.pdf
46184610Salfred * http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf
47184610Salfred */
48184610Salfred
49184610Salfred/*
50184610Salfred * Ported to NetBSD by Lennart Augustsson <augustss@NetBSD.org>.
51184610Salfred * Parts of the code written by Jason R. Thorpe <thorpej@shagadelic.org>.
52184610Salfred */
53184610Salfred
54184610Salfred/*
55184610Salfred * The driver handles 3 Wire Protocols
56184610Salfred * - Command/Bulk/Interrupt (CBI)
57184610Salfred * - Command/Bulk/Interrupt with Command Completion Interrupt (CBI with CCI)
58184610Salfred * - Mass Storage Bulk-Only (BBB)
59184610Salfred *   (BBB refers Bulk/Bulk/Bulk for Command/Data/Status phases)
60184610Salfred *
61184610Salfred * Over these wire protocols it handles the following command protocols
62184610Salfred * - SCSI
63184610Salfred * - UFI (floppy command set)
64184610Salfred * - 8070i (ATAPI)
65184610Salfred *
66184610Salfred * UFI and 8070i (ATAPI) are transformed versions of the SCSI command set. The
67184610Salfred * sc->sc_transform method is used to convert the commands into the appropriate
68184610Salfred * format (if at all necessary). For example, UFI requires all commands to be
69184610Salfred * 12 bytes in length amongst other things.
70184610Salfred *
71184610Salfred * The source code below is marked and can be split into a number of pieces
72184610Salfred * (in this order):
73184610Salfred *
74184610Salfred * - probe/attach/detach
75184610Salfred * - generic transfer routines
76184610Salfred * - BBB
77184610Salfred * - CBI
78184610Salfred * - CBI_I (in addition to functions from CBI)
79184610Salfred * - CAM (Common Access Method)
80184610Salfred * - SCSI
81184610Salfred * - UFI
82184610Salfred * - 8070i (ATAPI)
83184610Salfred *
84184610Salfred * The protocols are implemented using a state machine, for the transfers as
85184610Salfred * well as for the resets. The state machine is contained in umass_t_*_callback.
86184610Salfred * The state machine is started through either umass_command_start() or
87184610Salfred * umass_reset().
88184610Salfred *
89184610Salfred * The reason for doing this is a) CAM performs a lot better this way and b) it
90184610Salfred * avoids using tsleep from interrupt context (for example after a failed
91184610Salfred * transfer).
92184610Salfred */
93184610Salfred
94184610Salfred/*
95184610Salfred * The SCSI related part of this driver has been derived from the
96189002Sed * dev/ppbus/vpo.c driver, by Nicolas Souchu (nsouch@FreeBSD.org).
97184610Salfred *
98184610Salfred * The CAM layer uses so called actions which are messages sent to the host
99184610Salfred * adapter for completion. The actions come in through umass_cam_action. The
100184610Salfred * appropriate block of routines is called depending on the transport protocol
101184610Salfred * in use. When the transfer has finished, these routines call
102184610Salfred * umass_cam_cb again to complete the CAM command.
103184610Salfred */
104184610Salfred
105194677Sthompsa#include <sys/stdint.h>
106194677Sthompsa#include <sys/stddef.h>
107194677Sthompsa#include <sys/param.h>
108194677Sthompsa#include <sys/queue.h>
109194677Sthompsa#include <sys/types.h>
110194677Sthompsa#include <sys/systm.h>
111194677Sthompsa#include <sys/kernel.h>
112194677Sthompsa#include <sys/bus.h>
113194677Sthompsa#include <sys/linker_set.h>
114194677Sthompsa#include <sys/module.h>
115194677Sthompsa#include <sys/lock.h>
116194677Sthompsa#include <sys/mutex.h>
117194677Sthompsa#include <sys/condvar.h>
118194677Sthompsa#include <sys/sysctl.h>
119194677Sthompsa#include <sys/sx.h>
120194677Sthompsa#include <sys/unistd.h>
121194677Sthompsa#include <sys/callout.h>
122194677Sthompsa#include <sys/malloc.h>
123194677Sthompsa#include <sys/priv.h>
124194677Sthompsa
125194677Sthompsa#include <dev/usb/usb.h>
126194677Sthompsa#include <dev/usb/usbdi.h>
127196826Strasz#include <dev/usb/usb_device.h>
128188746Sthompsa#include "usbdevs.h"
129184610Salfred
130184610Salfred#include <cam/cam.h>
131184610Salfred#include <cam/cam_ccb.h>
132184610Salfred#include <cam/cam_sim.h>
133184610Salfred#include <cam/cam_xpt_sim.h>
134184610Salfred#include <cam/scsi/scsi_all.h>
135184610Salfred#include <cam/scsi/scsi_da.h>
136184610Salfred
137184610Salfred#include <cam/cam_periph.h>
138184610Salfred
139194677Sthompsa#define UMASS_EXT_BUFFER
140194677Sthompsa#ifdef UMASS_EXT_BUFFER
141184610Salfred/* this enables loading of virtual buffers into DMA */
142184610Salfred#define	UMASS_USB_FLAGS .ext_buffer=1,
143184610Salfred#else
144184610Salfred#define	UMASS_USB_FLAGS
145184610Salfred#endif
146184610Salfred
147184610Salfred#if USB_DEBUG
148184610Salfred#define	DIF(m, x)				\
149184610Salfred  do {						\
150184610Salfred    if (umass_debug & (m)) { x ; }		\
151184610Salfred  } while (0)
152184610Salfred
153184610Salfred#define	DPRINTF(sc, m, fmt, ...)			\
154184610Salfred  do {							\
155184610Salfred    if (umass_debug & (m)) {				\
156184610Salfred        printf("%s:%s: " fmt,				\
157184610Salfred	       (sc) ? (const char *)(sc)->sc_name :	\
158184610Salfred	       (const char *)"umassX",			\
159184610Salfred		__FUNCTION__ ,## __VA_ARGS__);		\
160184610Salfred    }							\
161184610Salfred  } while (0)
162184610Salfred
163184610Salfred#define	UDMASS_GEN	0x00010000	/* general */
164184610Salfred#define	UDMASS_SCSI	0x00020000	/* scsi */
165184610Salfred#define	UDMASS_UFI	0x00040000	/* ufi command set */
166184610Salfred#define	UDMASS_ATAPI	0x00080000	/* 8070i command set */
167184610Salfred#define	UDMASS_CMD	(UDMASS_SCSI|UDMASS_UFI|UDMASS_ATAPI)
168184610Salfred#define	UDMASS_USB	0x00100000	/* USB general */
169184610Salfred#define	UDMASS_BBB	0x00200000	/* Bulk-Only transfers */
170184610Salfred#define	UDMASS_CBI	0x00400000	/* CBI transfers */
171184610Salfred#define	UDMASS_WIRE	(UDMASS_BBB|UDMASS_CBI)
172184610Salfred#define	UDMASS_ALL	0xffff0000	/* all of the above */
173184610Salfredstatic int umass_debug = 0;
174184610Salfred
175192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass");
176192502SthompsaSYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW,
177184610Salfred    &umass_debug, 0, "umass debug level");
178199675Sthompsa
179199675SthompsaTUNABLE_INT("hw.usb.umass.debug", &umass_debug);
180184610Salfred#else
181184610Salfred#define	DIF(...) do { } while (0)
182184610Salfred#define	DPRINTF(...) do { } while (0)
183184610Salfred#endif
184184610Salfred
185184610Salfred#define	UMASS_GONE ((struct umass_softc *)1)
186184610Salfred
187184610Salfred#define	UMASS_BULK_SIZE (1 << 17)
188184610Salfred#define	UMASS_CBI_DIAGNOSTIC_CMDLEN 12	/* bytes */
189184610Salfred#define	UMASS_MAX_CMDLEN MAX(12, CAM_MAX_CDBLEN)	/* bytes */
190184610Salfred
191184610Salfred/* USB transfer definitions */
192184610Salfred
193184610Salfred#define	UMASS_T_BBB_RESET1      0	/* Bulk-Only */
194184610Salfred#define	UMASS_T_BBB_RESET2      1
195184610Salfred#define	UMASS_T_BBB_RESET3      2
196184610Salfred#define	UMASS_T_BBB_COMMAND     3
197184610Salfred#define	UMASS_T_BBB_DATA_READ   4
198184610Salfred#define	UMASS_T_BBB_DATA_RD_CS  5
199184610Salfred#define	UMASS_T_BBB_DATA_WRITE  6
200184610Salfred#define	UMASS_T_BBB_DATA_WR_CS  7
201184610Salfred#define	UMASS_T_BBB_STATUS      8
202184610Salfred#define	UMASS_T_BBB_MAX         9
203184610Salfred
204184610Salfred#define	UMASS_T_CBI_RESET1      0	/* CBI */
205184610Salfred#define	UMASS_T_CBI_RESET2      1
206184610Salfred#define	UMASS_T_CBI_RESET3      2
207184610Salfred#define	UMASS_T_CBI_COMMAND     3
208184610Salfred#define	UMASS_T_CBI_DATA_READ   4
209184610Salfred#define	UMASS_T_CBI_DATA_RD_CS  5
210184610Salfred#define	UMASS_T_CBI_DATA_WRITE  6
211184610Salfred#define	UMASS_T_CBI_DATA_WR_CS  7
212184610Salfred#define	UMASS_T_CBI_STATUS      8
213184610Salfred#define	UMASS_T_CBI_RESET4      9
214184610Salfred#define	UMASS_T_CBI_MAX        10
215184610Salfred
216184610Salfred#define	UMASS_T_MAX MAX(UMASS_T_CBI_MAX, UMASS_T_BBB_MAX)
217184610Salfred
218184610Salfred/* Generic definitions */
219184610Salfred
220184610Salfred/* Direction for transfer */
221184610Salfred#define	DIR_NONE	0
222184610Salfred#define	DIR_IN		1
223184610Salfred#define	DIR_OUT		2
224184610Salfred
225184610Salfred/* device name */
226184610Salfred#define	DEVNAME		"umass"
227184610Salfred#define	DEVNAME_SIM	"umass-sim"
228184610Salfred
229184610Salfred/* Approximate maximum transfer speeds (assumes 33% overhead). */
230184610Salfred#define	UMASS_FULL_TRANSFER_SPEED	1000
231184610Salfred#define	UMASS_HIGH_TRANSFER_SPEED	40000
232184610Salfred#define	UMASS_FLOPPY_TRANSFER_SPEED	20
233184610Salfred
234184610Salfred#define	UMASS_TIMEOUT			5000	/* ms */
235184610Salfred
236184610Salfred/* CAM specific definitions */
237184610Salfred
238184610Salfred#define	UMASS_SCSIID_MAX	1	/* maximum number of drives expected */
239184610Salfred#define	UMASS_SCSIID_HOST	UMASS_SCSIID_MAX
240184610Salfred
241184610Salfred/* Bulk-Only features */
242184610Salfred
243184610Salfred#define	UR_BBB_RESET		0xff	/* Bulk-Only reset */
244184610Salfred#define	UR_BBB_GET_MAX_LUN	0xfe	/* Get maximum lun */
245184610Salfred
246184610Salfred/* Command Block Wrapper */
247184610Salfredtypedef struct {
248184610Salfred	uDWord	dCBWSignature;
249184610Salfred#define	CBWSIGNATURE	0x43425355
250184610Salfred	uDWord	dCBWTag;
251184610Salfred	uDWord	dCBWDataTransferLength;
252184610Salfred	uByte	bCBWFlags;
253184610Salfred#define	CBWFLAGS_OUT	0x00
254184610Salfred#define	CBWFLAGS_IN	0x80
255184610Salfred	uByte	bCBWLUN;
256184610Salfred	uByte	bCDBLength;
257184610Salfred#define	CBWCDBLENGTH	16
258184610Salfred	uByte	CBWCDB[CBWCDBLENGTH];
259184610Salfred} __packed umass_bbb_cbw_t;
260184610Salfred
261184610Salfred#define	UMASS_BBB_CBW_SIZE	31
262184610Salfred
263184610Salfred/* Command Status Wrapper */
264184610Salfredtypedef struct {
265184610Salfred	uDWord	dCSWSignature;
266184610Salfred#define	CSWSIGNATURE	0x53425355
267184610Salfred#define	CSWSIGNATURE_IMAGINATION_DBX1	0x43425355
268184610Salfred#define	CSWSIGNATURE_OLYMPUS_C1	0x55425355
269184610Salfred	uDWord	dCSWTag;
270184610Salfred	uDWord	dCSWDataResidue;
271184610Salfred	uByte	bCSWStatus;
272184610Salfred#define	CSWSTATUS_GOOD	0x0
273184610Salfred#define	CSWSTATUS_FAILED	0x1
274184610Salfred#define	CSWSTATUS_PHASE	0x2
275184610Salfred} __packed umass_bbb_csw_t;
276184610Salfred
277184610Salfred#define	UMASS_BBB_CSW_SIZE	13
278184610Salfred
279184610Salfred/* CBI features */
280184610Salfred
281184610Salfred#define	UR_CBI_ADSC	0x00
282184610Salfred
283184610Salfredtypedef union {
284184610Salfred	struct {
285184610Salfred		uint8_t	type;
286184610Salfred#define	IDB_TYPE_CCI		0x00
287184610Salfred		uint8_t	value;
288184610Salfred#define	IDB_VALUE_PASS		0x00
289184610Salfred#define	IDB_VALUE_FAIL		0x01
290184610Salfred#define	IDB_VALUE_PHASE		0x02
291184610Salfred#define	IDB_VALUE_PERSISTENT	0x03
292184610Salfred#define	IDB_VALUE_STATUS_MASK	0x03
293184610Salfred	} __packed common;
294184610Salfred
295184610Salfred	struct {
296184610Salfred		uint8_t	asc;
297184610Salfred		uint8_t	ascq;
298184610Salfred	} __packed ufi;
299184610Salfred} __packed umass_cbi_sbl_t;
300184610Salfred
301184610Salfredstruct umass_softc;			/* see below */
302184610Salfred
303184610Salfredtypedef void (umass_callback_t)(struct umass_softc *sc, union ccb *ccb,
304184610Salfred    	uint32_t residue, uint8_t status);
305184610Salfred
306184610Salfred#define	STATUS_CMD_OK		0	/* everything ok */
307184610Salfred#define	STATUS_CMD_UNKNOWN	1	/* will have to fetch sense */
308184610Salfred#define	STATUS_CMD_FAILED	2	/* transfer was ok, command failed */
309184610Salfred#define	STATUS_WIRE_FAILED	3	/* couldn't even get command across */
310184610Salfred
311184610Salfredtypedef uint8_t (umass_transform_t)(struct umass_softc *sc, uint8_t *cmd_ptr,
312184610Salfred    	uint8_t cmd_len);
313184610Salfred
314184610Salfredstruct umass_devdescr {
315184610Salfred	uint32_t vid;
316184610Salfred#define	VID_WILDCARD	0xffffffff
317184610Salfred#define	VID_EOT		0xfffffffe
318184610Salfred	uint32_t pid;
319184610Salfred#define	PID_WILDCARD	0xffffffff
320184610Salfred#define	PID_EOT		0xfffffffe
321184610Salfred	uint32_t rid;
322184610Salfred#define	RID_WILDCARD	0xffffffff
323184610Salfred#define	RID_EOT		0xfffffffe
324184610Salfred
325184610Salfred	/* wire and command protocol */
326184610Salfred	uint16_t proto;
327192052Sthompsa#define	UMASS_PROTO_DEFAULT	0x0000	/* use protocol indicated by USB descriptors */
328184610Salfred#define	UMASS_PROTO_BBB		0x0001	/* USB wire protocol */
329184610Salfred#define	UMASS_PROTO_CBI		0x0002
330184610Salfred#define	UMASS_PROTO_CBI_I	0x0004
331184610Salfred#define	UMASS_PROTO_WIRE		0x00ff	/* USB wire protocol mask */
332184610Salfred#define	UMASS_PROTO_SCSI		0x0100	/* command protocol */
333184610Salfred#define	UMASS_PROTO_ATAPI	0x0200
334184610Salfred#define	UMASS_PROTO_UFI		0x0400
335184610Salfred#define	UMASS_PROTO_RBC		0x0800
336184610Salfred#define	UMASS_PROTO_COMMAND	0xff00	/* command protocol mask */
337184610Salfred
338184610Salfred	/* Device specific quirks */
339184610Salfred	uint16_t quirks;
340184610Salfred#define	NO_QUIRKS		0x0000
341184610Salfred	/*
342184610Salfred	 * The drive does not support Test Unit Ready. Convert to Start Unit
343184610Salfred	 */
344184610Salfred#define	NO_TEST_UNIT_READY	0x0001
345184610Salfred	/*
346184610Salfred	 * The drive does not reset the Unit Attention state after REQUEST
347184610Salfred	 * SENSE has been sent. The INQUIRY command does not reset the UA
348184610Salfred	 * either, and so CAM runs in circles trying to retrieve the initial
349184610Salfred	 * INQUIRY data.
350184610Salfred	 */
351184610Salfred#define	RS_NO_CLEAR_UA		0x0002
352184610Salfred	/* The drive does not support START STOP.  */
353184610Salfred#define	NO_START_STOP		0x0004
354184610Salfred	/* Don't ask for full inquiry data (255b).  */
355184610Salfred#define	FORCE_SHORT_INQUIRY	0x0008
356184610Salfred	/* Needs to be initialised the Shuttle way */
357184610Salfred#define	SHUTTLE_INIT		0x0010
358184610Salfred	/* Drive needs to be switched to alternate iface 1 */
359184610Salfred#define	ALT_IFACE_1		0x0020
360184610Salfred	/* Drive does not do 1Mb/s, but just floppy speeds (20kb/s) */
361184610Salfred#define	FLOPPY_SPEED		0x0040
362184610Salfred	/* The device can't count and gets the residue of transfers wrong */
363184610Salfred#define	IGNORE_RESIDUE		0x0080
364184610Salfred	/* No GetMaxLun call */
365184610Salfred#define	NO_GETMAXLUN		0x0100
366184610Salfred	/* The device uses a weird CSWSIGNATURE. */
367184610Salfred#define	WRONG_CSWSIG		0x0200
368184610Salfred	/* Device cannot handle INQUIRY so fake a generic response */
369184610Salfred#define	NO_INQUIRY		0x0400
370184610Salfred	/* Device cannot handle INQUIRY EVPD, return CHECK CONDITION */
371184610Salfred#define	NO_INQUIRY_EVPD		0x0800
372184610Salfred	/* Pad all RBC requests to 12 bytes. */
373184610Salfred#define	RBC_PAD_TO_12		0x1000
374184610Salfred	/*
375184610Salfred	 * Device reports number of sectors from READ_CAPACITY, not max
376184610Salfred	 * sector number.
377184610Salfred	 */
378184610Salfred#define	READ_CAPACITY_OFFBY1	0x2000
379184610Salfred	/*
380184610Salfred	 * Device cannot handle a SCSI synchronize cache command.  Normally
381184610Salfred	 * this quirk would be handled in the cam layer, but for IDE bridges
382184610Salfred	 * we need to associate the quirk with the bridge and not the
383184610Salfred	 * underlying disk device.  This is handled by faking a success
384184610Salfred	 * result.
385184610Salfred	 */
386184610Salfred#define	NO_SYNCHRONIZE_CACHE	0x4000
387184610Salfred};
388184610Salfred
389184610Salfredstatic const struct umass_devdescr umass_devdescr[] = {
390184610Salfred	{USB_VENDOR_ASAHIOPTICAL, PID_WILDCARD, RID_WILDCARD,
391192052Sthompsa		UMASS_PROTO_DEFAULT,
392184610Salfred		RS_NO_CLEAR_UA
393184610Salfred	},
394184610Salfred	{USB_VENDOR_ADDON, USB_PRODUCT_ADDON_ATTACHE, RID_WILDCARD,
395184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
396184610Salfred		IGNORE_RESIDUE
397184610Salfred	},
398184610Salfred	{USB_VENDOR_ADDON, USB_PRODUCT_ADDON_A256MB, RID_WILDCARD,
399184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
400184610Salfred		IGNORE_RESIDUE
401184610Salfred	},
402184610Salfred	{USB_VENDOR_ADDON, USB_PRODUCT_ADDON_DISKPRO512, RID_WILDCARD,
403184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
404184610Salfred		IGNORE_RESIDUE
405184610Salfred	},
406184610Salfred	{USB_VENDOR_ADDONICS2, USB_PRODUCT_ADDONICS2_CABLE_205, RID_WILDCARD,
407184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
408184610Salfred		NO_QUIRKS
409184610Salfred	},
410184610Salfred	{USB_VENDOR_AIPTEK, USB_PRODUCT_AIPTEK_POCKETCAM3M, RID_WILDCARD,
411184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
412184610Salfred		NO_QUIRKS
413184610Salfred	},
414193171Sdeischen	{USB_VENDOR_AIPTEK2, USB_PRODUCT_AIPTEK2_SUNPLUS_TECH, RID_WILDCARD,
415193171Sdeischen		UMASS_PROTO_DEFAULT,
416193171Sdeischen		NO_SYNCHRONIZE_CACHE
417193171Sdeischen	},
418196495Salfred	{USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_SDCR_6335, RID_WILDCARD,
419196495Salfred		UMASS_PROTO_DEFAULT,
420196495Salfred		NO_TEST_UNIT_READY | NO_SYNCHRONIZE_CACHE
421196495Salfred	},
422192052Sthompsa	{USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_AU6390, RID_WILDCARD,
423192052Sthompsa		UMASS_PROTO_DEFAULT,
424192052Sthompsa		NO_SYNCHRONIZE_CACHE
425192052Sthompsa	},
426184610Salfred	{USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_UMCR_9361, RID_WILDCARD,
427184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
428184610Salfred		NO_GETMAXLUN
429184610Salfred	},
430186730Salfred	{USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_TRANSCEND, RID_WILDCARD,
431186730Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
432186730Salfred		NO_GETMAXLUN
433186730Salfred	},
434184610Salfred	{USB_VENDOR_ASAHIOPTICAL, USB_PRODUCT_ASAHIOPTICAL_OPTIO230, RID_WILDCARD,
435184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
436184610Salfred		NO_INQUIRY
437184610Salfred	},
438184610Salfred	{USB_VENDOR_ASAHIOPTICAL, USB_PRODUCT_ASAHIOPTICAL_OPTIO330, RID_WILDCARD,
439184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
440184610Salfred		NO_INQUIRY
441184610Salfred	},
442184610Salfred	{USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2SCSI, RID_WILDCARD,
443184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
444184610Salfred		NO_QUIRKS
445184610Salfred	},
446184610Salfred	{USB_VENDOR_CASIO, USB_PRODUCT_CASIO_QV_DIGICAM, RID_WILDCARD,
447184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_CBI,
448184610Salfred		NO_INQUIRY
449184610Salfred	},
450184610Salfred	{USB_VENDOR_CCYU, USB_PRODUCT_CCYU_ED1064, RID_WILDCARD,
451184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
452184610Salfred		NO_QUIRKS
453184610Salfred	},
454184610Salfred	{USB_VENDOR_CENTURY, USB_PRODUCT_CENTURY_EX35QUAT, RID_WILDCARD,
455184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
456184610Salfred		FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE
457184610Salfred	},
458192052Sthompsa	{USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_XX6830XX, RID_WILDCARD,
459192052Sthompsa		UMASS_PROTO_DEFAULT,
460192052Sthompsa		NO_GETMAXLUN | NO_SYNCHRONIZE_CACHE
461192052Sthompsa	},
462184610Salfred	{USB_VENDOR_DESKNOTE, USB_PRODUCT_DESKNOTE_UCR_61S2B, RID_WILDCARD,
463184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
464184610Salfred		NO_QUIRKS
465184610Salfred	},
466184610Salfred	{USB_VENDOR_DMI, USB_PRODUCT_DMI_CFSM_RW, RID_WILDCARD,
467184610Salfred		UMASS_PROTO_SCSI,
468184610Salfred		NO_GETMAXLUN
469184610Salfred	},
470184610Salfred	{USB_VENDOR_EPSON, USB_PRODUCT_EPSON_STYLUS_875DC, RID_WILDCARD,
471184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_CBI,
472184610Salfred		NO_INQUIRY
473184610Salfred	},
474184610Salfred	{USB_VENDOR_EPSON, USB_PRODUCT_EPSON_STYLUS_895, RID_WILDCARD,
475184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
476184610Salfred		NO_GETMAXLUN
477184610Salfred	},
478184610Salfred	{USB_VENDOR_FEIYA, USB_PRODUCT_FEIYA_5IN1, RID_WILDCARD,
479184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
480184610Salfred		NO_QUIRKS
481184610Salfred	},
482184610Salfred	{USB_VENDOR_FREECOM, USB_PRODUCT_FREECOM_DVD, RID_WILDCARD,
483184610Salfred		UMASS_PROTO_SCSI,
484184610Salfred		NO_QUIRKS
485184610Salfred	},
486184610Salfred	{USB_VENDOR_FUJIPHOTO, USB_PRODUCT_FUJIPHOTO_MASS0100, RID_WILDCARD,
487184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I,
488184610Salfred		RS_NO_CLEAR_UA
489184610Salfred	},
490184610Salfred	{USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB2IDE, RID_WILDCARD,
491184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
492184610Salfred		FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE
493190189Sthompsa		    | NO_SYNCHRONIZE_CACHE
494184610Salfred	},
495184610Salfred	{USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB2IDE_2, RID_WILDCARD,
496184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_BBB,
497184610Salfred		FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE
498184610Salfred	},
499184610Salfred	{USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB, RID_WILDCARD,
500184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
501184610Salfred		FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE
502184610Salfred	},
503184610Salfred	{USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL641USB_2, RID_WILDCARD,
504184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
505184610Salfred		WRONG_CSWSIG
506184610Salfred	},
507184610Salfred	{USB_VENDOR_HAGIWARA, USB_PRODUCT_HAGIWARA_FG, RID_WILDCARD,
508184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
509184610Salfred		NO_QUIRKS
510184610Salfred	},
511184610Salfred	{USB_VENDOR_HAGIWARA, USB_PRODUCT_HAGIWARA_FGSM, RID_WILDCARD,
512184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
513184610Salfred		NO_QUIRKS
514184610Salfred	},
515184610Salfred	{USB_VENDOR_HITACHI, USB_PRODUCT_HITACHI_DVDCAM_DZ_MV100A, RID_WILDCARD,
516184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_CBI,
517184610Salfred		NO_GETMAXLUN
518184610Salfred	},
519184610Salfred	{USB_VENDOR_HITACHI, USB_PRODUCT_HITACHI_DVDCAM_USB, RID_WILDCARD,
520184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I,
521184610Salfred		NO_INQUIRY
522184610Salfred	},
523184610Salfred	{USB_VENDOR_HP, USB_PRODUCT_HP_CDW4E, RID_WILDCARD,
524184610Salfred		UMASS_PROTO_ATAPI,
525184610Salfred		NO_QUIRKS
526184610Salfred	},
527184610Salfred	{USB_VENDOR_HP, USB_PRODUCT_HP_CDW8200, RID_WILDCARD,
528184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I,
529184610Salfred		NO_TEST_UNIT_READY | NO_START_STOP
530184610Salfred	},
531184610Salfred	{USB_VENDOR_IMAGINATION, USB_PRODUCT_IMAGINATION_DBX1, RID_WILDCARD,
532184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
533184610Salfred		WRONG_CSWSIG
534184610Salfred	},
535184610Salfred	{USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_USBCABLE, RID_WILDCARD,
536184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI,
537184610Salfred		NO_TEST_UNIT_READY | NO_START_STOP | ALT_IFACE_1
538184610Salfred	},
539184610Salfred	{USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_ATAPI, RID_WILDCARD,
540184610Salfred		UMASS_PROTO_RBC | UMASS_PROTO_CBI,
541184610Salfred		NO_QUIRKS
542184610Salfred	},
543184610Salfred	{USB_VENDOR_INSYSTEM, USB_PRODUCT_INSYSTEM_STORAGE_V2, RID_WILDCARD,
544184610Salfred		UMASS_PROTO_RBC | UMASS_PROTO_CBI,
545184610Salfred		NO_QUIRKS
546184610Salfred	},
547184610Salfred	{USB_VENDOR_IODATA, USB_PRODUCT_IODATA_IU_CD2, RID_WILDCARD,
548184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
549184610Salfred		NO_QUIRKS
550184610Salfred	},
551184610Salfred	{USB_VENDOR_IODATA, USB_PRODUCT_IODATA_DVR_UEH8, RID_WILDCARD,
552184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
553184610Salfred		NO_QUIRKS
554184610Salfred	},
555184610Salfred	{USB_VENDOR_IOMEGA, USB_PRODUCT_IOMEGA_ZIP100, RID_WILDCARD,
556184610Salfred		/*
557184610Salfred		 * XXX This is not correct as there are Zip drives that use
558184610Salfred		 * ATAPI.
559184610Salfred		 */
560184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
561184610Salfred		NO_TEST_UNIT_READY
562184610Salfred	},
563184610Salfred	{USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_FINECAM_L3, RID_WILDCARD,
564184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
565184610Salfred		NO_INQUIRY
566184610Salfred	},
567184610Salfred	{USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_FINECAM_S3X, RID_WILDCARD,
568184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI,
569184610Salfred		NO_INQUIRY
570184610Salfred	},
571184610Salfred	{USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_FINECAM_S4, RID_WILDCARD,
572184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI,
573184610Salfred		NO_INQUIRY
574184610Salfred	},
575184610Salfred	{USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_FINECAM_S5, RID_WILDCARD,
576184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
577184610Salfred		NO_INQUIRY
578184610Salfred	},
579184610Salfred	{USB_VENDOR_LACIE, USB_PRODUCT_LACIE_HD, RID_WILDCARD,
580184610Salfred		UMASS_PROTO_RBC | UMASS_PROTO_CBI,
581184610Salfred		NO_QUIRKS
582184610Salfred	},
583184610Salfred	{USB_VENDOR_LEXAR, USB_PRODUCT_LEXAR_CF_READER, RID_WILDCARD,
584184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
585184610Salfred		NO_INQUIRY
586184610Salfred	},
587184610Salfred	{USB_VENDOR_LEXAR, USB_PRODUCT_LEXAR_JUMPSHOT, RID_WILDCARD,
588184610Salfred		UMASS_PROTO_SCSI,
589184610Salfred		NO_QUIRKS
590184610Salfred	},
591184610Salfred	{USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LDR_H443SU2, RID_WILDCARD,
592184610Salfred		UMASS_PROTO_SCSI,
593184610Salfred		NO_QUIRKS
594184610Salfred	},
595184610Salfred	{USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LDR_H443U2, RID_WILDCARD,
596184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
597184610Salfred		NO_QUIRKS
598184610Salfred	},
599184610Salfred	{USB_VENDOR_MELCO, USB_PRODUCT_MELCO_DUBPXXG, RID_WILDCARD,
600184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
601184610Salfred		FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE
602184610Salfred	},
603184610Salfred	{USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_DPCM, RID_WILDCARD,
604184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_CBI,
605184610Salfred		NO_TEST_UNIT_READY | NO_START_STOP
606184610Salfred	},
607184610Salfred	{USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_SCSIDB25, RID_WILDCARD,
608184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
609184610Salfred		NO_QUIRKS
610184610Salfred	},
611184610Salfred	{USB_VENDOR_MICROTECH, USB_PRODUCT_MICROTECH_SCSIHD50, RID_WILDCARD,
612184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
613184610Salfred		NO_QUIRKS
614184610Salfred	},
615184610Salfred	{USB_VENDOR_MINOLTA, USB_PRODUCT_MINOLTA_E223, RID_WILDCARD,
616184610Salfred		UMASS_PROTO_SCSI,
617184610Salfred		NO_QUIRKS
618184610Salfred	},
619184610Salfred	{USB_VENDOR_MINOLTA, USB_PRODUCT_MINOLTA_F300, RID_WILDCARD,
620184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
621184610Salfred		NO_QUIRKS
622184610Salfred	},
623184610Salfred	{USB_VENDOR_MITSUMI, USB_PRODUCT_MITSUMI_CDRRW, RID_WILDCARD,
624184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI,
625184610Salfred		NO_QUIRKS
626184610Salfred	},
627184610Salfred	{USB_VENDOR_MITSUMI, USB_PRODUCT_MITSUMI_FDD, RID_WILDCARD,
628184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
629184610Salfred		NO_GETMAXLUN
630184610Salfred	},
631184610Salfred	{USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_E398, RID_WILDCARD,
632184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
633184610Salfred		FORCE_SHORT_INQUIRY | NO_INQUIRY_EVPD | NO_GETMAXLUN
634184610Salfred	},
635192052Sthompsa	{USB_VENDOR_MPMAN, PID_WILDCARD, RID_WILDCARD,
636192052Sthompsa		UMASS_PROTO_DEFAULT,
637192052Sthompsa		NO_SYNCHRONIZE_CACHE
638192052Sthompsa	},
639184610Salfred	{USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY, RID_WILDCARD,
640184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
641184610Salfred		IGNORE_RESIDUE | NO_GETMAXLUN | RS_NO_CLEAR_UA
642184610Salfred	},
643184610Salfred	{USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY2, RID_WILDCARD,
644184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_BBB,
645184610Salfred		NO_QUIRKS
646184610Salfred	},
647184610Salfred	{USB_VENDOR_MYSON, USB_PRODUCT_MYSON_HEDEN, RID_WILDCARD,
648192052Sthompsa		UMASS_PROTO_DEFAULT,
649190263Simp		IGNORE_RESIDUE | NO_SYNCHRONIZE_CACHE
650184610Salfred	},
651194582Sremko	{USB_VENDOR_MYSON, USB_PRODUCT_MYSON_HEDEN_8813, RID_WILDCARD,
652194584Sremko		UMASS_PROTO_DEFAULT,
653194582Sremko		NO_SYNCHRONIZE_CACHE
654194582Sremko	},
655187726Sthompsa	{USB_VENDOR_MYSON, USB_PRODUCT_MYSON_STARREADER, RID_WILDCARD,
656192052Sthompsa		UMASS_PROTO_DEFAULT,
657187726Sthompsa		NO_SYNCHRONIZE_CACHE
658187726Sthompsa	},
659184610Salfred	{USB_VENDOR_NEODIO, USB_PRODUCT_NEODIO_ND3260, RID_WILDCARD,
660184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
661184610Salfred		FORCE_SHORT_INQUIRY
662184610Salfred	},
663184610Salfred	{USB_VENDOR_NETAC, USB_PRODUCT_NETAC_CF_CARD, RID_WILDCARD,
664184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
665184610Salfred		NO_INQUIRY
666184610Salfred	},
667184610Salfred	{USB_VENDOR_NETAC, USB_PRODUCT_NETAC_ONLYDISK, RID_WILDCARD,
668184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
669184610Salfred		IGNORE_RESIDUE
670184610Salfred	},
671184610Salfred	{USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_CLIK_40, RID_WILDCARD,
672184610Salfred		UMASS_PROTO_ATAPI,
673184610Salfred		NO_INQUIRY
674184610Salfred	},
675184610Salfred	{USB_VENDOR_NIKON, USB_PRODUCT_NIKON_D300, RID_WILDCARD,
676184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
677184610Salfred		NO_QUIRKS
678184610Salfred	},
679184610Salfred	{USB_VENDOR_OLYMPUS, USB_PRODUCT_OLYMPUS_C1, RID_WILDCARD,
680184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
681184610Salfred		WRONG_CSWSIG
682184610Salfred	},
683184610Salfred	{USB_VENDOR_OLYMPUS, USB_PRODUCT_OLYMPUS_C700, RID_WILDCARD,
684199062Sthompsa		UMASS_PROTO_DEFAULT,
685184610Salfred		NO_GETMAXLUN
686184610Salfred	},
687186730Salfred	{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_SDS_HOTFIND_D, RID_WILDCARD,
688186730Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
689186730Salfred		NO_GETMAXLUN | NO_SYNCHRONIZE_CACHE
690186730Salfred	},
691184610Salfred	{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_CFMS_RW, RID_WILDCARD,
692184610Salfred		UMASS_PROTO_SCSI,
693184610Salfred		NO_QUIRKS
694184610Salfred	},
695184610Salfred	{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_CFSM_COMBO, RID_WILDCARD,
696184610Salfred		UMASS_PROTO_SCSI,
697184610Salfred		NO_QUIRKS
698184610Salfred	},
699184610Salfred	{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_CFSM_READER, RID_WILDCARD,
700184610Salfred		UMASS_PROTO_SCSI,
701184610Salfred		NO_QUIRKS
702184610Salfred	},
703184610Salfred	{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_CFSM_READER2, RID_WILDCARD,
704184610Salfred		UMASS_PROTO_SCSI,
705184610Salfred		NO_QUIRKS
706184610Salfred	},
707184610Salfred	{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_MDCFE_B_CF_READER, RID_WILDCARD,
708184610Salfred		UMASS_PROTO_SCSI,
709184610Salfred		NO_QUIRKS
710184610Salfred	},
711184610Salfred	{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_MDSM_B_READER, RID_WILDCARD,
712184610Salfred		UMASS_PROTO_SCSI,
713184610Salfred		NO_INQUIRY
714184610Salfred	},
715184610Salfred	{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_READER, RID_WILDCARD,
716184610Salfred		UMASS_PROTO_SCSI,
717184610Salfred		NO_QUIRKS
718184610Salfred	},
719184610Salfred	{USB_VENDOR_ONSPEC, USB_PRODUCT_ONSPEC_UCF100, RID_WILDCARD,
720184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_BBB,
721184610Salfred		NO_INQUIRY | NO_GETMAXLUN
722184610Salfred	},
723184610Salfred	{USB_VENDOR_ONSPEC2, USB_PRODUCT_ONSPEC2_IMAGEMATE_SDDR55, RID_WILDCARD,
724184610Salfred		UMASS_PROTO_SCSI,
725184610Salfred		NO_GETMAXLUN
726184610Salfred	},
727184610Salfred	{USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXL840AN, RID_WILDCARD,
728184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_BBB,
729184610Salfred		NO_GETMAXLUN
730184610Salfred	},
731184610Salfred	{USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXLCB20AN, RID_WILDCARD,
732184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
733184610Salfred		NO_QUIRKS
734184610Salfred	},
735184610Salfred	{USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_KXLCB35AN, RID_WILDCARD,
736184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
737184610Salfred		NO_QUIRKS
738184610Salfred	},
739184610Salfred	{USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_LS120CAM, RID_WILDCARD,
740184610Salfred		UMASS_PROTO_UFI,
741184610Salfred		NO_QUIRKS
742184610Salfred	},
743196495Salfred	{ USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_SPE3030CC, RID_WILDCARD,
744196495Salfred		UMASS_PROTO_DEFAULT,
745196495Salfred		NO_SYNCHRONIZE_CACHE
746196495Salfred	},
747184610Salfred	{USB_VENDOR_PLEXTOR, USB_PRODUCT_PLEXTOR_40_12_40U, RID_WILDCARD,
748184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
749184610Salfred		NO_TEST_UNIT_READY
750184610Salfred	},
751184610Salfred	{USB_VENDOR_PNY, USB_PRODUCT_PNY_ATTACHE2, RID_WILDCARD,
752184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
753184610Salfred		IGNORE_RESIDUE | NO_START_STOP
754184610Salfred	},
755184610Salfred	{USB_VENDOR_SAMSUNG_TECHWIN, USB_PRODUCT_SAMSUNG_TECHWIN_DIGIMAX_410, RID_WILDCARD,
756184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
757184610Salfred		NO_INQUIRY
758184610Salfred	},
759184610Salfred	{USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR05A, RID_WILDCARD,
760184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_CBI,
761184610Salfred		READ_CAPACITY_OFFBY1 | NO_GETMAXLUN
762184610Salfred	},
763184610Salfred	{USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR09, RID_WILDCARD,
764184610Salfred		UMASS_PROTO_SCSI,
765184610Salfred		READ_CAPACITY_OFFBY1 | NO_GETMAXLUN
766184610Salfred	},
767184610Salfred	{USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR12, RID_WILDCARD,
768184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_CBI,
769184610Salfred		READ_CAPACITY_OFFBY1 | NO_GETMAXLUN
770184610Salfred	},
771184610Salfred	{USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ2_256, RID_WILDCARD,
772184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
773184610Salfred		IGNORE_RESIDUE
774184610Salfred	},
775184610Salfred	{USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ4_128, RID_WILDCARD,
776184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
777184610Salfred		IGNORE_RESIDUE
778184610Salfred	},
779184610Salfred	{USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDCZ4_256, RID_WILDCARD,
780184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
781184610Salfred		IGNORE_RESIDUE
782184610Salfred	},
783184610Salfred	{USB_VENDOR_SANDISK, USB_PRODUCT_SANDISK_SDDR31, RID_WILDCARD,
784184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
785184610Salfred		READ_CAPACITY_OFFBY1
786184610Salfred	},
787184610Salfred	{USB_VENDOR_SCANLOGIC, USB_PRODUCT_SCANLOGIC_SL11R, RID_WILDCARD,
788184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_BBB,
789184610Salfred		NO_INQUIRY
790184610Salfred	},
791184610Salfred	{USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSB, RID_WILDCARD,
792184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I,
793184610Salfred		NO_TEST_UNIT_READY | NO_START_STOP | SHUTTLE_INIT
794184610Salfred	},
795184610Salfred	{USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_CDRW, RID_WILDCARD,
796184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI,
797184610Salfred		NO_QUIRKS
798184610Salfred	},
799184610Salfred	{USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_CF, RID_WILDCARD,
800184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI,
801184610Salfred		NO_QUIRKS
802184610Salfred	},
803184610Salfred	{USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSBATAPI, RID_WILDCARD,
804184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI,
805184610Salfred		NO_QUIRKS
806184610Salfred	},
807184610Salfred	{USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSBCFSM, RID_WILDCARD,
808184610Salfred		UMASS_PROTO_SCSI,
809184610Salfred		NO_QUIRKS
810184610Salfred	},
811184610Salfred	{USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_EUSCSI, RID_WILDCARD,
812184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
813184610Salfred		NO_QUIRKS
814184610Salfred	},
815184610Salfred	{USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_HIFD, RID_WILDCARD,
816184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_CBI,
817184610Salfred		NO_GETMAXLUN
818184610Salfred	},
819184610Salfred	{USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_SDDR09, RID_WILDCARD,
820184610Salfred		UMASS_PROTO_SCSI,
821184610Salfred		NO_GETMAXLUN
822184610Salfred	},
823184610Salfred	{USB_VENDOR_SHUTTLE, USB_PRODUCT_SHUTTLE_ZIOMMC, RID_WILDCARD,
824184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_CBI,
825184610Salfred		NO_GETMAXLUN
826184610Salfred	},
827184610Salfred	{USB_VENDOR_SIGMATEL, USB_PRODUCT_SIGMATEL_I_BEAD100, RID_WILDCARD,
828184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
829184610Salfred		SHUTTLE_INIT
830184610Salfred	},
831184610Salfred	{USB_VENDOR_SIIG, USB_PRODUCT_SIIG_WINTERREADER, RID_WILDCARD,
832184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
833184610Salfred		IGNORE_RESIDUE
834184610Salfred	},
835184610Salfred	{USB_VENDOR_SKANHEX, USB_PRODUCT_SKANHEX_MD_7425, RID_WILDCARD,
836184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
837184610Salfred		NO_INQUIRY
838184610Salfred	},
839184610Salfred	{USB_VENDOR_SKANHEX, USB_PRODUCT_SKANHEX_SX_520Z, RID_WILDCARD,
840184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
841184610Salfred		NO_INQUIRY
842184610Salfred	},
843184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_HANDYCAM, 0x0500,
844184610Salfred		UMASS_PROTO_RBC | UMASS_PROTO_CBI,
845184610Salfred		RBC_PAD_TO_12
846184610Salfred	},
847184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_40_MS, RID_WILDCARD,
848184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
849184610Salfred		NO_INQUIRY
850184610Salfred	},
851184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, 0x0500,
852184610Salfred		UMASS_PROTO_RBC | UMASS_PROTO_CBI,
853184610Salfred		RBC_PAD_TO_12
854184610Salfred	},
855184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, 0x0600,
856184610Salfred		UMASS_PROTO_RBC | UMASS_PROTO_CBI,
857184610Salfred		RBC_PAD_TO_12
858184610Salfred	},
859184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_DSC, RID_WILDCARD,
860184610Salfred		UMASS_PROTO_RBC | UMASS_PROTO_CBI,
861184610Salfred		NO_QUIRKS
862184610Salfred	},
863184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_HANDYCAM, RID_WILDCARD,
864184610Salfred		UMASS_PROTO_RBC | UMASS_PROTO_CBI,
865184610Salfred		NO_QUIRKS
866184610Salfred	},
867184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_MSC, RID_WILDCARD,
868184610Salfred		UMASS_PROTO_RBC | UMASS_PROTO_CBI,
869184610Salfred		NO_QUIRKS
870184610Salfred	},
871184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_MS_MSC_U03, RID_WILDCARD,
872184610Salfred		UMASS_PROTO_UFI | UMASS_PROTO_CBI,
873184610Salfred		NO_GETMAXLUN
874184610Salfred	},
875184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_MS_NW_MS7, RID_WILDCARD,
876184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
877184610Salfred		NO_GETMAXLUN
878184610Salfred	},
879184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_MS_PEG_N760C, RID_WILDCARD,
880184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
881184610Salfred		NO_INQUIRY
882184610Salfred	},
883184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_MSACUS1, RID_WILDCARD,
884184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
885184610Salfred		NO_GETMAXLUN
886184610Salfred	},
887184610Salfred	{USB_VENDOR_SONY, USB_PRODUCT_SONY_PORTABLE_HDD_V2, RID_WILDCARD,
888184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
889184610Salfred		NO_QUIRKS
890184610Salfred	},
891189905Sthompsa	{USB_VENDOR_SUPERTOP, USB_PRODUCT_SUPERTOP_IDE, RID_WILDCARD,
892192052Sthompsa		UMASS_PROTO_DEFAULT,
893189905Sthompsa		IGNORE_RESIDUE | NO_SYNCHRONIZE_CACHE
894189905Sthompsa	},
895184610Salfred	{USB_VENDOR_TAUGA, USB_PRODUCT_TAUGA_CAMERAMATE, RID_WILDCARD,
896184610Salfred		UMASS_PROTO_SCSI,
897184610Salfred		NO_QUIRKS
898184610Salfred	},
899184610Salfred	{USB_VENDOR_TEAC, USB_PRODUCT_TEAC_FD05PUB, RID_WILDCARD,
900184610Salfred		UMASS_PROTO_UFI | UMASS_PROTO_CBI,
901184610Salfred		NO_QUIRKS
902184610Salfred	},
903196495Salfred	{USB_VENDOR_TECLAST, USB_PRODUCT_TECLAST_TLC300, RID_WILDCARD,
904196495Salfred		UMASS_PROTO_DEFAULT,
905196495Salfred		NO_TEST_UNIT_READY | NO_SYNCHRONIZE_CACHE
906196495Salfred	},
907184610Salfred	{USB_VENDOR_TREK, USB_PRODUCT_TREK_MEMKEY, RID_WILDCARD,
908184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
909184610Salfred		NO_INQUIRY
910184610Salfred	},
911184610Salfred	{USB_VENDOR_TREK, USB_PRODUCT_TREK_THUMBDRIVE_8MB, RID_WILDCARD,
912184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_BBB,
913184610Salfred		IGNORE_RESIDUE
914184610Salfred	},
915184610Salfred	{USB_VENDOR_TRUMPION, USB_PRODUCT_TRUMPION_C3310, RID_WILDCARD,
916184610Salfred		UMASS_PROTO_UFI | UMASS_PROTO_CBI,
917184610Salfred		NO_QUIRKS
918184610Salfred	},
919184610Salfred	{USB_VENDOR_TRUMPION, USB_PRODUCT_TRUMPION_MP3, RID_WILDCARD,
920184610Salfred		UMASS_PROTO_RBC,
921184610Salfred		NO_QUIRKS
922184610Salfred	},
923184610Salfred	{USB_VENDOR_TRUMPION, USB_PRODUCT_TRUMPION_T33520, RID_WILDCARD,
924184610Salfred		UMASS_PROTO_SCSI,
925184610Salfred		NO_QUIRKS
926184610Salfred	},
927184610Salfred	{USB_VENDOR_TWINMOS, USB_PRODUCT_TWINMOS_MDIV, RID_WILDCARD,
928184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
929184610Salfred		NO_QUIRKS
930184610Salfred	},
931184610Salfred	{USB_VENDOR_VIA, USB_PRODUCT_VIA_USB2IDEBRIDGE, RID_WILDCARD,
932184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
933184610Salfred		NO_SYNCHRONIZE_CACHE
934184610Salfred	},
935184610Salfred	{USB_VENDOR_VIVITAR, USB_PRODUCT_VIVITAR_35XX, RID_WILDCARD,
936184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
937184610Salfred		NO_INQUIRY
938184610Salfred	},
939184610Salfred	{USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_COMBO, RID_WILDCARD,
940184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
941184610Salfred		FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE
942184610Salfred	},
943184610Salfred	{USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_EXTHDD, RID_WILDCARD,
944184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
945184610Salfred		FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE
946184610Salfred	},
947184610Salfred	{USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_MYBOOK, RID_WILDCARD,
948184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
949184610Salfred		NO_INQUIRY_EVPD
950184610Salfred	},
951197565Sthompsa	{USB_VENDOR_WESTERN, USB_PRODUCT_WESTERN_MYPASSWORD, RID_WILDCARD,
952197565Sthompsa		UMASS_PROTO_DEFAULT,
953197565Sthompsa		FORCE_SHORT_INQUIRY
954197565Sthompsa	},
955184610Salfred	{USB_VENDOR_WINMAXGROUP, USB_PRODUCT_WINMAXGROUP_FLASH64MC, RID_WILDCARD,
956184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
957184610Salfred		NO_INQUIRY
958184610Salfred	},
959184610Salfred	{USB_VENDOR_YANO, USB_PRODUCT_YANO_FW800HD, RID_WILDCARD,
960184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
961184610Salfred		FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE
962184610Salfred	},
963184610Salfred	{USB_VENDOR_YANO, USB_PRODUCT_YANO_U640MO, RID_WILDCARD,
964184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I,
965184610Salfred		FORCE_SHORT_INQUIRY
966184610Salfred	},
967184610Salfred	{USB_VENDOR_YEDATA, USB_PRODUCT_YEDATA_FLASHBUSTERU, RID_WILDCARD,
968184610Salfred		UMASS_PROTO_SCSI | UMASS_PROTO_CBI,
969184610Salfred		NO_GETMAXLUN
970184610Salfred	},
971184610Salfred	{USB_VENDOR_ZORAN, USB_PRODUCT_ZORAN_EX20DSC, RID_WILDCARD,
972184610Salfred		UMASS_PROTO_ATAPI | UMASS_PROTO_CBI,
973184610Salfred		NO_QUIRKS
974184610Salfred	},
975187163Sthompsa	{USB_VENDOR_MEIZU, USB_PRODUCT_MEIZU_M6_SL, RID_WILDCARD,
976187163Sthompsa		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
977187163Sthompsa		NO_INQUIRY | NO_SYNCHRONIZE_CACHE
978187163Sthompsa	},
979195080Sdelphij	{USB_VENDOR_ACTIONS, USB_PRODUCT_ACTIONS_MP4, RID_WILDCARD,
980195080Sdelphij		UMASS_PROTO_SCSI | UMASS_PROTO_BBB,
981195080Sdelphij		NO_SYNCHRONIZE_CACHE
982195080Sdelphij	},
983196495Salfred	{USB_VENDOR_ASUS, USB_PRODUCT_ASUS_GMSC, RID_WILDCARD,
984196495Salfred		UMASS_PROTO_DEFAULT,
985196495Salfred		NO_SYNCHRONIZE_CACHE
986196495Salfred	},
987184610Salfred	{VID_EOT, PID_EOT, RID_EOT, 0, 0}
988184610Salfred};
989184610Salfred
990184610Salfredstruct umass_softc {
991184610Salfred
992184610Salfred	struct scsi_sense cam_scsi_sense;
993184610Salfred	struct scsi_test_unit_ready cam_scsi_test_unit_ready;
994184610Salfred	struct mtx sc_mtx;
995184610Salfred	struct {
996184610Salfred		uint8_t *data_ptr;
997184610Salfred		union ccb *ccb;
998184610Salfred		umass_callback_t *callback;
999184610Salfred
1000184610Salfred		uint32_t data_len;	/* bytes */
1001184610Salfred		uint32_t data_rem;	/* bytes */
1002184610Salfred		uint32_t data_timeout;	/* ms */
1003184610Salfred		uint32_t actlen;	/* bytes */
1004184610Salfred
1005184610Salfred		uint8_t	cmd_data[UMASS_MAX_CMDLEN];
1006184610Salfred		uint8_t	cmd_len;	/* bytes */
1007184610Salfred		uint8_t	dir;
1008184610Salfred		uint8_t	lun;
1009184610Salfred	}	sc_transfer;
1010184610Salfred
1011184610Salfred	/* Bulk specific variables for transfers in progress */
1012184610Salfred	umass_bbb_cbw_t cbw;		/* command block wrapper */
1013184610Salfred	umass_bbb_csw_t csw;		/* command status wrapper */
1014184610Salfred
1015184610Salfred	/* CBI specific variables for transfers in progress */
1016184610Salfred	umass_cbi_sbl_t sbl;		/* status block */
1017184610Salfred
1018184610Salfred	device_t sc_dev;
1019192984Sthompsa	struct usb_device *sc_udev;
1020184610Salfred	struct cam_sim *sc_sim;		/* SCSI Interface Module */
1021192984Sthompsa	struct usb_xfer *sc_xfer[UMASS_T_MAX];
1022184610Salfred
1023184610Salfred	/*
1024184610Salfred	 * The command transform function is used to convert the SCSI
1025184610Salfred	 * commands into their derivatives, like UFI, ATAPI, and friends.
1026184610Salfred	 */
1027184610Salfred	umass_transform_t *sc_transform;
1028184610Salfred
1029184610Salfred	uint32_t sc_unit;
1030184610Salfred
1031184610Salfred	uint16_t sc_proto;		/* wire and cmd protocol */
1032184610Salfred	uint16_t sc_quirks;		/* they got it almost right */
1033184610Salfred
1034184610Salfred	uint8_t	sc_name[16];
1035184610Salfred	uint8_t	sc_iface_no;		/* interface number */
1036184610Salfred	uint8_t	sc_maxlun;		/* maximum LUN number, inclusive */
1037184610Salfred	uint8_t	sc_last_xfer_index;
1038184610Salfred	uint8_t	sc_status_try;
1039184610Salfred};
1040184610Salfred
1041184610Salfredstruct umass_probe_proto {
1042184610Salfred	uint16_t quirks;
1043184610Salfred	uint16_t proto;
1044184610Salfred
1045184610Salfred	int32_t	error;
1046184610Salfred};
1047184610Salfred
1048184610Salfred/* prototypes */
1049184610Salfred
1050184610Salfredstatic device_probe_t umass_probe;
1051184610Salfredstatic device_attach_t umass_attach;
1052184610Salfredstatic device_detach_t umass_detach;
1053184610Salfred
1054193045Sthompsastatic usb_callback_t umass_tr_error;
1055193045Sthompsastatic usb_callback_t umass_t_bbb_reset1_callback;
1056193045Sthompsastatic usb_callback_t umass_t_bbb_reset2_callback;
1057193045Sthompsastatic usb_callback_t umass_t_bbb_reset3_callback;
1058193045Sthompsastatic usb_callback_t umass_t_bbb_command_callback;
1059193045Sthompsastatic usb_callback_t umass_t_bbb_data_read_callback;
1060193045Sthompsastatic usb_callback_t umass_t_bbb_data_rd_cs_callback;
1061193045Sthompsastatic usb_callback_t umass_t_bbb_data_write_callback;
1062193045Sthompsastatic usb_callback_t umass_t_bbb_data_wr_cs_callback;
1063193045Sthompsastatic usb_callback_t umass_t_bbb_status_callback;
1064193045Sthompsastatic usb_callback_t umass_t_cbi_reset1_callback;
1065193045Sthompsastatic usb_callback_t umass_t_cbi_reset2_callback;
1066193045Sthompsastatic usb_callback_t umass_t_cbi_reset3_callback;
1067193045Sthompsastatic usb_callback_t umass_t_cbi_reset4_callback;
1068193045Sthompsastatic usb_callback_t umass_t_cbi_command_callback;
1069193045Sthompsastatic usb_callback_t umass_t_cbi_data_read_callback;
1070193045Sthompsastatic usb_callback_t umass_t_cbi_data_rd_cs_callback;
1071193045Sthompsastatic usb_callback_t umass_t_cbi_data_write_callback;
1072193045Sthompsastatic usb_callback_t umass_t_cbi_data_wr_cs_callback;
1073193045Sthompsastatic usb_callback_t umass_t_cbi_status_callback;
1074184610Salfred
1075185948Sthompsastatic void	umass_cancel_ccb(struct umass_softc *);
1076185948Sthompsastatic void	umass_init_shuttle(struct umass_softc *);
1077185948Sthompsastatic void	umass_reset(struct umass_softc *);
1078192984Sthompsastatic void	umass_t_bbb_data_clear_stall_callback(struct usb_xfer *,
1079194677Sthompsa		    uint8_t, uint8_t, usb_error_t);
1080185948Sthompsastatic void	umass_command_start(struct umass_softc *, uint8_t, void *,
1081185948Sthompsa		    uint32_t, uint32_t, umass_callback_t *, union ccb *);
1082185948Sthompsastatic uint8_t	umass_bbb_get_max_lun(struct umass_softc *);
1083185948Sthompsastatic void	umass_cbi_start_status(struct umass_softc *);
1084192984Sthompsastatic void	umass_t_cbi_data_clear_stall_callback(struct usb_xfer *,
1085194677Sthompsa		    uint8_t, uint8_t, usb_error_t);
1086185948Sthompsastatic int	umass_cam_attach_sim(struct umass_softc *);
1087185948Sthompsastatic void	umass_cam_rescan_callback(struct cam_periph *, union ccb *);
1088185948Sthompsastatic void	umass_cam_rescan(struct umass_softc *);
1089185948Sthompsastatic void	umass_cam_attach(struct umass_softc *);
1090185948Sthompsastatic void	umass_cam_detach_sim(struct umass_softc *);
1091185948Sthompsastatic void	umass_cam_action(struct cam_sim *, union ccb *);
1092185948Sthompsastatic void	umass_cam_poll(struct cam_sim *);
1093185948Sthompsastatic void	umass_cam_cb(struct umass_softc *, union ccb *, uint32_t,
1094185948Sthompsa		    uint8_t);
1095185948Sthompsastatic void	umass_cam_sense_cb(struct umass_softc *, union ccb *, uint32_t,
1096185948Sthompsa		    uint8_t);
1097185948Sthompsastatic void	umass_cam_quirk_cb(struct umass_softc *, union ccb *, uint32_t,
1098185948Sthompsa		    uint8_t);
1099185948Sthompsastatic uint8_t	umass_scsi_transform(struct umass_softc *, uint8_t *, uint8_t);
1100185948Sthompsastatic uint8_t	umass_rbc_transform(struct umass_softc *, uint8_t *, uint8_t);
1101185948Sthompsastatic uint8_t	umass_ufi_transform(struct umass_softc *, uint8_t *, uint8_t);
1102185948Sthompsastatic uint8_t	umass_atapi_transform(struct umass_softc *, uint8_t *,
1103185948Sthompsa		    uint8_t);
1104185948Sthompsastatic uint8_t	umass_no_transform(struct umass_softc *, uint8_t *, uint8_t);
1105185948Sthompsastatic uint8_t	umass_std_transform(struct umass_softc *, union ccb *, uint8_t
1106185948Sthompsa		    *, uint8_t);
1107184610Salfred
1108184610Salfred#if USB_DEBUG
1109185948Sthompsastatic void	umass_bbb_dump_cbw(struct umass_softc *, umass_bbb_cbw_t *);
1110185948Sthompsastatic void	umass_bbb_dump_csw(struct umass_softc *, umass_bbb_csw_t *);
1111185948Sthompsastatic void	umass_cbi_dump_cmd(struct umass_softc *, void *, uint8_t);
1112185948Sthompsastatic void	umass_dump_buffer(struct umass_softc *, uint8_t *, uint32_t,
1113185948Sthompsa		    uint32_t);
1114184610Salfred#endif
1115184610Salfred
1116194099Sthompsastatic struct usb_config umass_bbb_config[UMASS_T_BBB_MAX] = {
1117184610Salfred
1118184610Salfred	[UMASS_T_BBB_RESET1] = {
1119184610Salfred		.type = UE_CONTROL,
1120184610Salfred		.endpoint = 0x00,	/* Control pipe */
1121184610Salfred		.direction = UE_DIR_ANY,
1122192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1123190734Sthompsa		.callback = &umass_t_bbb_reset1_callback,
1124190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1125190734Sthompsa		.interval = 500,	/* 500 milliseconds */
1126184610Salfred	},
1127184610Salfred
1128184610Salfred	[UMASS_T_BBB_RESET2] = {
1129184610Salfred		.type = UE_CONTROL,
1130184610Salfred		.endpoint = 0x00,	/* Control pipe */
1131184610Salfred		.direction = UE_DIR_ANY,
1132192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1133190734Sthompsa		.callback = &umass_t_bbb_reset2_callback,
1134190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1135190734Sthompsa		.interval = 50,	/* 50 milliseconds */
1136184610Salfred	},
1137184610Salfred
1138184610Salfred	[UMASS_T_BBB_RESET3] = {
1139184610Salfred		.type = UE_CONTROL,
1140184610Salfred		.endpoint = 0x00,	/* Control pipe */
1141184610Salfred		.direction = UE_DIR_ANY,
1142192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1143190734Sthompsa		.callback = &umass_t_bbb_reset3_callback,
1144190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1145190734Sthompsa		.interval = 50,	/* 50 milliseconds */
1146184610Salfred	},
1147184610Salfred
1148184610Salfred	[UMASS_T_BBB_COMMAND] = {
1149184610Salfred		.type = UE_BULK,
1150184610Salfred		.endpoint = UE_ADDR_ANY,
1151184610Salfred		.direction = UE_DIR_OUT,
1152190734Sthompsa		.bufsize = sizeof(umass_bbb_cbw_t),
1153190734Sthompsa		.callback = &umass_t_bbb_command_callback,
1154190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1155184610Salfred	},
1156184610Salfred
1157184610Salfred	[UMASS_T_BBB_DATA_READ] = {
1158184610Salfred		.type = UE_BULK,
1159184610Salfred		.endpoint = UE_ADDR_ANY,
1160184610Salfred		.direction = UE_DIR_IN,
1161190734Sthompsa		.bufsize = UMASS_BULK_SIZE,
1162190734Sthompsa		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS},
1163190734Sthompsa		.callback = &umass_t_bbb_data_read_callback,
1164190734Sthompsa		.timeout = 0,	/* overwritten later */
1165184610Salfred	},
1166184610Salfred
1167184610Salfred	[UMASS_T_BBB_DATA_RD_CS] = {
1168184610Salfred		.type = UE_CONTROL,
1169184610Salfred		.endpoint = 0x00,	/* Control pipe */
1170184610Salfred		.direction = UE_DIR_ANY,
1171192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1172190734Sthompsa		.callback = &umass_t_bbb_data_rd_cs_callback,
1173190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1174184610Salfred	},
1175184610Salfred
1176184610Salfred	[UMASS_T_BBB_DATA_WRITE] = {
1177184610Salfred		.type = UE_BULK,
1178184610Salfred		.endpoint = UE_ADDR_ANY,
1179184610Salfred		.direction = UE_DIR_OUT,
1180190734Sthompsa		.bufsize = UMASS_BULK_SIZE,
1181190734Sthompsa		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS},
1182190734Sthompsa		.callback = &umass_t_bbb_data_write_callback,
1183190734Sthompsa		.timeout = 0,	/* overwritten later */
1184184610Salfred	},
1185184610Salfred
1186184610Salfred	[UMASS_T_BBB_DATA_WR_CS] = {
1187184610Salfred		.type = UE_CONTROL,
1188184610Salfred		.endpoint = 0x00,	/* Control pipe */
1189184610Salfred		.direction = UE_DIR_ANY,
1190192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1191190734Sthompsa		.callback = &umass_t_bbb_data_wr_cs_callback,
1192190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1193184610Salfred	},
1194184610Salfred
1195184610Salfred	[UMASS_T_BBB_STATUS] = {
1196184610Salfred		.type = UE_BULK,
1197184610Salfred		.endpoint = UE_ADDR_ANY,
1198184610Salfred		.direction = UE_DIR_IN,
1199190734Sthompsa		.bufsize = sizeof(umass_bbb_csw_t),
1200190734Sthompsa		.flags = {.short_xfer_ok = 1,},
1201190734Sthompsa		.callback = &umass_t_bbb_status_callback,
1202190734Sthompsa		.timeout = 5000,	/* ms */
1203184610Salfred	},
1204184610Salfred};
1205184610Salfred
1206194099Sthompsastatic struct usb_config umass_cbi_config[UMASS_T_CBI_MAX] = {
1207184610Salfred
1208184610Salfred	[UMASS_T_CBI_RESET1] = {
1209184610Salfred		.type = UE_CONTROL,
1210184610Salfred		.endpoint = 0x00,	/* Control pipe */
1211184610Salfred		.direction = UE_DIR_ANY,
1212192984Sthompsa		.bufsize = (sizeof(struct usb_device_request) +
1213184610Salfred		    UMASS_CBI_DIAGNOSTIC_CMDLEN),
1214190734Sthompsa		.callback = &umass_t_cbi_reset1_callback,
1215190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1216190734Sthompsa		.interval = 500,	/* 500 milliseconds */
1217184610Salfred	},
1218184610Salfred
1219184610Salfred	[UMASS_T_CBI_RESET2] = {
1220184610Salfred		.type = UE_CONTROL,
1221184610Salfred		.endpoint = 0x00,	/* Control pipe */
1222184610Salfred		.direction = UE_DIR_ANY,
1223192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1224190734Sthompsa		.callback = &umass_t_cbi_reset2_callback,
1225190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1226190734Sthompsa		.interval = 50,	/* 50 milliseconds */
1227184610Salfred	},
1228184610Salfred
1229184610Salfred	[UMASS_T_CBI_RESET3] = {
1230184610Salfred		.type = UE_CONTROL,
1231184610Salfred		.endpoint = 0x00,	/* Control pipe */
1232184610Salfred		.direction = UE_DIR_ANY,
1233192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1234190734Sthompsa		.callback = &umass_t_cbi_reset3_callback,
1235190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1236190734Sthompsa		.interval = 50,	/* 50 milliseconds */
1237184610Salfred	},
1238184610Salfred
1239184610Salfred	[UMASS_T_CBI_COMMAND] = {
1240184610Salfred		.type = UE_CONTROL,
1241184610Salfred		.endpoint = 0x00,	/* Control pipe */
1242184610Salfred		.direction = UE_DIR_ANY,
1243192984Sthompsa		.bufsize = (sizeof(struct usb_device_request) +
1244184610Salfred		    UMASS_MAX_CMDLEN),
1245190734Sthompsa		.callback = &umass_t_cbi_command_callback,
1246190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1247184610Salfred	},
1248184610Salfred
1249184610Salfred	[UMASS_T_CBI_DATA_READ] = {
1250184610Salfred		.type = UE_BULK,
1251184610Salfred		.endpoint = UE_ADDR_ANY,
1252184610Salfred		.direction = UE_DIR_IN,
1253190734Sthompsa		.bufsize = UMASS_BULK_SIZE,
1254190734Sthompsa		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS},
1255190734Sthompsa		.callback = &umass_t_cbi_data_read_callback,
1256190734Sthompsa		.timeout = 0,	/* overwritten later */
1257184610Salfred	},
1258184610Salfred
1259184610Salfred	[UMASS_T_CBI_DATA_RD_CS] = {
1260184610Salfred		.type = UE_CONTROL,
1261184610Salfred		.endpoint = 0x00,	/* Control pipe */
1262184610Salfred		.direction = UE_DIR_ANY,
1263192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1264190734Sthompsa		.callback = &umass_t_cbi_data_rd_cs_callback,
1265190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1266184610Salfred	},
1267184610Salfred
1268184610Salfred	[UMASS_T_CBI_DATA_WRITE] = {
1269184610Salfred		.type = UE_BULK,
1270184610Salfred		.endpoint = UE_ADDR_ANY,
1271184610Salfred		.direction = UE_DIR_OUT,
1272190734Sthompsa		.bufsize = UMASS_BULK_SIZE,
1273190734Sthompsa		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1, UMASS_USB_FLAGS},
1274190734Sthompsa		.callback = &umass_t_cbi_data_write_callback,
1275190734Sthompsa		.timeout = 0,	/* overwritten later */
1276184610Salfred	},
1277184610Salfred
1278184610Salfred	[UMASS_T_CBI_DATA_WR_CS] = {
1279184610Salfred		.type = UE_CONTROL,
1280184610Salfred		.endpoint = 0x00,	/* Control pipe */
1281184610Salfred		.direction = UE_DIR_ANY,
1282192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1283190734Sthompsa		.callback = &umass_t_cbi_data_wr_cs_callback,
1284190734Sthompsa		.timeout = 5000,	/* 5 seconds */
1285184610Salfred	},
1286184610Salfred
1287184610Salfred	[UMASS_T_CBI_STATUS] = {
1288184610Salfred		.type = UE_INTERRUPT,
1289184610Salfred		.endpoint = UE_ADDR_ANY,
1290184610Salfred		.direction = UE_DIR_IN,
1291190734Sthompsa		.flags = {.short_xfer_ok = 1,},
1292190734Sthompsa		.bufsize = sizeof(umass_cbi_sbl_t),
1293190734Sthompsa		.callback = &umass_t_cbi_status_callback,
1294190734Sthompsa		.timeout = 5000,	/* ms */
1295184610Salfred	},
1296184610Salfred
1297184610Salfred	[UMASS_T_CBI_RESET4] = {
1298184610Salfred		.type = UE_CONTROL,
1299184610Salfred		.endpoint = 0x00,	/* Control pipe */
1300184610Salfred		.direction = UE_DIR_ANY,
1301192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
1302190734Sthompsa		.callback = &umass_t_cbi_reset4_callback,
1303190734Sthompsa		.timeout = 5000,	/* ms */
1304184610Salfred	},
1305184610Salfred};
1306184610Salfred
1307184610Salfred/* If device cannot return valid inquiry data, fake it */
1308184610Salfredstatic const uint8_t fake_inq_data[SHORT_INQUIRY_LENGTH] = {
1309184610Salfred	0, /* removable */ 0x80, SCSI_REV_2, SCSI_REV_2,
1310184610Salfred	 /* additional_length */ 31, 0, 0, 0
1311184610Salfred};
1312184610Salfred
1313184610Salfred#define	UFI_COMMAND_LENGTH	12	/* UFI commands are always 12 bytes */
1314184610Salfred#define	ATAPI_COMMAND_LENGTH	12	/* ATAPI commands are always 12 bytes */
1315184610Salfred
1316184610Salfredstatic devclass_t umass_devclass;
1317184610Salfred
1318184610Salfredstatic device_method_t umass_methods[] = {
1319184610Salfred	/* Device interface */
1320184610Salfred	DEVMETHOD(device_probe, umass_probe),
1321184610Salfred	DEVMETHOD(device_attach, umass_attach),
1322184610Salfred	DEVMETHOD(device_detach, umass_detach),
1323184610Salfred	{0, 0}
1324184610Salfred};
1325184610Salfred
1326184610Salfredstatic driver_t umass_driver = {
1327184610Salfred	.name = "umass",
1328184610Salfred	.methods = umass_methods,
1329184610Salfred	.size = sizeof(struct umass_softc),
1330184610Salfred};
1331184610Salfred
1332189275SthompsaDRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, NULL, 0);
1333188942SthompsaMODULE_DEPEND(umass, usb, 1, 1, 1);
1334184610SalfredMODULE_DEPEND(umass, cam, 1, 1, 1);
1335184610Salfred
1336184610Salfred/*
1337184610Salfred * USB device probe/attach/detach
1338184610Salfred */
1339184610Salfred
1340192052Sthompsastatic uint16_t
1341192984Sthompsaumass_get_proto(struct usb_interface *iface)
1342192052Sthompsa{
1343192984Sthompsa	struct usb_interface_descriptor *id;
1344192052Sthompsa	uint16_t retval;
1345192052Sthompsa
1346192052Sthompsa	retval = 0;
1347192052Sthompsa
1348192052Sthompsa	/* Check for a standards compliant device */
1349194228Sthompsa	id = usbd_get_interface_descriptor(iface);
1350192052Sthompsa	if ((id == NULL) ||
1351192052Sthompsa	    (id->bInterfaceClass != UICLASS_MASS)) {
1352192052Sthompsa		goto done;
1353192052Sthompsa	}
1354192052Sthompsa	switch (id->bInterfaceSubClass) {
1355192052Sthompsa	case UISUBCLASS_SCSI:
1356192052Sthompsa		retval |= UMASS_PROTO_SCSI;
1357192052Sthompsa		break;
1358192052Sthompsa	case UISUBCLASS_UFI:
1359192052Sthompsa		retval |= UMASS_PROTO_UFI;
1360192052Sthompsa		break;
1361192052Sthompsa	case UISUBCLASS_RBC:
1362192052Sthompsa		retval |= UMASS_PROTO_RBC;
1363192052Sthompsa		break;
1364192052Sthompsa	case UISUBCLASS_SFF8020I:
1365192052Sthompsa	case UISUBCLASS_SFF8070I:
1366192052Sthompsa		retval |= UMASS_PROTO_ATAPI;
1367192052Sthompsa		break;
1368192052Sthompsa	default:
1369192052Sthompsa		retval = 0;
1370192052Sthompsa		goto done;
1371192052Sthompsa	}
1372192052Sthompsa
1373192052Sthompsa	switch (id->bInterfaceProtocol) {
1374192052Sthompsa	case UIPROTO_MASS_CBI:
1375192052Sthompsa		retval |= UMASS_PROTO_CBI;
1376192052Sthompsa		break;
1377192052Sthompsa	case UIPROTO_MASS_CBI_I:
1378192052Sthompsa		retval |= UMASS_PROTO_CBI_I;
1379192052Sthompsa		break;
1380192052Sthompsa	case UIPROTO_MASS_BBB_OLD:
1381192052Sthompsa	case UIPROTO_MASS_BBB:
1382192052Sthompsa		retval |= UMASS_PROTO_BBB;
1383192052Sthompsa		break;
1384192052Sthompsa	default:
1385192052Sthompsa		retval = 0;
1386192052Sthompsa		goto done;
1387192052Sthompsa	}
1388192052Sthompsadone:
1389192052Sthompsa	return (retval);
1390192052Sthompsa}
1391192052Sthompsa
1392184610Salfred/*
1393184610Salfred * Match the device we are seeing with the
1394184610Salfred * devices supported.
1395184610Salfred */
1396184610Salfredstatic struct umass_probe_proto
1397192984Sthompsaumass_probe_proto(device_t dev, struct usb_attach_arg *uaa)
1398184610Salfred{
1399184610Salfred	const struct umass_devdescr *udd = umass_devdescr;
1400184610Salfred	struct umass_probe_proto ret;
1401184610Salfred
1402192052Sthompsa	memset(&ret, 0, sizeof(ret));
1403184610Salfred
1404184610Salfred	/*
1405184610Salfred	 * An entry specifically for Y-E Data devices as they don't fit in
1406184610Salfred	 * the device description table.
1407184610Salfred	 */
1408184610Salfred	if ((uaa->info.idVendor == USB_VENDOR_YEDATA) &&
1409184610Salfred	    (uaa->info.idProduct == USB_PRODUCT_YEDATA_FLASHBUSTERU)) {
1410184610Salfred
1411184610Salfred		/*
1412184610Salfred		 * Revisions < 1.28 do not handle the interrupt endpoint
1413184610Salfred		 * very well.
1414184610Salfred		 */
1415184610Salfred		if (uaa->info.bcdDevice < 0x128) {
1416184610Salfred			ret.proto = UMASS_PROTO_UFI | UMASS_PROTO_CBI;
1417184610Salfred		} else {
1418184610Salfred			ret.proto = UMASS_PROTO_UFI | UMASS_PROTO_CBI_I;
1419184610Salfred		}
1420184610Salfred
1421184610Salfred		/*
1422184610Salfred		 * Revisions < 1.28 do not have the TEST UNIT READY command
1423184610Salfred		 * Revisions == 1.28 have a broken TEST UNIT READY
1424184610Salfred		 */
1425184610Salfred		if (uaa->info.bcdDevice <= 0x128) {
1426184610Salfred			ret.quirks |= NO_TEST_UNIT_READY;
1427184610Salfred		}
1428184610Salfred		ret.quirks |= RS_NO_CLEAR_UA | FLOPPY_SPEED;
1429184610Salfred		goto done;
1430184610Salfred	}
1431184610Salfred	/*
1432184610Salfred	 * Check the list of supported devices for a match. While looking,
1433184610Salfred	 * check for wildcarded and fully matched. First match wins.
1434184610Salfred	 */
1435184610Salfred	for (; udd->vid != VID_EOT; udd++) {
1436184610Salfred		if (((udd->vid == uaa->info.idVendor) ||
1437184610Salfred		    (udd->vid == VID_WILDCARD)) &&
1438184610Salfred		    ((udd->pid == uaa->info.idProduct) ||
1439184610Salfred		    (udd->pid == PID_WILDCARD))) {
1440184610Salfred			if (udd->rid == RID_WILDCARD) {
1441184610Salfred				ret.proto = udd->proto;
1442184610Salfred				ret.quirks = udd->quirks;
1443192052Sthompsa				if (ret.proto == UMASS_PROTO_DEFAULT)
1444192052Sthompsa					goto default_proto;
1445192052Sthompsa				else
1446192052Sthompsa					goto done;
1447184610Salfred			} else if (udd->rid == uaa->info.bcdDevice) {
1448184610Salfred				ret.proto = udd->proto;
1449184610Salfred				ret.quirks = udd->quirks;
1450192052Sthompsa				if (ret.proto == UMASS_PROTO_DEFAULT)
1451192052Sthompsa					goto default_proto;
1452192052Sthompsa				else
1453192052Sthompsa					goto done;
1454184610Salfred			}		/* else RID does not match */
1455184610Salfred		}
1456184610Salfred	}
1457184610Salfred
1458192052Sthompsadefault_proto:
1459192052Sthompsa	ret.proto = umass_get_proto(uaa->iface);
1460192052Sthompsa	if (ret.proto == 0)
1461184610Salfred		ret.error = ENXIO;
1462192052Sthompsa	else
1463192052Sthompsa		ret.error = 0;
1464184610Salfreddone:
1465184610Salfred	return (ret);
1466184610Salfred}
1467184610Salfred
1468184610Salfredstatic int
1469184610Salfredumass_probe(device_t dev)
1470184610Salfred{
1471192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
1472184610Salfred	struct umass_probe_proto temp;
1473184610Salfred
1474192499Sthompsa	if (uaa->usb_mode != USB_MODE_HOST) {
1475184610Salfred		return (ENXIO);
1476184610Salfred	}
1477184610Salfred	if (uaa->use_generic == 0) {
1478184610Salfred		/* give other drivers a try first */
1479184610Salfred		return (ENXIO);
1480184610Salfred	}
1481184610Salfred	temp = umass_probe_proto(dev, uaa);
1482184610Salfred
1483184610Salfred	return (temp.error);
1484184610Salfred}
1485184610Salfred
1486184610Salfredstatic int
1487184610Salfredumass_attach(device_t dev)
1488184610Salfred{
1489184610Salfred	struct umass_softc *sc = device_get_softc(dev);
1490192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
1491184610Salfred	struct umass_probe_proto temp = umass_probe_proto(dev, uaa);
1492192984Sthompsa	struct usb_interface_descriptor *id;
1493184610Salfred	int32_t err;
1494184610Salfred
1495184610Salfred	/*
1496184610Salfred	 * NOTE: the softc struct is bzero-ed in device_set_driver.
1497184610Salfred	 * We can safely call umass_detach without specifically
1498184610Salfred	 * initializing the struct.
1499184610Salfred	 */
1500184610Salfred
1501184610Salfred	sc->sc_dev = dev;
1502184610Salfred	sc->sc_udev = uaa->device;
1503184610Salfred	sc->sc_proto = temp.proto;
1504184610Salfred	sc->sc_quirks = temp.quirks;
1505184610Salfred	sc->sc_unit = device_get_unit(dev);
1506184610Salfred
1507184610Salfred	snprintf(sc->sc_name, sizeof(sc->sc_name),
1508184610Salfred	    "%s", device_get_nameunit(dev));
1509184610Salfred
1510194228Sthompsa	device_set_usb_desc(dev);
1511184610Salfred
1512188415Sthompsa        mtx_init(&sc->sc_mtx, device_get_nameunit(dev),
1513188415Sthompsa	    NULL, MTX_DEF | MTX_RECURSE);
1514188415Sthompsa
1515184610Salfred	/* get interface index */
1516184610Salfred
1517194228Sthompsa	id = usbd_get_interface_descriptor(uaa->iface);
1518184610Salfred	if (id == NULL) {
1519184610Salfred		device_printf(dev, "failed to get "
1520184610Salfred		    "interface number\n");
1521184610Salfred		goto detach;
1522184610Salfred	}
1523184610Salfred	sc->sc_iface_no = id->bInterfaceNumber;
1524184610Salfred
1525184610Salfred#if USB_DEBUG
1526184610Salfred	device_printf(dev, " ");
1527184610Salfred
1528184610Salfred	switch (sc->sc_proto & UMASS_PROTO_COMMAND) {
1529184610Salfred	case UMASS_PROTO_SCSI:
1530184610Salfred		printf("SCSI");
1531184610Salfred		break;
1532184610Salfred	case UMASS_PROTO_ATAPI:
1533184610Salfred		printf("8070i (ATAPI)");
1534184610Salfred		break;
1535184610Salfred	case UMASS_PROTO_UFI:
1536184610Salfred		printf("UFI");
1537184610Salfred		break;
1538184610Salfred	case UMASS_PROTO_RBC:
1539184610Salfred		printf("RBC");
1540184610Salfred		break;
1541184610Salfred	default:
1542184610Salfred		printf("(unknown 0x%02x)",
1543184610Salfred		    sc->sc_proto & UMASS_PROTO_COMMAND);
1544184610Salfred		break;
1545184610Salfred	}
1546184610Salfred
1547184610Salfred	printf(" over ");
1548184610Salfred
1549184610Salfred	switch (sc->sc_proto & UMASS_PROTO_WIRE) {
1550184610Salfred	case UMASS_PROTO_BBB:
1551184610Salfred		printf("Bulk-Only");
1552184610Salfred		break;
1553184610Salfred	case UMASS_PROTO_CBI:		/* uses Comand/Bulk pipes */
1554184610Salfred		printf("CBI");
1555184610Salfred		break;
1556184610Salfred	case UMASS_PROTO_CBI_I:	/* uses Comand/Bulk/Interrupt pipes */
1557184610Salfred		printf("CBI with CCI");
1558184610Salfred		break;
1559184610Salfred	default:
1560184610Salfred		printf("(unknown 0x%02x)",
1561184610Salfred		    sc->sc_proto & UMASS_PROTO_WIRE);
1562184610Salfred	}
1563184610Salfred
1564184610Salfred	printf("; quirks = 0x%04x\n", sc->sc_quirks);
1565184610Salfred#endif
1566184610Salfred
1567184610Salfred	if (sc->sc_quirks & ALT_IFACE_1) {
1568194228Sthompsa		err = usbd_set_alt_interface_index
1569184610Salfred		    (uaa->device, uaa->info.bIfaceIndex, 1);
1570184610Salfred
1571184610Salfred		if (err) {
1572184610Salfred			DPRINTF(sc, UDMASS_USB, "could not switch to "
1573184610Salfred			    "Alt Interface 1\n");
1574184610Salfred			goto detach;
1575184610Salfred		}
1576184610Salfred	}
1577184610Salfred	/* allocate all required USB transfers */
1578184610Salfred
1579184610Salfred	if (sc->sc_proto & UMASS_PROTO_BBB) {
1580184610Salfred
1581194228Sthompsa		err = usbd_transfer_setup(uaa->device,
1582184610Salfred		    &uaa->info.bIfaceIndex, sc->sc_xfer, umass_bbb_config,
1583188415Sthompsa		    UMASS_T_BBB_MAX, sc, &sc->sc_mtx);
1584184610Salfred
1585184610Salfred		/* skip reset first time */
1586184610Salfred		sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
1587184610Salfred
1588184610Salfred	} else if (sc->sc_proto & (UMASS_PROTO_CBI | UMASS_PROTO_CBI_I)) {
1589184610Salfred
1590194228Sthompsa		err = usbd_transfer_setup(uaa->device,
1591184610Salfred		    &uaa->info.bIfaceIndex, sc->sc_xfer, umass_cbi_config,
1592184610Salfred		    (sc->sc_proto & UMASS_PROTO_CBI_I) ?
1593184610Salfred		    UMASS_T_CBI_MAX : (UMASS_T_CBI_MAX - 2), sc,
1594188415Sthompsa		    &sc->sc_mtx);
1595184610Salfred
1596184610Salfred		/* skip reset first time */
1597184610Salfred		sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
1598184610Salfred
1599184610Salfred	} else {
1600184610Salfred		err = USB_ERR_INVAL;
1601184610Salfred	}
1602184610Salfred
1603184610Salfred	if (err) {
1604184610Salfred		device_printf(dev, "could not setup required "
1605194228Sthompsa		    "transfers, %s\n", usbd_errstr(err));
1606184610Salfred		goto detach;
1607184610Salfred	}
1608184610Salfred	sc->sc_transform =
1609184610Salfred	    (sc->sc_proto & UMASS_PROTO_SCSI) ? &umass_scsi_transform :
1610184610Salfred	    (sc->sc_proto & UMASS_PROTO_UFI) ? &umass_ufi_transform :
1611184610Salfred	    (sc->sc_proto & UMASS_PROTO_ATAPI) ? &umass_atapi_transform :
1612184610Salfred	    (sc->sc_proto & UMASS_PROTO_RBC) ? &umass_rbc_transform :
1613184610Salfred	    &umass_no_transform;
1614184610Salfred
1615184610Salfred	/* from here onwards the device can be used. */
1616184610Salfred
1617184610Salfred	if (sc->sc_quirks & SHUTTLE_INIT) {
1618184610Salfred		umass_init_shuttle(sc);
1619184610Salfred	}
1620184610Salfred	/* get the maximum LUN supported by the device */
1621184610Salfred
1622184610Salfred	if (((sc->sc_proto & UMASS_PROTO_WIRE) == UMASS_PROTO_BBB) &&
1623184610Salfred	    !(sc->sc_quirks & NO_GETMAXLUN))
1624184610Salfred		sc->sc_maxlun = umass_bbb_get_max_lun(sc);
1625184610Salfred	else
1626184610Salfred		sc->sc_maxlun = 0;
1627184610Salfred
1628184610Salfred	/* Prepare the SCSI command block */
1629184610Salfred	sc->cam_scsi_sense.opcode = REQUEST_SENSE;
1630184610Salfred	sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY;
1631184610Salfred
1632184610Salfred	/*
1633184610Salfred	 * some devices need a delay after that the configuration value is
1634184610Salfred	 * set to function properly:
1635184610Salfred	 */
1636194228Sthompsa	usb_pause_mtx(NULL, hz);
1637184610Salfred
1638184610Salfred	/* register the SIM */
1639184610Salfred	err = umass_cam_attach_sim(sc);
1640184610Salfred	if (err) {
1641184610Salfred		goto detach;
1642184610Salfred	}
1643184610Salfred	/* scan the SIM */
1644184610Salfred	umass_cam_attach(sc);
1645184610Salfred
1646184610Salfred	DPRINTF(sc, UDMASS_GEN, "Attach finished\n");
1647184610Salfred
1648184610Salfred	return (0);			/* success */
1649184610Salfred
1650184610Salfreddetach:
1651184610Salfred	umass_detach(dev);
1652184610Salfred	return (ENXIO);			/* failure */
1653184610Salfred}
1654184610Salfred
1655184610Salfredstatic int
1656184610Salfredumass_detach(device_t dev)
1657184610Salfred{
1658184610Salfred	struct umass_softc *sc = device_get_softc(dev);
1659184610Salfred
1660184610Salfred	DPRINTF(sc, UDMASS_USB, "\n");
1661184610Salfred
1662184610Salfred	/* teardown our statemachine */
1663184610Salfred
1664194228Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, UMASS_T_MAX);
1665184610Salfred
1666184610Salfred#if (__FreeBSD_version >= 700037)
1667188415Sthompsa	mtx_lock(&sc->sc_mtx);
1668184610Salfred#endif
1669184610Salfred	umass_cam_detach_sim(sc);
1670184610Salfred
1671184610Salfred#if (__FreeBSD_version >= 700037)
1672188415Sthompsa	mtx_unlock(&sc->sc_mtx);
1673184610Salfred#endif
1674199061Sthompsa	mtx_destroy(&sc->sc_mtx);
1675184610Salfred
1676184610Salfred	return (0);			/* success */
1677184610Salfred}
1678184610Salfred
1679184610Salfredstatic void
1680184610Salfredumass_init_shuttle(struct umass_softc *sc)
1681184610Salfred{
1682192984Sthompsa	struct usb_device_request req;
1683193045Sthompsa	usb_error_t err;
1684184610Salfred	uint8_t status[2] = {0, 0};
1685184610Salfred
1686184610Salfred	/*
1687184610Salfred	 * The Linux driver does this, but no one can tell us what the
1688184610Salfred	 * command does.
1689184610Salfred	 */
1690184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1691184610Salfred	req.bRequest = 1;		/* XXX unknown command */
1692184610Salfred	USETW(req.wValue, 0);
1693184610Salfred	req.wIndex[0] = sc->sc_iface_no;
1694184610Salfred	req.wIndex[1] = 0;
1695184610Salfred	USETW(req.wLength, sizeof(status));
1696194228Sthompsa	err = usbd_do_request(sc->sc_udev, NULL, &req, &status);
1697184610Salfred
1698184610Salfred	DPRINTF(sc, UDMASS_GEN, "Shuttle init returned 0x%02x%02x\n",
1699184610Salfred	    status[0], status[1]);
1700184610Salfred}
1701184610Salfred
1702184610Salfred/*
1703184610Salfred * Generic functions to handle transfers
1704184610Salfred */
1705184610Salfred
1706184610Salfredstatic void
1707184610Salfredumass_transfer_start(struct umass_softc *sc, uint8_t xfer_index)
1708184610Salfred{
1709184610Salfred	DPRINTF(sc, UDMASS_GEN, "transfer index = "
1710184610Salfred	    "%d\n", xfer_index);
1711184610Salfred
1712184610Salfred	if (sc->sc_xfer[xfer_index]) {
1713184610Salfred		sc->sc_last_xfer_index = xfer_index;
1714194228Sthompsa		usbd_transfer_start(sc->sc_xfer[xfer_index]);
1715184610Salfred	} else {
1716184610Salfred		umass_cancel_ccb(sc);
1717184610Salfred	}
1718184610Salfred}
1719184610Salfred
1720184610Salfredstatic void
1721184610Salfredumass_reset(struct umass_softc *sc)
1722184610Salfred{
1723184610Salfred	DPRINTF(sc, UDMASS_GEN, "resetting device\n");
1724184610Salfred
1725184610Salfred	/*
1726184610Salfred	 * stop the last transfer, if not already stopped:
1727184610Salfred	 */
1728194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[sc->sc_last_xfer_index]);
1729184610Salfred	umass_transfer_start(sc, 0);
1730184610Salfred}
1731184610Salfred
1732184610Salfredstatic void
1733184610Salfredumass_cancel_ccb(struct umass_softc *sc)
1734184610Salfred{
1735184610Salfred	union ccb *ccb;
1736184610Salfred
1737188415Sthompsa	mtx_assert(&sc->sc_mtx, MA_OWNED);
1738184610Salfred
1739184610Salfred	ccb = sc->sc_transfer.ccb;
1740184610Salfred	sc->sc_transfer.ccb = NULL;
1741184610Salfred	sc->sc_last_xfer_index = 0;
1742184610Salfred
1743184610Salfred	if (ccb) {
1744184610Salfred		(sc->sc_transfer.callback)
1745184610Salfred		    (sc, ccb, (sc->sc_transfer.data_len -
1746184610Salfred		    sc->sc_transfer.actlen), STATUS_WIRE_FAILED);
1747184610Salfred	}
1748184610Salfred}
1749184610Salfred
1750184610Salfredstatic void
1751194677Sthompsaumass_tr_error(struct usb_xfer *xfer, usb_error_t error)
1752184610Salfred{
1753194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1754184610Salfred
1755194677Sthompsa	if (error != USB_ERR_CANCELLED) {
1756184610Salfred
1757184610Salfred		DPRINTF(sc, UDMASS_GEN, "transfer error, %s -> "
1758194677Sthompsa		    "reset\n", usbd_errstr(error));
1759184610Salfred	}
1760184610Salfred	umass_cancel_ccb(sc);
1761184610Salfred}
1762184610Salfred
1763184610Salfred/*
1764184610Salfred * BBB protocol specific functions
1765184610Salfred */
1766184610Salfred
1767184610Salfredstatic void
1768194677Sthompsaumass_t_bbb_reset1_callback(struct usb_xfer *xfer, usb_error_t error)
1769184610Salfred{
1770194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1771192984Sthompsa	struct usb_device_request req;
1772194677Sthompsa	struct usb_page_cache *pc;
1773184610Salfred
1774184610Salfred	switch (USB_GET_STATE(xfer)) {
1775184610Salfred	case USB_ST_TRANSFERRED:
1776184610Salfred		umass_transfer_start(sc, UMASS_T_BBB_RESET2);
1777184610Salfred		return;
1778184610Salfred
1779184610Salfred	case USB_ST_SETUP:
1780184610Salfred		/*
1781184610Salfred		 * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
1782184610Salfred		 *
1783184610Salfred		 * For Reset Recovery the host shall issue in the following order:
1784184610Salfred		 * a) a Bulk-Only Mass Storage Reset
1785184610Salfred		 * b) a Clear Feature HALT to the Bulk-In endpoint
1786184610Salfred		 * c) a Clear Feature HALT to the Bulk-Out endpoint
1787184610Salfred		 *
1788184610Salfred		 * This is done in 3 steps, using 3 transfers:
1789184610Salfred		 * UMASS_T_BBB_RESET1
1790184610Salfred		 * UMASS_T_BBB_RESET2
1791184610Salfred		 * UMASS_T_BBB_RESET3
1792184610Salfred		 */
1793184610Salfred
1794184610Salfred		DPRINTF(sc, UDMASS_BBB, "BBB reset!\n");
1795184610Salfred
1796184610Salfred		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1797184610Salfred		req.bRequest = UR_BBB_RESET;	/* bulk only reset */
1798184610Salfred		USETW(req.wValue, 0);
1799184610Salfred		req.wIndex[0] = sc->sc_iface_no;
1800184610Salfred		req.wIndex[1] = 0;
1801184610Salfred		USETW(req.wLength, 0);
1802184610Salfred
1803194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1804194677Sthompsa		usbd_copy_in(pc, 0, &req, sizeof(req));
1805184610Salfred
1806194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1807194677Sthompsa		usbd_xfer_set_frames(xfer, 1);
1808194228Sthompsa		usbd_transfer_submit(xfer);
1809184610Salfred		return;
1810184610Salfred
1811184610Salfred	default:			/* Error */
1812194677Sthompsa		umass_tr_error(xfer, error);
1813184610Salfred		return;
1814184610Salfred
1815184610Salfred	}
1816184610Salfred}
1817184610Salfred
1818184610Salfredstatic void
1819194677Sthompsaumass_t_bbb_reset2_callback(struct usb_xfer *xfer, usb_error_t error)
1820184610Salfred{
1821184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_RESET3,
1822194677Sthompsa	    UMASS_T_BBB_DATA_READ, error);
1823184610Salfred}
1824184610Salfred
1825184610Salfredstatic void
1826194677Sthompsaumass_t_bbb_reset3_callback(struct usb_xfer *xfer, usb_error_t error)
1827184610Salfred{
1828184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_COMMAND,
1829194677Sthompsa	    UMASS_T_BBB_DATA_WRITE, error);
1830184610Salfred}
1831184610Salfred
1832184610Salfredstatic void
1833192984Sthompsaumass_t_bbb_data_clear_stall_callback(struct usb_xfer *xfer,
1834194677Sthompsa    uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error)
1835184610Salfred{
1836194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1837184610Salfred
1838184610Salfred	switch (USB_GET_STATE(xfer)) {
1839184610Salfred	case USB_ST_TRANSFERRED:
1840184610Salfredtr_transferred:
1841184610Salfred		umass_transfer_start(sc, next_xfer);
1842184610Salfred		return;
1843184610Salfred
1844184610Salfred	case USB_ST_SETUP:
1845194228Sthompsa		if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) {
1846184610Salfred			goto tr_transferred;
1847184610Salfred		}
1848184610Salfred		return;
1849184610Salfred
1850184610Salfred	default:			/* Error */
1851194677Sthompsa		umass_tr_error(xfer, error);
1852184610Salfred		return;
1853184610Salfred
1854184610Salfred	}
1855184610Salfred}
1856184610Salfred
1857184610Salfredstatic void
1858194677Sthompsaumass_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
1859184610Salfred{
1860194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1861184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
1862194677Sthompsa	struct usb_page_cache *pc;
1863184610Salfred	uint32_t tag;
1864184610Salfred
1865184610Salfred	switch (USB_GET_STATE(xfer)) {
1866184610Salfred	case USB_ST_TRANSFERRED:
1867184610Salfred		umass_transfer_start
1868184610Salfred		    (sc, ((sc->sc_transfer.dir == DIR_IN) ? UMASS_T_BBB_DATA_READ :
1869184610Salfred		    (sc->sc_transfer.dir == DIR_OUT) ? UMASS_T_BBB_DATA_WRITE :
1870184610Salfred		    UMASS_T_BBB_STATUS));
1871184610Salfred		return;
1872184610Salfred
1873184610Salfred	case USB_ST_SETUP:
1874184610Salfred
1875184610Salfred		sc->sc_status_try = 0;
1876184610Salfred
1877184610Salfred		if (ccb) {
1878184610Salfred
1879184610Salfred			/*
1880184610Salfred		         * the initial value is not important,
1881184610Salfred		         * as long as the values are unique:
1882184610Salfred		         */
1883184610Salfred			tag = UGETDW(sc->cbw.dCBWTag) + 1;
1884184610Salfred
1885184610Salfred			USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE);
1886184610Salfred			USETDW(sc->cbw.dCBWTag, tag);
1887184610Salfred
1888184610Salfred			/*
1889184610Salfred		         * dCBWDataTransferLength:
1890184610Salfred		         *   This field indicates the number of bytes of data that the host
1891184610Salfred		         *   intends to transfer on the IN or OUT Bulk endpoint(as indicated by
1892184610Salfred		         *   the Direction bit) during the execution of this command. If this
1893184610Salfred		         *   field is set to 0, the device will expect that no data will be
1894184610Salfred		         *   transferred IN or OUT during this command, regardless of the value
1895184610Salfred		         *   of the Direction bit defined in dCBWFlags.
1896184610Salfred		         */
1897184610Salfred			USETDW(sc->cbw.dCBWDataTransferLength, sc->sc_transfer.data_len);
1898184610Salfred
1899184610Salfred			/*
1900184610Salfred		         * dCBWFlags:
1901184610Salfred		         *   The bits of the Flags field are defined as follows:
1902184610Salfred		         *     Bits 0-6  reserved
1903184610Salfred		         *     Bit  7    Direction - this bit shall be ignored if the
1904184610Salfred		         *                           dCBWDataTransferLength field is zero.
1905184610Salfred		         *               0 = data Out from host to device
1906184610Salfred		         *               1 = data In from device to host
1907184610Salfred		         */
1908184610Salfred			sc->cbw.bCBWFlags = ((sc->sc_transfer.dir == DIR_IN) ?
1909184610Salfred			    CBWFLAGS_IN : CBWFLAGS_OUT);
1910184610Salfred			sc->cbw.bCBWLUN = sc->sc_transfer.lun;
1911184610Salfred
1912184610Salfred			if (sc->sc_transfer.cmd_len > sizeof(sc->cbw.CBWCDB)) {
1913184610Salfred				sc->sc_transfer.cmd_len = sizeof(sc->cbw.CBWCDB);
1914184610Salfred				DPRINTF(sc, UDMASS_BBB, "Truncating long command!\n");
1915184610Salfred			}
1916184610Salfred			sc->cbw.bCDBLength = sc->sc_transfer.cmd_len;
1917184610Salfred
1918184610Salfred			bcopy(sc->sc_transfer.cmd_data, sc->cbw.CBWCDB,
1919184610Salfred			    sc->sc_transfer.cmd_len);
1920184610Salfred
1921184610Salfred			bzero(sc->sc_transfer.cmd_data + sc->sc_transfer.cmd_len,
1922184610Salfred			    sizeof(sc->cbw.CBWCDB) - sc->sc_transfer.cmd_len);
1923184610Salfred
1924184610Salfred			DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw));
1925184610Salfred
1926194677Sthompsa			pc = usbd_xfer_get_frame(xfer, 0);
1927194677Sthompsa			usbd_copy_in(pc, 0, &sc->cbw, sizeof(sc->cbw));
1928194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, sizeof(sc->cbw));
1929184610Salfred
1930194228Sthompsa			usbd_transfer_submit(xfer);
1931184610Salfred		}
1932184610Salfred		return;
1933184610Salfred
1934184610Salfred	default:			/* Error */
1935194677Sthompsa		umass_tr_error(xfer, error);
1936184610Salfred		return;
1937184610Salfred
1938184610Salfred	}
1939184610Salfred}
1940184610Salfred
1941184610Salfredstatic void
1942194677Sthompsaumass_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
1943184610Salfred{
1944194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1945194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1946194677Sthompsa#ifndef UMASS_EXT_BUFFER
1947194677Sthompsa	struct usb_page_cache *pc;
1948194677Sthompsa#endif
1949194677Sthompsa	int actlen, sumlen;
1950184610Salfred
1951194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1952194677Sthompsa
1953184610Salfred	switch (USB_GET_STATE(xfer)) {
1954184610Salfred	case USB_ST_TRANSFERRED:
1955194677Sthompsa#ifndef UMASS_EXT_BUFFER
1956194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1957194677Sthompsa		usbd_copy_out(pc, 0, sc->sc_transfer.data_ptr, actlen);
1958194677Sthompsa#endif
1959194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
1960194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
1961194677Sthompsa		sc->sc_transfer.actlen += actlen;
1962184610Salfred
1963194677Sthompsa		if (actlen < sumlen) {
1964184610Salfred			/* short transfer */
1965184610Salfred			sc->sc_transfer.data_rem = 0;
1966184610Salfred		}
1967184610Salfred	case USB_ST_SETUP:
1968184610Salfred		DPRINTF(sc, UDMASS_BBB, "max_bulk=%d, data_rem=%d\n",
1969184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
1970184610Salfred
1971184610Salfred		if (sc->sc_transfer.data_rem == 0) {
1972184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_STATUS);
1973184610Salfred			return;
1974184610Salfred		}
1975184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
1976184610Salfred			max_bulk = sc->sc_transfer.data_rem;
1977184610Salfred		}
1978194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1979184610Salfred
1980194677Sthompsa#ifdef UMASS_EXT_BUFFER
1981194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1982194677Sthompsa		    max_bulk);
1983194677Sthompsa#else
1984194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, max_bulk);
1985194677Sthompsa#endif
1986194228Sthompsa		usbd_transfer_submit(xfer);
1987184610Salfred		return;
1988184610Salfred
1989184610Salfred	default:			/* Error */
1990194677Sthompsa		if (error == USB_ERR_CANCELLED) {
1991194677Sthompsa			umass_tr_error(xfer, error);
1992184610Salfred		} else {
1993184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS);
1994184610Salfred		}
1995184610Salfred		return;
1996184610Salfred
1997184610Salfred	}
1998184610Salfred}
1999184610Salfred
2000184610Salfredstatic void
2001194677Sthompsaumass_t_bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
2002184610Salfred{
2003184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS,
2004194677Sthompsa	    UMASS_T_BBB_DATA_READ, error);
2005184610Salfred}
2006184610Salfred
2007184610Salfredstatic void
2008194677Sthompsaumass_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
2009184610Salfred{
2010194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
2011194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
2012194677Sthompsa#ifndef UMASS_EXT_BUFFER
2013194677Sthompsa	struct usb_page_cache *pc;
2014194677Sthompsa#endif
2015194677Sthompsa	int actlen, sumlen;
2016184610Salfred
2017194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
2018194677Sthompsa
2019184610Salfred	switch (USB_GET_STATE(xfer)) {
2020184610Salfred	case USB_ST_TRANSFERRED:
2021194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
2022194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
2023194677Sthompsa		sc->sc_transfer.actlen += actlen;
2024184610Salfred
2025194677Sthompsa		if (actlen < sumlen) {
2026184610Salfred			/* short transfer */
2027184610Salfred			sc->sc_transfer.data_rem = 0;
2028184610Salfred		}
2029184610Salfred	case USB_ST_SETUP:
2030184610Salfred		DPRINTF(sc, UDMASS_BBB, "max_bulk=%d, data_rem=%d\n",
2031184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
2032184610Salfred
2033184610Salfred		if (sc->sc_transfer.data_rem == 0) {
2034184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_STATUS);
2035184610Salfred			return;
2036184610Salfred		}
2037184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
2038184610Salfred			max_bulk = sc->sc_transfer.data_rem;
2039184610Salfred		}
2040194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
2041184610Salfred
2042194677Sthompsa#ifdef UMASS_EXT_BUFFER
2043194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
2044194677Sthompsa		    max_bulk);
2045194677Sthompsa#else
2046194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
2047194677Sthompsa		usbd_copy_in(pc, 0, sc->sc_transfer.data_ptr, max_bulk);
2048194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, max_bulk);
2049194677Sthompsa#endif
2050184610Salfred
2051194228Sthompsa		usbd_transfer_submit(xfer);
2052184610Salfred		return;
2053184610Salfred
2054184610Salfred	default:			/* Error */
2055194677Sthompsa		if (error == USB_ERR_CANCELLED) {
2056194677Sthompsa			umass_tr_error(xfer, error);
2057184610Salfred		} else {
2058184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_DATA_WR_CS);
2059184610Salfred		}
2060184610Salfred		return;
2061184610Salfred
2062184610Salfred	}
2063184610Salfred}
2064184610Salfred
2065184610Salfredstatic void
2066194677Sthompsaumass_t_bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
2067184610Salfred{
2068184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS,
2069194677Sthompsa	    UMASS_T_BBB_DATA_WRITE, error);
2070184610Salfred}
2071184610Salfred
2072184610Salfredstatic void
2073194677Sthompsaumass_t_bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
2074184610Salfred{
2075194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
2076184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
2077194677Sthompsa	struct usb_page_cache *pc;
2078184610Salfred	uint32_t residue;
2079194677Sthompsa	int actlen;
2080184610Salfred
2081194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
2082194677Sthompsa
2083184610Salfred	switch (USB_GET_STATE(xfer)) {
2084184610Salfred	case USB_ST_TRANSFERRED:
2085184610Salfred
2086184610Salfred		/*
2087184610Salfred		 * Do a full reset if there is something wrong with the CSW:
2088184610Salfred		 */
2089184610Salfred		sc->sc_status_try = 1;
2090184610Salfred
2091184610Salfred		/* Zero missing parts of the CSW: */
2092184610Salfred
2093194677Sthompsa		if (actlen < sizeof(sc->csw)) {
2094184610Salfred			bzero(&sc->csw, sizeof(sc->csw));
2095184610Salfred		}
2096194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
2097194677Sthompsa		usbd_copy_out(pc, 0, &sc->csw, actlen);
2098184610Salfred
2099184610Salfred		DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw));
2100184610Salfred
2101184610Salfred		residue = UGETDW(sc->csw.dCSWDataResidue);
2102184610Salfred
2103189905Sthompsa		if ((!residue) || (sc->sc_quirks & IGNORE_RESIDUE)) {
2104184610Salfred			residue = (sc->sc_transfer.data_len -
2105184610Salfred			    sc->sc_transfer.actlen);
2106184610Salfred		}
2107184610Salfred		if (residue > sc->sc_transfer.data_len) {
2108184610Salfred			DPRINTF(sc, UDMASS_BBB, "truncating residue from %d "
2109184610Salfred			    "to %d bytes\n", residue, sc->sc_transfer.data_len);
2110184610Salfred			residue = sc->sc_transfer.data_len;
2111184610Salfred		}
2112184610Salfred		/* translate weird command-status signatures: */
2113184610Salfred		if (sc->sc_quirks & WRONG_CSWSIG) {
2114184610Salfred
2115184610Salfred			uint32_t temp = UGETDW(sc->csw.dCSWSignature);
2116184610Salfred
2117184610Salfred			if ((temp == CSWSIGNATURE_OLYMPUS_C1) ||
2118184610Salfred			    (temp == CSWSIGNATURE_IMAGINATION_DBX1)) {
2119184610Salfred				USETDW(sc->csw.dCSWSignature, CSWSIGNATURE);
2120184610Salfred			}
2121184610Salfred		}
2122184610Salfred		/* check CSW and handle eventual error */
2123184610Salfred		if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) {
2124184610Salfred			DPRINTF(sc, UDMASS_BBB, "bad CSW signature 0x%08x != 0x%08x\n",
2125184610Salfred			    UGETDW(sc->csw.dCSWSignature), CSWSIGNATURE);
2126184610Salfred			/*
2127184610Salfred			 * Invalid CSW: Wrong signature or wrong tag might
2128184610Salfred			 * indicate that we lost synchronization. Reset the
2129184610Salfred			 * device.
2130184610Salfred			 */
2131184610Salfred			goto tr_error;
2132184610Salfred		} else if (UGETDW(sc->csw.dCSWTag) != UGETDW(sc->cbw.dCBWTag)) {
2133184610Salfred			DPRINTF(sc, UDMASS_BBB, "Invalid CSW: tag 0x%08x should be "
2134184610Salfred			    "0x%08x\n", UGETDW(sc->csw.dCSWTag),
2135184610Salfred			    UGETDW(sc->cbw.dCBWTag));
2136184610Salfred			goto tr_error;
2137184610Salfred		} else if (sc->csw.bCSWStatus > CSWSTATUS_PHASE) {
2138184610Salfred			DPRINTF(sc, UDMASS_BBB, "Invalid CSW: status %d > %d\n",
2139184610Salfred			    sc->csw.bCSWStatus, CSWSTATUS_PHASE);
2140184610Salfred			goto tr_error;
2141184610Salfred		} else if (sc->csw.bCSWStatus == CSWSTATUS_PHASE) {
2142184610Salfred			DPRINTF(sc, UDMASS_BBB, "Phase error, residue = "
2143184610Salfred			    "%d\n", residue);
2144184610Salfred			goto tr_error;
2145184610Salfred		} else if (sc->sc_transfer.actlen > sc->sc_transfer.data_len) {
2146184610Salfred			DPRINTF(sc, UDMASS_BBB, "Buffer overrun %d > %d\n",
2147184610Salfred			    sc->sc_transfer.actlen, sc->sc_transfer.data_len);
2148184610Salfred			goto tr_error;
2149184610Salfred		} else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) {
2150184610Salfred			DPRINTF(sc, UDMASS_BBB, "Command failed, residue = "
2151184610Salfred			    "%d\n", residue);
2152184610Salfred
2153184610Salfred			sc->sc_transfer.ccb = NULL;
2154184610Salfred
2155184610Salfred			sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
2156184610Salfred
2157184610Salfred			(sc->sc_transfer.callback)
2158184610Salfred			    (sc, ccb, residue, STATUS_CMD_FAILED);
2159184610Salfred		} else {
2160184610Salfred			sc->sc_transfer.ccb = NULL;
2161184610Salfred
2162184610Salfred			sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
2163184610Salfred
2164184610Salfred			(sc->sc_transfer.callback)
2165184610Salfred			    (sc, ccb, residue, STATUS_CMD_OK);
2166184610Salfred		}
2167184610Salfred		return;
2168184610Salfred
2169184610Salfred	case USB_ST_SETUP:
2170194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
2171194228Sthompsa		usbd_transfer_submit(xfer);
2172184610Salfred		return;
2173184610Salfred
2174184610Salfred	default:
2175184610Salfredtr_error:
2176184610Salfred		DPRINTF(sc, UDMASS_BBB, "Failed to read CSW: %s, try %d\n",
2177194677Sthompsa		    usbd_errstr(error), sc->sc_status_try);
2178184610Salfred
2179194677Sthompsa		if ((error == USB_ERR_CANCELLED) ||
2180184610Salfred		    (sc->sc_status_try)) {
2181194677Sthompsa			umass_tr_error(xfer, error);
2182184610Salfred		} else {
2183184610Salfred			sc->sc_status_try = 1;
2184184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS);
2185184610Salfred		}
2186184610Salfred		return;
2187184610Salfred
2188184610Salfred	}
2189184610Salfred}
2190184610Salfred
2191184610Salfredstatic void
2192184610Salfredumass_command_start(struct umass_softc *sc, uint8_t dir,
2193184610Salfred    void *data_ptr, uint32_t data_len,
2194184610Salfred    uint32_t data_timeout, umass_callback_t *callback,
2195184610Salfred    union ccb *ccb)
2196184610Salfred{
2197184610Salfred	sc->sc_transfer.lun = ccb->ccb_h.target_lun;
2198184610Salfred
2199184610Salfred	/*
2200184610Salfred	 * NOTE: assumes that "sc->sc_transfer.cmd_data" and
2201184610Salfred	 * "sc->sc_transfer.cmd_len" has been properly
2202184610Salfred	 * initialized.
2203184610Salfred	 */
2204184610Salfred
2205184610Salfred	sc->sc_transfer.dir = data_len ? dir : DIR_NONE;
2206184610Salfred	sc->sc_transfer.data_ptr = data_ptr;
2207184610Salfred	sc->sc_transfer.data_len = data_len;
2208184610Salfred	sc->sc_transfer.data_rem = data_len;
2209184610Salfred	sc->sc_transfer.data_timeout = (data_timeout + UMASS_TIMEOUT);
2210184610Salfred
2211184610Salfred	sc->sc_transfer.actlen = 0;
2212184610Salfred	sc->sc_transfer.callback = callback;
2213184610Salfred	sc->sc_transfer.ccb = ccb;
2214184610Salfred
2215184610Salfred	if (sc->sc_xfer[sc->sc_last_xfer_index]) {
2216194228Sthompsa		usbd_transfer_start(sc->sc_xfer[sc->sc_last_xfer_index]);
2217184610Salfred	} else {
2218184610Salfred		ccb->ccb_h.status = CAM_TID_INVALID;
2219184610Salfred		xpt_done(ccb);
2220184610Salfred	}
2221184610Salfred}
2222184610Salfred
2223184610Salfredstatic uint8_t
2224184610Salfredumass_bbb_get_max_lun(struct umass_softc *sc)
2225184610Salfred{
2226192984Sthompsa	struct usb_device_request req;
2227193045Sthompsa	usb_error_t err;
2228184610Salfred	uint8_t buf = 0;
2229184610Salfred
2230184610Salfred	/* The Get Max Lun command is a class-specific request. */
2231184610Salfred	req.bmRequestType = UT_READ_CLASS_INTERFACE;
2232184610Salfred	req.bRequest = UR_BBB_GET_MAX_LUN;
2233184610Salfred	USETW(req.wValue, 0);
2234184610Salfred	req.wIndex[0] = sc->sc_iface_no;
2235184610Salfred	req.wIndex[1] = 0;
2236184610Salfred	USETW(req.wLength, 1);
2237184610Salfred
2238194228Sthompsa	err = usbd_do_request(sc->sc_udev, NULL, &req, &buf);
2239184610Salfred	if (err) {
2240184610Salfred		buf = 0;
2241184610Salfred
2242184610Salfred		/* Device doesn't support Get Max Lun request. */
2243184610Salfred		printf("%s: Get Max Lun not supported (%s)\n",
2244194228Sthompsa		    sc->sc_name, usbd_errstr(err));
2245184610Salfred	}
2246184610Salfred	return (buf);
2247184610Salfred}
2248184610Salfred
2249184610Salfred/*
2250184610Salfred * Command/Bulk/Interrupt (CBI) specific functions
2251184610Salfred */
2252184610Salfred
2253184610Salfredstatic void
2254184610Salfredumass_cbi_start_status(struct umass_softc *sc)
2255184610Salfred{
2256184610Salfred	if (sc->sc_xfer[UMASS_T_CBI_STATUS]) {
2257184610Salfred		umass_transfer_start(sc, UMASS_T_CBI_STATUS);
2258184610Salfred	} else {
2259184610Salfred		union ccb *ccb = sc->sc_transfer.ccb;
2260184610Salfred
2261184610Salfred		sc->sc_transfer.ccb = NULL;
2262184610Salfred
2263184610Salfred		sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
2264184610Salfred
2265184610Salfred		(sc->sc_transfer.callback)
2266184610Salfred		    (sc, ccb, (sc->sc_transfer.data_len -
2267184610Salfred		    sc->sc_transfer.actlen), STATUS_CMD_UNKNOWN);
2268184610Salfred	}
2269184610Salfred}
2270184610Salfred
2271184610Salfredstatic void
2272194677Sthompsaumass_t_cbi_reset1_callback(struct usb_xfer *xfer, usb_error_t error)
2273184610Salfred{
2274194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
2275192984Sthompsa	struct usb_device_request req;
2276194677Sthompsa	struct usb_page_cache *pc;
2277184610Salfred	uint8_t buf[UMASS_CBI_DIAGNOSTIC_CMDLEN];
2278184610Salfred
2279184610Salfred	uint8_t i;
2280184610Salfred
2281184610Salfred	switch (USB_GET_STATE(xfer)) {
2282184610Salfred	case USB_ST_TRANSFERRED:
2283184610Salfred		umass_transfer_start(sc, UMASS_T_CBI_RESET2);
2284184610Salfred		return;
2285184610Salfred
2286184610Salfred	case USB_ST_SETUP:
2287184610Salfred		/*
2288184610Salfred		 * Command Block Reset Protocol
2289184610Salfred		 *
2290184610Salfred		 * First send a reset request to the device. Then clear
2291184610Salfred		 * any possibly stalled bulk endpoints.
2292184610Salfred		 *
2293184610Salfred		 * This is done in 3 steps, using 3 transfers:
2294184610Salfred		 * UMASS_T_CBI_RESET1
2295184610Salfred		 * UMASS_T_CBI_RESET2
2296184610Salfred		 * UMASS_T_CBI_RESET3
2297184610Salfred		 * UMASS_T_CBI_RESET4 (only if there is an interrupt endpoint)
2298184610Salfred		 */
2299184610Salfred
2300184610Salfred		DPRINTF(sc, UDMASS_CBI, "CBI reset!\n");
2301184610Salfred
2302184610Salfred		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
2303184610Salfred		req.bRequest = UR_CBI_ADSC;
2304184610Salfred		USETW(req.wValue, 0);
2305184610Salfred		req.wIndex[0] = sc->sc_iface_no;
2306184610Salfred		req.wIndex[1] = 0;
2307184610Salfred		USETW(req.wLength, UMASS_CBI_DIAGNOSTIC_CMDLEN);
2308184610Salfred
2309184610Salfred		/*
2310184610Salfred		 * The 0x1d code is the SEND DIAGNOSTIC command. To
2311184610Salfred		 * distinguish between the two, the last 10 bytes of the CBL
2312184610Salfred		 * is filled with 0xff (section 2.2 of the CBI
2313184610Salfred		 * specification)
2314184610Salfred		 */
2315184610Salfred		buf[0] = 0x1d;		/* Command Block Reset */
2316184610Salfred		buf[1] = 0x04;
2317184610Salfred
2318184610Salfred		for (i = 2; i < UMASS_CBI_DIAGNOSTIC_CMDLEN; i++) {
2319184610Salfred			buf[i] = 0xff;
2320184610Salfred		}
2321184610Salfred
2322194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
2323194677Sthompsa		usbd_copy_in(pc, 0, &req, sizeof(req));
2324194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 1);
2325194677Sthompsa		usbd_copy_in(pc, 0, buf, sizeof(buf));
2326184610Salfred
2327194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
2328194677Sthompsa		usbd_xfer_set_frame_len(xfer, 1, sizeof(buf));
2329194677Sthompsa		usbd_xfer_set_frames(xfer, 2);
2330194228Sthompsa		usbd_transfer_submit(xfer);
2331184610Salfred		return;
2332184610Salfred
2333184610Salfred	default:			/* Error */
2334194677Sthompsa		umass_tr_error(xfer, error);
2335184610Salfred		return;
2336184610Salfred
2337184610Salfred	}
2338184610Salfred}
2339184610Salfred
2340184610Salfredstatic void
2341194677Sthompsaumass_t_cbi_reset2_callback(struct usb_xfer *xfer, usb_error_t error)
2342184610Salfred{
2343184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_RESET3,
2344194677Sthompsa	    UMASS_T_CBI_DATA_READ, error);
2345184610Salfred}
2346184610Salfred
2347184610Salfredstatic void
2348194677Sthompsaumass_t_cbi_reset3_callback(struct usb_xfer *xfer, usb_error_t error)
2349184610Salfred{
2350194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
2351184610Salfred
2352184610Salfred	umass_t_cbi_data_clear_stall_callback
2353184610Salfred	    (xfer, (sc->sc_xfer[UMASS_T_CBI_RESET4] &&
2354184610Salfred	    sc->sc_xfer[UMASS_T_CBI_STATUS]) ?
2355184610Salfred	    UMASS_T_CBI_RESET4 : UMASS_T_CBI_COMMAND,
2356194677Sthompsa	    UMASS_T_CBI_DATA_WRITE, error);
2357184610Salfred}
2358184610Salfred
2359184610Salfredstatic void
2360194677Sthompsaumass_t_cbi_reset4_callback(struct usb_xfer *xfer, usb_error_t error)
2361184610Salfred{
2362184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_COMMAND,
2363194677Sthompsa	    UMASS_T_CBI_STATUS, error);
2364184610Salfred}
2365184610Salfred
2366184610Salfredstatic void
2367192984Sthompsaumass_t_cbi_data_clear_stall_callback(struct usb_xfer *xfer,
2368194677Sthompsa    uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error)
2369184610Salfred{
2370194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
2371184610Salfred
2372184610Salfred	switch (USB_GET_STATE(xfer)) {
2373184610Salfred	case USB_ST_TRANSFERRED:
2374184610Salfredtr_transferred:
2375184610Salfred		if (next_xfer == UMASS_T_CBI_STATUS) {
2376184610Salfred			umass_cbi_start_status(sc);
2377184610Salfred		} else {
2378184610Salfred			umass_transfer_start(sc, next_xfer);
2379184610Salfred		}
2380184610Salfred		return;
2381184610Salfred
2382184610Salfred	case USB_ST_SETUP:
2383194228Sthompsa		if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) {
2384184610Salfred			goto tr_transferred;	/* should not happen */
2385184610Salfred		}
2386184610Salfred		return;
2387184610Salfred
2388184610Salfred	default:			/* Error */
2389194677Sthompsa		umass_tr_error(xfer, error);
2390184610Salfred		return;
2391184610Salfred
2392184610Salfred	}
2393184610Salfred}
2394184610Salfred
2395184610Salfredstatic void
2396194677Sthompsaumass_t_cbi_command_callback(struct usb_xfer *xfer, usb_error_t error)
2397184610Salfred{
2398194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
2399184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
2400192984Sthompsa	struct usb_device_request req;
2401194677Sthompsa	struct usb_page_cache *pc;
2402184610Salfred
2403184610Salfred	switch (USB_GET_STATE(xfer)) {
2404184610Salfred	case USB_ST_TRANSFERRED:
2405184610Salfred
2406184610Salfred		if (sc->sc_transfer.dir == DIR_NONE) {
2407184610Salfred			umass_cbi_start_status(sc);
2408184610Salfred		} else {
2409184610Salfred			umass_transfer_start
2410184610Salfred			    (sc, (sc->sc_transfer.dir == DIR_IN) ?
2411184610Salfred			    UMASS_T_CBI_DATA_READ : UMASS_T_CBI_DATA_WRITE);
2412184610Salfred		}
2413184610Salfred		return;
2414184610Salfred
2415184610Salfred	case USB_ST_SETUP:
2416184610Salfred
2417184610Salfred		if (ccb) {
2418184610Salfred
2419184610Salfred			/*
2420184610Salfred		         * do a CBI transfer with cmd_len bytes from
2421184610Salfred		         * cmd_data, possibly a data phase of data_len
2422184610Salfred		         * bytes from/to the device and finally a status
2423184610Salfred		         * read phase.
2424184610Salfred		         */
2425184610Salfred
2426184610Salfred			req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
2427184610Salfred			req.bRequest = UR_CBI_ADSC;
2428184610Salfred			USETW(req.wValue, 0);
2429184610Salfred			req.wIndex[0] = sc->sc_iface_no;
2430184610Salfred			req.wIndex[1] = 0;
2431184610Salfred			req.wLength[0] = sc->sc_transfer.cmd_len;
2432184610Salfred			req.wLength[1] = 0;
2433184610Salfred
2434194677Sthompsa			pc = usbd_xfer_get_frame(xfer, 0);
2435194677Sthompsa			usbd_copy_in(pc, 0, &req, sizeof(req));
2436194677Sthompsa			pc = usbd_xfer_get_frame(xfer, 1);
2437194677Sthompsa			usbd_copy_in(pc, 0, sc->sc_transfer.cmd_data,
2438184610Salfred			    sc->sc_transfer.cmd_len);
2439184610Salfred
2440194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
2441194677Sthompsa			usbd_xfer_set_frame_len(xfer, 1, sc->sc_transfer.cmd_len);
2442194677Sthompsa			usbd_xfer_set_frames(xfer,
2443194677Sthompsa			    sc->sc_transfer.cmd_len ? 2 : 1);
2444184610Salfred
2445184610Salfred			DIF(UDMASS_CBI,
2446184610Salfred			    umass_cbi_dump_cmd(sc,
2447184610Salfred			    sc->sc_transfer.cmd_data,
2448184610Salfred			    sc->sc_transfer.cmd_len));
2449184610Salfred
2450194228Sthompsa			usbd_transfer_submit(xfer);
2451184610Salfred		}
2452184610Salfred		return;
2453184610Salfred
2454184610Salfred	default:			/* Error */
2455194677Sthompsa		umass_tr_error(xfer, error);
2456184610Salfred		return;
2457184610Salfred
2458184610Salfred	}
2459184610Salfred}
2460184610Salfred
2461184610Salfredstatic void
2462194677Sthompsaumass_t_cbi_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
2463184610Salfred{
2464194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
2465194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
2466194677Sthompsa#ifndef UMASS_EXT_BUFFER
2467194677Sthompsa	struct usb_page_cache *pc;
2468194677Sthompsa#endif
2469194677Sthompsa	int actlen, sumlen;
2470184610Salfred
2471194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
2472194677Sthompsa
2473184610Salfred	switch (USB_GET_STATE(xfer)) {
2474184610Salfred	case USB_ST_TRANSFERRED:
2475194677Sthompsa#ifndef UMASS_EXT_BUFFER
2476194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
2477194677Sthompsa		usbd_copy_out(pc, 0, sc->sc_transfer.data_ptr, actlen);
2478194677Sthompsa#endif
2479194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
2480194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
2481194677Sthompsa		sc->sc_transfer.actlen += actlen;
2482184610Salfred
2483194677Sthompsa		if (actlen < sumlen) {
2484184610Salfred			/* short transfer */
2485184610Salfred			sc->sc_transfer.data_rem = 0;
2486184610Salfred		}
2487184610Salfred	case USB_ST_SETUP:
2488184610Salfred		DPRINTF(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n",
2489184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
2490184610Salfred
2491184610Salfred		if (sc->sc_transfer.data_rem == 0) {
2492184610Salfred			umass_cbi_start_status(sc);
2493184610Salfred			return;
2494184610Salfred		}
2495184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
2496184610Salfred			max_bulk = sc->sc_transfer.data_rem;
2497184610Salfred		}
2498194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
2499184610Salfred
2500194677Sthompsa#ifdef UMASS_EXT_BUFFER
2501194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
2502194677Sthompsa		    max_bulk);
2503194677Sthompsa#else
2504194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, max_bulk);
2505194677Sthompsa#endif
2506194228Sthompsa		usbd_transfer_submit(xfer);
2507184610Salfred		return;
2508184610Salfred
2509184610Salfred	default:			/* Error */
2510194677Sthompsa		if ((error == USB_ERR_CANCELLED) ||
2511184610Salfred		    (sc->sc_transfer.callback != &umass_cam_cb)) {
2512194677Sthompsa			umass_tr_error(xfer, error);
2513184610Salfred		} else {
2514184610Salfred			umass_transfer_start(sc, UMASS_T_CBI_DATA_RD_CS);
2515184610Salfred		}
2516184610Salfred		return;
2517184610Salfred
2518184610Salfred	}
2519184610Salfred}
2520184610Salfred
2521184610Salfredstatic void
2522194677Sthompsaumass_t_cbi_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
2523184610Salfred{
2524184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS,
2525194677Sthompsa	    UMASS_T_CBI_DATA_READ, error);
2526184610Salfred}
2527184610Salfred
2528184610Salfredstatic void
2529194677Sthompsaumass_t_cbi_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
2530184610Salfred{
2531194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
2532194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
2533194677Sthompsa#ifndef UMASS_EXT_BUFFER
2534194677Sthompsa	struct usb_page_cache *pc;
2535194677Sthompsa#endif
2536194677Sthompsa	int actlen, sumlen;
2537184610Salfred
2538194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
2539194677Sthompsa
2540184610Salfred	switch (USB_GET_STATE(xfer)) {
2541184610Salfred	case USB_ST_TRANSFERRED:
2542194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
2543194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
2544194677Sthompsa		sc->sc_transfer.actlen += actlen;
2545184610Salfred
2546194677Sthompsa		if (actlen < sumlen) {
2547184610Salfred			/* short transfer */
2548184610Salfred			sc->sc_transfer.data_rem = 0;
2549184610Salfred		}
2550184610Salfred	case USB_ST_SETUP:
2551184610Salfred		DPRINTF(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n",
2552184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
2553184610Salfred
2554184610Salfred		if (sc->sc_transfer.data_rem == 0) {
2555184610Salfred			umass_cbi_start_status(sc);
2556184610Salfred			return;
2557184610Salfred		}
2558184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
2559184610Salfred			max_bulk = sc->sc_transfer.data_rem;
2560184610Salfred		}
2561194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
2562184610Salfred
2563194677Sthompsa#ifdef UMASS_EXT_BUFFER
2564194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
2565194677Sthompsa		    max_bulk);
2566194677Sthompsa#else
2567194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
2568194677Sthompsa		usbd_copy_in(pc, 0, sc->sc_transfer.data_ptr, max_bulk);
2569194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, max_bulk);
2570194677Sthompsa#endif
2571184610Salfred
2572194228Sthompsa		usbd_transfer_submit(xfer);
2573184610Salfred		return;
2574184610Salfred
2575184610Salfred	default:			/* Error */
2576194677Sthompsa		if ((error == USB_ERR_CANCELLED) ||
2577184610Salfred		    (sc->sc_transfer.callback != &umass_cam_cb)) {
2578194677Sthompsa			umass_tr_error(xfer, error);
2579184610Salfred		} else {
2580184610Salfred			umass_transfer_start(sc, UMASS_T_CBI_DATA_WR_CS);
2581184610Salfred		}
2582184610Salfred		return;
2583184610Salfred
2584184610Salfred	}
2585184610Salfred}
2586184610Salfred
2587184610Salfredstatic void
2588194677Sthompsaumass_t_cbi_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
2589184610Salfred{
2590184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS,
2591194677Sthompsa	    UMASS_T_CBI_DATA_WRITE, error);
2592184610Salfred}
2593184610Salfred
2594184610Salfredstatic void
2595194677Sthompsaumass_t_cbi_status_callback(struct usb_xfer *xfer, usb_error_t error)
2596184610Salfred{
2597194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
2598184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
2599194677Sthompsa	struct usb_page_cache *pc;
2600184610Salfred	uint32_t residue;
2601184610Salfred	uint8_t status;
2602194677Sthompsa	int actlen;
2603184610Salfred
2604194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
2605194677Sthompsa
2606184610Salfred	switch (USB_GET_STATE(xfer)) {
2607184610Salfred	case USB_ST_TRANSFERRED:
2608184610Salfred
2609194677Sthompsa		if (actlen < sizeof(sc->sbl)) {
2610184610Salfred			goto tr_setup;
2611184610Salfred		}
2612194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
2613194677Sthompsa		usbd_copy_out(pc, 0, &sc->sbl, sizeof(sc->sbl));
2614184610Salfred
2615184610Salfred		residue = (sc->sc_transfer.data_len -
2616184610Salfred		    sc->sc_transfer.actlen);
2617184610Salfred
2618184610Salfred		/* dissect the information in the buffer */
2619184610Salfred
2620184610Salfred		if (sc->sc_proto & UMASS_PROTO_UFI) {
2621184610Salfred
2622184610Salfred			/*
2623184610Salfred			 * Section 3.4.3.1.3 specifies that the UFI command
2624184610Salfred			 * protocol returns an ASC and ASCQ in the interrupt
2625184610Salfred			 * data block.
2626184610Salfred			 */
2627184610Salfred
2628184610Salfred			DPRINTF(sc, UDMASS_CBI, "UFI CCI, ASC = 0x%02x, "
2629184610Salfred			    "ASCQ = 0x%02x\n", sc->sbl.ufi.asc,
2630184610Salfred			    sc->sbl.ufi.ascq);
2631184610Salfred
2632184610Salfred			status = (((sc->sbl.ufi.asc == 0) &&
2633184610Salfred			    (sc->sbl.ufi.ascq == 0)) ?
2634184610Salfred			    STATUS_CMD_OK : STATUS_CMD_FAILED);
2635184610Salfred
2636184610Salfred			sc->sc_transfer.ccb = NULL;
2637184610Salfred
2638184610Salfred			sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
2639184610Salfred
2640184610Salfred			(sc->sc_transfer.callback)
2641184610Salfred			    (sc, ccb, residue, status);
2642184610Salfred
2643184610Salfred			return;
2644184610Salfred
2645184610Salfred		} else {
2646184610Salfred
2647184610Salfred			/* Command Interrupt Data Block */
2648184610Salfred
2649184610Salfred			DPRINTF(sc, UDMASS_CBI, "type=0x%02x, value=0x%02x\n",
2650184610Salfred			    sc->sbl.common.type, sc->sbl.common.value);
2651184610Salfred
2652184610Salfred			if (sc->sbl.common.type == IDB_TYPE_CCI) {
2653184610Salfred
2654184610Salfred				status = (sc->sbl.common.value & IDB_VALUE_STATUS_MASK);
2655184610Salfred
2656184610Salfred				status = ((status == IDB_VALUE_PASS) ? STATUS_CMD_OK :
2657184610Salfred				    (status == IDB_VALUE_FAIL) ? STATUS_CMD_FAILED :
2658184610Salfred				    (status == IDB_VALUE_PERSISTENT) ? STATUS_CMD_FAILED :
2659184610Salfred				    STATUS_WIRE_FAILED);
2660184610Salfred
2661184610Salfred				sc->sc_transfer.ccb = NULL;
2662184610Salfred
2663184610Salfred				sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
2664184610Salfred
2665184610Salfred				(sc->sc_transfer.callback)
2666184610Salfred				    (sc, ccb, residue, status);
2667184610Salfred
2668184610Salfred				return;
2669184610Salfred			}
2670184610Salfred		}
2671184610Salfred
2672184610Salfred		/* fallthrough */
2673184610Salfred
2674184610Salfred	case USB_ST_SETUP:
2675184610Salfredtr_setup:
2676194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
2677194228Sthompsa		usbd_transfer_submit(xfer);
2678184610Salfred		return;
2679184610Salfred
2680184610Salfred	default:			/* Error */
2681184610Salfred		DPRINTF(sc, UDMASS_CBI, "Failed to read CSW: %s\n",
2682194677Sthompsa		    usbd_errstr(error));
2683194677Sthompsa		umass_tr_error(xfer, error);
2684184610Salfred		return;
2685184610Salfred
2686184610Salfred	}
2687184610Salfred}
2688184610Salfred
2689184610Salfred/*
2690184610Salfred * CAM specific functions (used by SCSI, UFI, 8070i (ATAPI))
2691184610Salfred */
2692184610Salfred
2693184610Salfredstatic int
2694184610Salfredumass_cam_attach_sim(struct umass_softc *sc)
2695184610Salfred{
2696184610Salfred	struct cam_devq *devq;		/* Per device Queue */
2697184610Salfred
2698184610Salfred	/*
2699184610Salfred	 * A HBA is attached to the CAM layer.
2700184610Salfred	 *
2701184610Salfred	 * The CAM layer will then after a while start probing for devices on
2702184610Salfred	 * the bus. The number of SIMs is limited to one.
2703184610Salfred	 */
2704184610Salfred
2705184610Salfred	devq = cam_simq_alloc(1 /* maximum openings */ );
2706184610Salfred	if (devq == NULL) {
2707184610Salfred		return (ENOMEM);
2708184610Salfred	}
2709184610Salfred	sc->sc_sim = cam_sim_alloc
2710184610Salfred	    (&umass_cam_action, &umass_cam_poll,
2711184610Salfred	    DEVNAME_SIM,
2712184610Salfred	    sc /* priv */ ,
2713184610Salfred	    sc->sc_unit /* unit number */ ,
2714184610Salfred#if (__FreeBSD_version >= 700037)
2715188415Sthompsa	    &sc->sc_mtx /* mutex */ ,
2716184610Salfred#endif
2717184610Salfred	    1 /* maximum device openings */ ,
2718184610Salfred	    0 /* maximum tagged device openings */ ,
2719184610Salfred	    devq);
2720184610Salfred
2721184610Salfred	if (sc->sc_sim == NULL) {
2722184610Salfred		cam_simq_free(devq);
2723184610Salfred		return (ENOMEM);
2724184610Salfred	}
2725184610Salfred
2726184610Salfred#if (__FreeBSD_version >= 700037)
2727188415Sthompsa	mtx_lock(&sc->sc_mtx);
2728184610Salfred#endif
2729184610Salfred
2730184610Salfred#if (__FreeBSD_version >= 700048)
2731184610Salfred	if (xpt_bus_register(sc->sc_sim, sc->sc_dev, sc->sc_unit) != CAM_SUCCESS) {
2732188415Sthompsa		mtx_unlock(&sc->sc_mtx);
2733184610Salfred		return (ENOMEM);
2734184610Salfred	}
2735184610Salfred#else
2736184610Salfred	if (xpt_bus_register(sc->sc_sim, sc->sc_unit) != CAM_SUCCESS) {
2737184610Salfred#if (__FreeBSD_version >= 700037)
2738188415Sthompsa		mtx_unlock(&sc->sc_mtx);
2739184610Salfred#endif
2740184610Salfred		return (ENOMEM);
2741184610Salfred	}
2742184610Salfred#endif
2743184610Salfred
2744184610Salfred#if (__FreeBSD_version >= 700037)
2745188415Sthompsa	mtx_unlock(&sc->sc_mtx);
2746184610Salfred#endif
2747184610Salfred	return (0);
2748184610Salfred}
2749184610Salfred
2750184610Salfredstatic void
2751184610Salfredumass_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb)
2752184610Salfred{
2753184610Salfred#if USB_DEBUG
2754184610Salfred	struct umass_softc *sc = NULL;
2755184610Salfred
2756184610Salfred	if (ccb->ccb_h.status != CAM_REQ_CMP) {
2757184610Salfred		DPRINTF(sc, UDMASS_SCSI, "%s:%d Rescan failed, 0x%04x\n",
2758184610Salfred		    periph->periph_name, periph->unit_number,
2759184610Salfred		    ccb->ccb_h.status);
2760184610Salfred	} else {
2761184610Salfred		DPRINTF(sc, UDMASS_SCSI, "%s%d: Rescan succeeded\n",
2762184610Salfred		    periph->periph_name, periph->unit_number);
2763184610Salfred	}
2764184610Salfred#endif
2765184610Salfred
2766184610Salfred	xpt_free_path(ccb->ccb_h.path);
2767184610Salfred	free(ccb, M_USBDEV);
2768184610Salfred}
2769184610Salfred
2770184610Salfredstatic void
2771184610Salfredumass_cam_rescan(struct umass_softc *sc)
2772184610Salfred{
2773184610Salfred	struct cam_path *path;
2774184610Salfred	union ccb *ccb;
2775184610Salfred
2776184610Salfred	DPRINTF(sc, UDMASS_SCSI, "scbus%d: scanning for %d:%d:%d\n",
2777184610Salfred	    cam_sim_path(sc->sc_sim),
2778184610Salfred	    cam_sim_path(sc->sc_sim),
2779184610Salfred	    sc->sc_unit, CAM_LUN_WILDCARD);
2780184610Salfred
2781184610Salfred	ccb = malloc(sizeof(*ccb), M_USBDEV, M_WAITOK | M_ZERO);
2782184610Salfred
2783184610Salfred	if (ccb == NULL) {
2784184610Salfred		return;
2785184610Salfred	}
2786184610Salfred#if (__FreeBSD_version >= 700037)
2787188415Sthompsa	mtx_lock(&sc->sc_mtx);
2788184610Salfred#endif
2789184610Salfred
2790184610Salfred	if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->sc_sim),
2791184610Salfred	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
2792184610Salfred	    != CAM_REQ_CMP) {
2793184610Salfred#if (__FreeBSD_version >= 700037)
2794188415Sthompsa		mtx_unlock(&sc->sc_mtx);
2795184610Salfred#endif
2796184610Salfred		free(ccb, M_USBDEV);
2797184610Salfred		return;
2798184610Salfred	}
2799184610Salfred	xpt_setup_ccb(&ccb->ccb_h, path, 5 /* priority (low) */ );
2800184610Salfred	ccb->ccb_h.func_code = XPT_SCAN_BUS;
2801184610Salfred	ccb->ccb_h.cbfcnp = &umass_cam_rescan_callback;
2802184610Salfred	ccb->crcn.flags = CAM_FLAG_NONE;
2803184610Salfred	xpt_action(ccb);
2804184610Salfred
2805184610Salfred#if (__FreeBSD_version >= 700037)
2806188415Sthompsa	mtx_unlock(&sc->sc_mtx);
2807184610Salfred#endif
2808184610Salfred
2809184610Salfred	/* The scan is in progress now. */
2810184610Salfred}
2811184610Salfred
2812184610Salfredstatic void
2813184610Salfredumass_cam_attach(struct umass_softc *sc)
2814184610Salfred{
2815184610Salfred#ifndef USB_DEBUG
2816184610Salfred	if (bootverbose)
2817184610Salfred#endif
2818184610Salfred		printf("%s:%d:%d:%d: Attached to scbus%d\n",
2819184610Salfred		    sc->sc_name, cam_sim_path(sc->sc_sim),
2820184610Salfred		    sc->sc_unit, CAM_LUN_WILDCARD,
2821184610Salfred		    cam_sim_path(sc->sc_sim));
2822184610Salfred
2823184610Salfred	if (!cold) {
2824184610Salfred		/*
2825184610Salfred		 * Notify CAM of the new device after a short delay. Any
2826184610Salfred		 * failure is benign, as the user can still do it by hand
2827184610Salfred		 * (camcontrol rescan <busno>). Only do this if we are not
2828184610Salfred		 * booting, because CAM does a scan after booting has
2829184610Salfred		 * completed, when interrupts have been enabled.
2830184610Salfred		 */
2831184610Salfred
2832184610Salfred		/* scan the new sim */
2833184610Salfred		umass_cam_rescan(sc);
2834184610Salfred	}
2835184610Salfred}
2836184610Salfred
2837184610Salfred/* umass_cam_detach
2838184610Salfred *	detach from the CAM layer
2839184610Salfred */
2840184610Salfred
2841184610Salfredstatic void
2842184610Salfredumass_cam_detach_sim(struct umass_softc *sc)
2843184610Salfred{
2844188415Sthompsa	if (sc->sc_sim != NULL) {
2845184610Salfred		if (xpt_bus_deregister(cam_sim_path(sc->sc_sim))) {
2846184610Salfred			/* accessing the softc is not possible after this */
2847184610Salfred			sc->sc_sim->softc = UMASS_GONE;
2848188415Sthompsa			cam_sim_free(sc->sc_sim, /* free_devq */ TRUE);
2849184610Salfred		} else {
2850184610Salfred			panic("%s: CAM layer is busy!\n",
2851184610Salfred			    sc->sc_name);
2852184610Salfred		}
2853184610Salfred		sc->sc_sim = NULL;
2854184610Salfred	}
2855184610Salfred}
2856184610Salfred
2857184610Salfred/* umass_cam_action
2858184610Salfred * 	CAM requests for action come through here
2859184610Salfred */
2860184610Salfred
2861184610Salfredstatic void
2862184610Salfredumass_cam_action(struct cam_sim *sim, union ccb *ccb)
2863184610Salfred{
2864184610Salfred	struct umass_softc *sc = (struct umass_softc *)sim->softc;
2865184610Salfred
2866198307Sthompsa	if (sc == UMASS_GONE ||
2867198307Sthompsa	    (sc != NULL && !usbd_device_attached(sc->sc_udev))) {
2868198307Sthompsa		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
2869184610Salfred		xpt_done(ccb);
2870184610Salfred		return;
2871184610Salfred	}
2872184610Salfred	if (sc) {
2873184610Salfred#if (__FreeBSD_version < 700037)
2874188415Sthompsa		mtx_lock(&sc->sc_mtx);
2875184610Salfred#endif
2876184610Salfred	}
2877184610Salfred	/*
2878184610Salfred	 * Verify, depending on the operation to perform, that we either got
2879184610Salfred	 * a valid sc, because an existing target was referenced, or
2880184610Salfred	 * otherwise the SIM is addressed.
2881184610Salfred	 *
2882184610Salfred	 * This avoids bombing out at a printf and does give the CAM layer some
2883184610Salfred	 * sensible feedback on errors.
2884184610Salfred	 */
2885184610Salfred	switch (ccb->ccb_h.func_code) {
2886184610Salfred	case XPT_SCSI_IO:
2887184610Salfred	case XPT_RESET_DEV:
2888184610Salfred	case XPT_GET_TRAN_SETTINGS:
2889184610Salfred	case XPT_SET_TRAN_SETTINGS:
2890184610Salfred	case XPT_CALC_GEOMETRY:
2891184610Salfred		/* the opcodes requiring a target. These should never occur. */
2892184610Salfred		if (sc == NULL) {
2893184610Salfred			DPRINTF(sc, UDMASS_GEN, "%s:%d:%d:%d:func_code 0x%04x: "
2894184610Salfred			    "Invalid target (target needed)\n",
2895184610Salfred			    DEVNAME_SIM, cam_sim_path(sc->sc_sim),
2896184610Salfred			    ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
2897184610Salfred			    ccb->ccb_h.func_code);
2898184610Salfred
2899184610Salfred			ccb->ccb_h.status = CAM_TID_INVALID;
2900184610Salfred			xpt_done(ccb);
2901184610Salfred			goto done;
2902184610Salfred		}
2903184610Salfred		break;
2904184610Salfred	case XPT_PATH_INQ:
2905184610Salfred	case XPT_NOOP:
2906184610Salfred		/*
2907184610Salfred		 * The opcodes sometimes aimed at a target (sc is valid),
2908184610Salfred		 * sometimes aimed at the SIM (sc is invalid and target is
2909184610Salfred		 * CAM_TARGET_WILDCARD)
2910184610Salfred		 */
2911184610Salfred		if ((sc == NULL) &&
2912184610Salfred		    (ccb->ccb_h.target_id != CAM_TARGET_WILDCARD)) {
2913184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%s:%d:%d:%d:func_code 0x%04x: "
2914184610Salfred			    "Invalid target (no wildcard)\n",
2915184610Salfred			    DEVNAME_SIM, cam_sim_path(sc->sc_sim),
2916184610Salfred			    ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
2917184610Salfred			    ccb->ccb_h.func_code);
2918184610Salfred
2919184610Salfred			ccb->ccb_h.status = CAM_TID_INVALID;
2920184610Salfred			xpt_done(ccb);
2921184610Salfred			goto done;
2922184610Salfred		}
2923184610Salfred		break;
2924184610Salfred	default:
2925184610Salfred		/* XXX Hm, we should check the input parameters */
2926184610Salfred		break;
2927184610Salfred	}
2928184610Salfred
2929184610Salfred	/* Perform the requested action */
2930184610Salfred	switch (ccb->ccb_h.func_code) {
2931184610Salfred	case XPT_SCSI_IO:
2932184610Salfred		{
2933184610Salfred			uint8_t *cmd;
2934184610Salfred			uint8_t dir;
2935184610Salfred
2936184610Salfred			if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) {
2937184610Salfred				cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr);
2938184610Salfred			} else {
2939184610Salfred				cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes);
2940184610Salfred			}
2941184610Salfred
2942184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SCSI_IO: "
2943184610Salfred			    "cmd: 0x%02x, flags: 0x%02x, "
2944184610Salfred			    "%db cmd/%db data/%db sense\n",
2945184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2946184610Salfred			    ccb->ccb_h.target_lun, cmd[0],
2947184610Salfred			    ccb->ccb_h.flags & CAM_DIR_MASK, ccb->csio.cdb_len,
2948184610Salfred			    ccb->csio.dxfer_len, ccb->csio.sense_len);
2949184610Salfred
2950184610Salfred			if (sc->sc_transfer.ccb) {
2951184610Salfred				DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SCSI_IO: "
2952184610Salfred				    "I/O in progress, deferring\n",
2953184610Salfred				    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2954184610Salfred				    ccb->ccb_h.target_lun);
2955184610Salfred				ccb->ccb_h.status = CAM_SCSI_BUSY;
2956184610Salfred				xpt_done(ccb);
2957184610Salfred				goto done;
2958184610Salfred			}
2959184610Salfred			switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
2960184610Salfred			case CAM_DIR_IN:
2961184610Salfred				dir = DIR_IN;
2962184610Salfred				break;
2963184610Salfred			case CAM_DIR_OUT:
2964184610Salfred				dir = DIR_OUT;
2965184610Salfred				DIF(UDMASS_SCSI,
2966184610Salfred				    umass_dump_buffer(sc, ccb->csio.data_ptr,
2967184610Salfred				    ccb->csio.dxfer_len, 48));
2968184610Salfred				break;
2969184610Salfred			default:
2970184610Salfred				dir = DIR_NONE;
2971184610Salfred			}
2972184610Salfred
2973184610Salfred			ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED;
2974184610Salfred
2975184610Salfred			/*
2976184610Salfred			 * sc->sc_transform will convert the command to the
2977184610Salfred			 * command format needed by the specific command set
2978184610Salfred			 * and return the converted command in
2979184610Salfred			 * "sc->sc_transfer.cmd_data"
2980184610Salfred			 */
2981184610Salfred			if (umass_std_transform(sc, ccb, cmd, ccb->csio.cdb_len)) {
2982184610Salfred
2983184610Salfred				if (sc->sc_transfer.cmd_data[0] == INQUIRY) {
2984184610Salfred
2985184610Salfred					/*
2986196826Strasz					 * Umass devices don't generally report their serial numbers
2987196826Strasz					 * in the usual SCSI way.  Emulate it here.
2988196826Strasz					 */
2989196826Strasz					if ((sc->sc_transfer.cmd_data[1] & SI_EVPD) &&
2990196826Strasz					    sc->sc_transfer.cmd_data[2] == SVPD_UNIT_SERIAL_NUMBER &&
2991196826Strasz					    sc->sc_udev != NULL &&
2992196826Strasz					    sc->sc_udev->serial != NULL &&
2993196826Strasz					    sc->sc_udev->serial[0] != '\0') {
2994196826Strasz						struct scsi_vpd_unit_serial_number *vpd_serial;
2995196826Strasz
2996196826Strasz						vpd_serial = (struct scsi_vpd_unit_serial_number *)ccb->csio.data_ptr;
2997196826Strasz						vpd_serial->length = strlen(sc->sc_udev->serial);
2998196826Strasz						if (vpd_serial->length > sizeof(vpd_serial->serial_num))
2999196826Strasz							vpd_serial->length = sizeof(vpd_serial->serial_num);
3000196826Strasz						memcpy(vpd_serial->serial_num, sc->sc_udev->serial, vpd_serial->length);
3001196826Strasz						ccb->csio.scsi_status = SCSI_STATUS_OK;
3002196826Strasz						ccb->ccb_h.status = CAM_REQ_CMP;
3003196826Strasz						xpt_done(ccb);
3004196826Strasz						goto done;
3005196826Strasz					}
3006196826Strasz
3007196826Strasz					/*
3008184610Salfred					 * Handle EVPD inquiry for broken devices first
3009184610Salfred					 * NO_INQUIRY also implies NO_INQUIRY_EVPD
3010184610Salfred					 */
3011184610Salfred					if ((sc->sc_quirks & (NO_INQUIRY_EVPD | NO_INQUIRY)) &&
3012184610Salfred					    (sc->sc_transfer.cmd_data[1] & SI_EVPD)) {
3013184610Salfred						struct scsi_sense_data *sense;
3014184610Salfred
3015184610Salfred						sense = &ccb->csio.sense_data;
3016184610Salfred						bzero(sense, sizeof(*sense));
3017184610Salfred						sense->error_code = SSD_CURRENT_ERROR;
3018184610Salfred						sense->flags = SSD_KEY_ILLEGAL_REQUEST;
3019184610Salfred						sense->add_sense_code = 0x24;
3020184610Salfred						sense->extra_len = 10;
3021184610Salfred						ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
3022184610Salfred						ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
3023184610Salfred						    CAM_AUTOSNS_VALID;
3024184610Salfred						xpt_done(ccb);
3025184610Salfred						goto done;
3026184610Salfred					}
3027184610Salfred					/*
3028184610Salfred					 * Return fake inquiry data for
3029184610Salfred					 * broken devices
3030184610Salfred					 */
3031184610Salfred					if (sc->sc_quirks & NO_INQUIRY) {
3032184610Salfred						memcpy(ccb->csio.data_ptr, &fake_inq_data,
3033184610Salfred						    sizeof(fake_inq_data));
3034184610Salfred						ccb->csio.scsi_status = SCSI_STATUS_OK;
3035184610Salfred						ccb->ccb_h.status = CAM_REQ_CMP;
3036184610Salfred						xpt_done(ccb);
3037184610Salfred						goto done;
3038184610Salfred					}
3039184610Salfred					if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
3040184610Salfred						ccb->csio.dxfer_len = SHORT_INQUIRY_LENGTH;
3041184610Salfred					}
3042184610Salfred				} else if (sc->sc_transfer.cmd_data[0] == SYNCHRONIZE_CACHE) {
3043184610Salfred					if (sc->sc_quirks & NO_SYNCHRONIZE_CACHE) {
3044184610Salfred						ccb->csio.scsi_status = SCSI_STATUS_OK;
3045184610Salfred						ccb->ccb_h.status = CAM_REQ_CMP;
3046184610Salfred						xpt_done(ccb);
3047184610Salfred						goto done;
3048184610Salfred					}
3049184610Salfred				}
3050184610Salfred				umass_command_start(sc, dir, ccb->csio.data_ptr,
3051184610Salfred				    ccb->csio.dxfer_len,
3052184610Salfred				    ccb->ccb_h.timeout,
3053184610Salfred				    &umass_cam_cb, ccb);
3054184610Salfred			}
3055184610Salfred			break;
3056184610Salfred		}
3057184610Salfred	case XPT_PATH_INQ:
3058184610Salfred		{
3059184610Salfred			struct ccb_pathinq *cpi = &ccb->cpi;
3060184610Salfred
3061184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_PATH_INQ:.\n",
3062184610Salfred			    sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id,
3063184610Salfred			    ccb->ccb_h.target_lun);
3064184610Salfred
3065184610Salfred			/* host specific information */
3066184610Salfred			cpi->version_num = 1;
3067184610Salfred			cpi->hba_inquiry = 0;
3068184610Salfred			cpi->target_sprt = 0;
3069184610Salfred			cpi->hba_misc = PIM_NO_6_BYTE;
3070184610Salfred			cpi->hba_eng_cnt = 0;
3071184610Salfred			cpi->max_target = UMASS_SCSIID_MAX;	/* one target */
3072184610Salfred			cpi->initiator_id = UMASS_SCSIID_HOST;
3073184610Salfred			strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
3074184610Salfred			strlcpy(cpi->hba_vid, "USB SCSI", HBA_IDLEN);
3075184610Salfred			strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
3076184610Salfred			cpi->unit_number = cam_sim_unit(sim);
3077184610Salfred			cpi->bus_id = sc->sc_unit;
3078184610Salfred#if (__FreeBSD_version >= 700025)
3079184610Salfred			cpi->protocol = PROTO_SCSI;
3080184610Salfred			cpi->protocol_version = SCSI_REV_2;
3081184610Salfred			cpi->transport = XPORT_USB;
3082184610Salfred			cpi->transport_version = 0;
3083184610Salfred#endif
3084184610Salfred			if (sc == NULL) {
3085184610Salfred				cpi->base_transfer_speed = 0;
3086184610Salfred				cpi->max_lun = 0;
3087184610Salfred			} else {
3088184610Salfred				if (sc->sc_quirks & FLOPPY_SPEED) {
3089184610Salfred					cpi->base_transfer_speed =
3090184610Salfred					    UMASS_FLOPPY_TRANSFER_SPEED;
3091194228Sthompsa				} else if (usbd_get_speed(sc->sc_udev) ==
3092184610Salfred				    USB_SPEED_HIGH) {
3093184610Salfred					cpi->base_transfer_speed =
3094184610Salfred					    UMASS_HIGH_TRANSFER_SPEED;
3095184610Salfred				} else {
3096184610Salfred					cpi->base_transfer_speed =
3097184610Salfred					    UMASS_FULL_TRANSFER_SPEED;
3098184610Salfred				}
3099184610Salfred				cpi->max_lun = sc->sc_maxlun;
3100184610Salfred			}
3101184610Salfred
3102184610Salfred			cpi->ccb_h.status = CAM_REQ_CMP;
3103184610Salfred			xpt_done(ccb);
3104184610Salfred			break;
3105184610Salfred		}
3106184610Salfred	case XPT_RESET_DEV:
3107184610Salfred		{
3108184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_RESET_DEV:.\n",
3109184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
3110184610Salfred			    ccb->ccb_h.target_lun);
3111184610Salfred
3112184610Salfred			umass_reset(sc);
3113184610Salfred
3114184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
3115184610Salfred			xpt_done(ccb);
3116184610Salfred			break;
3117184610Salfred		}
3118184610Salfred	case XPT_GET_TRAN_SETTINGS:
3119184610Salfred		{
3120184610Salfred			struct ccb_trans_settings *cts = &ccb->cts;
3121184610Salfred
3122184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_GET_TRAN_SETTINGS:.\n",
3123184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
3124184610Salfred			    ccb->ccb_h.target_lun);
3125184610Salfred
3126184610Salfred#if (__FreeBSD_version >= 700025)
3127184610Salfred			cts->protocol = PROTO_SCSI;
3128184610Salfred			cts->protocol_version = SCSI_REV_2;
3129184610Salfred			cts->transport = XPORT_USB;
3130184610Salfred			cts->transport_version = 0;
3131184610Salfred			cts->xport_specific.valid = 0;
3132184610Salfred#else
3133184610Salfred			cts->valid = 0;
3134184610Salfred			cts->flags = 0;	/* no disconnection, tagging */
3135184610Salfred#endif
3136184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
3137184610Salfred			xpt_done(ccb);
3138184610Salfred			break;
3139184610Salfred		}
3140184610Salfred	case XPT_SET_TRAN_SETTINGS:
3141184610Salfred		{
3142184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SET_TRAN_SETTINGS:.\n",
3143184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
3144184610Salfred			    ccb->ccb_h.target_lun);
3145184610Salfred
3146184610Salfred			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
3147184610Salfred			xpt_done(ccb);
3148184610Salfred			break;
3149184610Salfred		}
3150184610Salfred	case XPT_CALC_GEOMETRY:
3151184610Salfred		{
3152184610Salfred			cam_calc_geometry(&ccb->ccg, /* extended */ 1);
3153184610Salfred			xpt_done(ccb);
3154184610Salfred			break;
3155184610Salfred		}
3156184610Salfred	case XPT_NOOP:
3157184610Salfred		{
3158184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_NOOP:.\n",
3159184610Salfred			    sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id,
3160184610Salfred			    ccb->ccb_h.target_lun);
3161184610Salfred
3162184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
3163184610Salfred			xpt_done(ccb);
3164184610Salfred			break;
3165184610Salfred		}
3166184610Salfred	default:
3167184610Salfred		DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:func_code 0x%04x: "
3168184610Salfred		    "Not implemented\n",
3169184610Salfred		    sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id,
3170184610Salfred		    ccb->ccb_h.target_lun, ccb->ccb_h.func_code);
3171184610Salfred
3172184610Salfred		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
3173184610Salfred		xpt_done(ccb);
3174184610Salfred		break;
3175184610Salfred	}
3176184610Salfred
3177184610Salfreddone:
3178184610Salfred#if (__FreeBSD_version < 700037)
3179184610Salfred	if (sc) {
3180188415Sthompsa		mtx_unlock(&sc->sc_mtx);
3181184610Salfred	}
3182184610Salfred#endif
3183184610Salfred	return;
3184184610Salfred}
3185184610Salfred
3186184610Salfredstatic void
3187184610Salfredumass_cam_poll(struct cam_sim *sim)
3188184610Salfred{
3189184610Salfred	struct umass_softc *sc = (struct umass_softc *)sim->softc;
3190184610Salfred
3191184610Salfred	if (sc == UMASS_GONE)
3192184610Salfred		return;
3193184610Salfred
3194184610Salfred	DPRINTF(sc, UDMASS_SCSI, "CAM poll\n");
3195184610Salfred
3196194677Sthompsa	usbd_transfer_poll(sc->sc_xfer, UMASS_T_MAX);
3197184610Salfred}
3198184610Salfred
3199184610Salfred
3200184610Salfred/* umass_cam_cb
3201184610Salfred *	finalise a completed CAM command
3202184610Salfred */
3203184610Salfred
3204184610Salfredstatic void
3205184610Salfredumass_cam_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
3206184610Salfred    uint8_t status)
3207184610Salfred{
3208184610Salfred	ccb->csio.resid = residue;
3209184610Salfred
3210184610Salfred	switch (status) {
3211184610Salfred	case STATUS_CMD_OK:
3212184610Salfred		ccb->ccb_h.status = CAM_REQ_CMP;
3213184610Salfred		if ((sc->sc_quirks & READ_CAPACITY_OFFBY1) &&
3214184610Salfred		    (ccb->ccb_h.func_code == XPT_SCSI_IO) &&
3215184610Salfred		    (ccb->csio.cdb_io.cdb_bytes[0] == READ_CAPACITY)) {
3216184610Salfred			struct scsi_read_capacity_data *rcap;
3217184610Salfred			uint32_t maxsector;
3218184610Salfred
3219184610Salfred			rcap = (void *)(ccb->csio.data_ptr);
3220184610Salfred			maxsector = scsi_4btoul(rcap->addr) - 1;
3221184610Salfred			scsi_ulto4b(maxsector, rcap->addr);
3222184610Salfred		}
3223196826Strasz		/*
3224196826Strasz		 * We have to add SVPD_UNIT_SERIAL_NUMBER to the list
3225196826Strasz		 * of pages supported by the device - otherwise, CAM
3226196826Strasz		 * will never ask us for the serial number if the
3227196826Strasz		 * device cannot handle that by itself.
3228196826Strasz		 */
3229196826Strasz		if (ccb->ccb_h.func_code == XPT_SCSI_IO &&
3230196826Strasz		    sc->sc_transfer.cmd_data[0] == INQUIRY &&
3231196826Strasz		    (sc->sc_transfer.cmd_data[1] & SI_EVPD) &&
3232196826Strasz		    sc->sc_transfer.cmd_data[2] == SVPD_SUPPORTED_PAGE_LIST &&
3233196826Strasz		    sc->sc_udev != NULL &&
3234196826Strasz		    sc->sc_udev->serial != NULL &&
3235196826Strasz		    sc->sc_udev->serial[0] != '\0') {
3236196826Strasz			struct ccb_scsiio *csio;
3237196826Strasz			struct scsi_vpd_supported_page_list *page_list;
3238196826Strasz
3239196826Strasz			csio = &ccb->csio;
3240196826Strasz			page_list = (struct scsi_vpd_supported_page_list *)csio->data_ptr;
3241196826Strasz			if (page_list->length + 1 < SVPD_SUPPORTED_PAGES_SIZE) {
3242196826Strasz				page_list->list[page_list->length] = SVPD_UNIT_SERIAL_NUMBER;
3243196826Strasz				page_list->length++;
3244196826Strasz			}
3245196826Strasz		}
3246184610Salfred		xpt_done(ccb);
3247184610Salfred		break;
3248184610Salfred
3249184610Salfred	case STATUS_CMD_UNKNOWN:
3250184610Salfred	case STATUS_CMD_FAILED:
3251184610Salfred
3252184610Salfred		/* fetch sense data */
3253184610Salfred
3254184610Salfred		/* the rest of the command was filled in at attach */
3255184610Salfred		sc->cam_scsi_sense.length = ccb->csio.sense_len;
3256184610Salfred
3257184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Fetching %d bytes of "
3258184610Salfred		    "sense data\n", ccb->csio.sense_len);
3259184610Salfred
3260184610Salfred		if (umass_std_transform(sc, ccb, &sc->cam_scsi_sense.opcode,
3261184610Salfred		    sizeof(sc->cam_scsi_sense))) {
3262184610Salfred
3263184610Salfred			if ((sc->sc_quirks & FORCE_SHORT_INQUIRY) &&
3264184610Salfred			    (sc->sc_transfer.cmd_data[0] == INQUIRY)) {
3265184610Salfred				ccb->csio.sense_len = SHORT_INQUIRY_LENGTH;
3266184610Salfred			}
3267184610Salfred			umass_command_start(sc, DIR_IN, &ccb->csio.sense_data.error_code,
3268184610Salfred			    ccb->csio.sense_len, ccb->ccb_h.timeout,
3269184610Salfred			    &umass_cam_sense_cb, ccb);
3270184610Salfred		}
3271184610Salfred		break;
3272184610Salfred
3273184610Salfred	default:
3274184610Salfred		/*
3275184610Salfred		 * the wire protocol failed and will have recovered
3276184610Salfred		 * (hopefully).  We return an error to CAM and let CAM retry
3277184610Salfred		 * the command if necessary.
3278184610Salfred		 */
3279184610Salfred		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
3280184610Salfred		xpt_done(ccb);
3281184610Salfred		break;
3282184610Salfred	}
3283184610Salfred}
3284184610Salfred
3285184610Salfred/*
3286184610Salfred * Finalise a completed autosense operation
3287184610Salfred */
3288184610Salfredstatic void
3289184610Salfredumass_cam_sense_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
3290184610Salfred    uint8_t status)
3291184610Salfred{
3292184610Salfred	uint8_t *cmd;
3293184610Salfred	uint8_t key;
3294184610Salfred
3295184610Salfred	switch (status) {
3296184610Salfred	case STATUS_CMD_OK:
3297184610Salfred	case STATUS_CMD_UNKNOWN:
3298184610Salfred	case STATUS_CMD_FAILED:
3299184610Salfred
3300184610Salfred		if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) {
3301184610Salfred			cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr);
3302184610Salfred		} else {
3303184610Salfred			cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes);
3304184610Salfred		}
3305184610Salfred
3306184610Salfred		key = (ccb->csio.sense_data.flags & SSD_KEY);
3307184610Salfred
3308184610Salfred		/*
3309184610Salfred		 * Getting sense data always succeeds (apart from wire
3310184610Salfred		 * failures):
3311184610Salfred		 */
3312184610Salfred		if ((sc->sc_quirks & RS_NO_CLEAR_UA) &&
3313184610Salfred		    (cmd[0] == INQUIRY) &&
3314184610Salfred		    (key == SSD_KEY_UNIT_ATTENTION)) {
3315184610Salfred			/*
3316184610Salfred			 * Ignore unit attention errors in the case where
3317184610Salfred			 * the Unit Attention state is not cleared on
3318184610Salfred			 * REQUEST SENSE. They will appear again at the next
3319184610Salfred			 * command.
3320184610Salfred			 */
3321184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
3322184610Salfred		} else if (key == SSD_KEY_NO_SENSE) {
3323184610Salfred			/*
3324184610Salfred			 * No problem after all (in the case of CBI without
3325184610Salfred			 * CCI)
3326184610Salfred			 */
3327184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
3328184610Salfred		} else if ((sc->sc_quirks & RS_NO_CLEAR_UA) &&
3329184610Salfred			    (cmd[0] == READ_CAPACITY) &&
3330184610Salfred		    (key == SSD_KEY_UNIT_ATTENTION)) {
3331184610Salfred			/*
3332184610Salfred			 * Some devices do not clear the unit attention error
3333184610Salfred			 * on request sense. We insert a test unit ready
3334184610Salfred			 * command to make sure we clear the unit attention
3335184610Salfred			 * condition, then allow the retry to proceed as
3336184610Salfred			 * usual.
3337184610Salfred			 */
3338184610Salfred
3339184610Salfred			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
3340184610Salfred			    | CAM_AUTOSNS_VALID;
3341184610Salfred			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
3342184610Salfred
3343184610Salfred#if 0
3344184610Salfred			DELAY(300000);
3345184610Salfred#endif
3346184610Salfred			DPRINTF(sc, UDMASS_SCSI, "Doing a sneaky"
3347184610Salfred			    "TEST_UNIT_READY\n");
3348184610Salfred
3349184610Salfred			/* the rest of the command was filled in at attach */
3350184610Salfred
3351184610Salfred			if (umass_std_transform(sc, ccb,
3352184610Salfred			    &sc->cam_scsi_test_unit_ready.opcode,
3353184610Salfred			    sizeof(sc->cam_scsi_test_unit_ready))) {
3354184610Salfred				umass_command_start(sc, DIR_NONE, NULL, 0,
3355184610Salfred				    ccb->ccb_h.timeout,
3356184610Salfred				    &umass_cam_quirk_cb, ccb);
3357184610Salfred			}
3358184610Salfred			break;
3359184610Salfred		} else {
3360184610Salfred			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
3361184610Salfred			    | CAM_AUTOSNS_VALID;
3362184610Salfred			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
3363184610Salfred		}
3364184610Salfred		xpt_done(ccb);
3365184610Salfred		break;
3366184610Salfred
3367184610Salfred	default:
3368184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Autosense failed, "
3369184610Salfred		    "status %d\n", status);
3370184610Salfred		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
3371184610Salfred		xpt_done(ccb);
3372184610Salfred	}
3373184610Salfred}
3374184610Salfred
3375184610Salfred/*
3376184610Salfred * This completion code just handles the fact that we sent a test-unit-ready
3377184610Salfred * after having previously failed a READ CAPACITY with CHECK_COND.  Even
3378184610Salfred * though this command succeeded, we have to tell CAM to retry.
3379184610Salfred */
3380184610Salfredstatic void
3381184610Salfredumass_cam_quirk_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
3382184610Salfred    uint8_t status)
3383184610Salfred{
3384184610Salfred	DPRINTF(sc, UDMASS_SCSI, "Test unit ready "
3385184610Salfred	    "returned status %d\n", status);
3386184610Salfred
3387184610Salfred	ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
3388184610Salfred	    | CAM_AUTOSNS_VALID;
3389184610Salfred	ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
3390184610Salfred	xpt_done(ccb);
3391184610Salfred}
3392184610Salfred
3393184610Salfred/*
3394184610Salfred * SCSI specific functions
3395184610Salfred */
3396184610Salfred
3397184610Salfredstatic uint8_t
3398184610Salfredumass_scsi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
3399184610Salfred    uint8_t cmd_len)
3400184610Salfred{
3401184610Salfred	if ((cmd_len == 0) ||
3402184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
3403184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
3404184610Salfred		    "length: %d bytes\n", cmd_len);
3405184610Salfred		return (0);		/* failure */
3406184610Salfred	}
3407184610Salfred	sc->sc_transfer.cmd_len = cmd_len;
3408184610Salfred
3409184610Salfred	switch (cmd_ptr[0]) {
3410184610Salfred	case TEST_UNIT_READY:
3411184610Salfred		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
3412184610Salfred			DPRINTF(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY "
3413184610Salfred			    "to START_UNIT\n");
3414184610Salfred			bzero(sc->sc_transfer.cmd_data, cmd_len);
3415184610Salfred			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
3416184610Salfred			sc->sc_transfer.cmd_data[4] = SSS_START;
3417184610Salfred			return (1);
3418184610Salfred		}
3419184610Salfred		break;
3420184610Salfred
3421184610Salfred	case INQUIRY:
3422184610Salfred		/*
3423184610Salfred		 * some drives wedge when asked for full inquiry
3424184610Salfred		 * information.
3425184610Salfred		 */
3426184610Salfred		if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
3427184610Salfred			bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
3428184610Salfred			sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
3429184610Salfred			return (1);
3430184610Salfred		}
3431184610Salfred		break;
3432184610Salfred	}
3433184610Salfred
3434184610Salfred	bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
3435184610Salfred	return (1);
3436184610Salfred}
3437184610Salfred
3438184610Salfredstatic uint8_t
3439184610Salfredumass_rbc_transform(struct umass_softc *sc, uint8_t *cmd_ptr, uint8_t cmd_len)
3440184610Salfred{
3441184610Salfred	if ((cmd_len == 0) ||
3442184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
3443184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
3444184610Salfred		    "length: %d bytes\n", cmd_len);
3445184610Salfred		return (0);		/* failure */
3446184610Salfred	}
3447184610Salfred	switch (cmd_ptr[0]) {
3448184610Salfred		/* these commands are defined in RBC: */
3449184610Salfred	case READ_10:
3450184610Salfred	case READ_CAPACITY:
3451184610Salfred	case START_STOP_UNIT:
3452184610Salfred	case SYNCHRONIZE_CACHE:
3453184610Salfred	case WRITE_10:
3454184610Salfred	case 0x2f:			/* VERIFY_10 is absent from
3455184610Salfred					 * scsi_all.h??? */
3456184610Salfred	case INQUIRY:
3457184610Salfred	case MODE_SELECT_10:
3458184610Salfred	case MODE_SENSE_10:
3459184610Salfred	case TEST_UNIT_READY:
3460184610Salfred	case WRITE_BUFFER:
3461184610Salfred		/*
3462184610Salfred		 * The following commands are not listed in my copy of the
3463184610Salfred		 * RBC specs. CAM however seems to want those, and at least
3464184610Salfred		 * the Sony DSC device appears to support those as well
3465184610Salfred		 */
3466184610Salfred	case REQUEST_SENSE:
3467184610Salfred	case PREVENT_ALLOW:
3468184610Salfred
3469184610Salfred		bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
3470184610Salfred
3471184610Salfred		if ((sc->sc_quirks & RBC_PAD_TO_12) && (cmd_len < 12)) {
3472184610Salfred			bzero(sc->sc_transfer.cmd_data + cmd_len, 12 - cmd_len);
3473184610Salfred			cmd_len = 12;
3474184610Salfred		}
3475184610Salfred		sc->sc_transfer.cmd_len = cmd_len;
3476184610Salfred		return (1);		/* sucess */
3477184610Salfred
3478184610Salfred		/* All other commands are not legal in RBC */
3479184610Salfred	default:
3480184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Unsupported RBC "
3481184610Salfred		    "command 0x%02x\n", cmd_ptr[0]);
3482184610Salfred		return (0);		/* failure */
3483184610Salfred	}
3484184610Salfred}
3485184610Salfred
3486184610Salfredstatic uint8_t
3487184610Salfredumass_ufi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
3488184610Salfred    uint8_t cmd_len)
3489184610Salfred{
3490184610Salfred	if ((cmd_len == 0) ||
3491184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
3492184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
3493184610Salfred		    "length: %d bytes\n", cmd_len);
3494184610Salfred		return (0);		/* failure */
3495184610Salfred	}
3496184610Salfred	/* An UFI command is always 12 bytes in length */
3497184610Salfred	sc->sc_transfer.cmd_len = UFI_COMMAND_LENGTH;
3498184610Salfred
3499184610Salfred	/* Zero the command data */
3500184610Salfred	bzero(sc->sc_transfer.cmd_data, UFI_COMMAND_LENGTH);
3501184610Salfred
3502184610Salfred	switch (cmd_ptr[0]) {
3503184610Salfred		/*
3504184610Salfred		 * Commands of which the format has been verified. They
3505184610Salfred		 * should work. Copy the command into the (zeroed out)
3506184610Salfred		 * destination buffer.
3507184610Salfred		 */
3508184610Salfred	case TEST_UNIT_READY:
3509184610Salfred		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
3510184610Salfred			/*
3511184610Salfred			 * Some devices do not support this command. Start
3512184610Salfred			 * Stop Unit should give the same results
3513184610Salfred			 */
3514184610Salfred			DPRINTF(sc, UDMASS_UFI, "Converted TEST_UNIT_READY "
3515184610Salfred			    "to START_UNIT\n");
3516184610Salfred
3517184610Salfred			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
3518184610Salfred			sc->sc_transfer.cmd_data[4] = SSS_START;
3519184610Salfred			return (1);
3520184610Salfred		}
3521184610Salfred		break;
3522184610Salfred
3523184610Salfred	case REZERO_UNIT:
3524184610Salfred	case REQUEST_SENSE:
3525184610Salfred	case FORMAT_UNIT:
3526184610Salfred	case INQUIRY:
3527184610Salfred	case START_STOP_UNIT:
3528184610Salfred	case SEND_DIAGNOSTIC:
3529184610Salfred	case PREVENT_ALLOW:
3530184610Salfred	case READ_CAPACITY:
3531184610Salfred	case READ_10:
3532184610Salfred	case WRITE_10:
3533184610Salfred	case POSITION_TO_ELEMENT:	/* SEEK_10 */
3534184610Salfred	case WRITE_AND_VERIFY:
3535184610Salfred	case VERIFY:
3536184610Salfred	case MODE_SELECT_10:
3537184610Salfred	case MODE_SENSE_10:
3538184610Salfred	case READ_12:
3539184610Salfred	case WRITE_12:
3540184610Salfred	case READ_FORMAT_CAPACITIES:
3541184610Salfred		break;
3542184610Salfred
3543184610Salfred		/*
3544184610Salfred		 * SYNCHRONIZE_CACHE isn't supported by UFI, nor should it be
3545184610Salfred		 * required for UFI devices, so it is appropriate to fake
3546184610Salfred		 * success.
3547184610Salfred		 */
3548184610Salfred	case SYNCHRONIZE_CACHE:
3549184610Salfred		return (2);
3550184610Salfred
3551184610Salfred	default:
3552184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Unsupported UFI "
3553184610Salfred		    "command 0x%02x\n", cmd_ptr[0]);
3554184610Salfred		return (0);		/* failure */
3555184610Salfred	}
3556184610Salfred
3557184610Salfred	bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
3558184610Salfred	return (1);			/* success */
3559184610Salfred}
3560184610Salfred
3561184610Salfred/*
3562184610Salfred * 8070i (ATAPI) specific functions
3563184610Salfred */
3564184610Salfredstatic uint8_t
3565184610Salfredumass_atapi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
3566184610Salfred    uint8_t cmd_len)
3567184610Salfred{
3568184610Salfred	if ((cmd_len == 0) ||
3569184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
3570184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
3571184610Salfred		    "length: %d bytes\n", cmd_len);
3572184610Salfred		return (0);		/* failure */
3573184610Salfred	}
3574184610Salfred	/* An ATAPI command is always 12 bytes in length. */
3575184610Salfred	sc->sc_transfer.cmd_len = ATAPI_COMMAND_LENGTH;
3576184610Salfred
3577184610Salfred	/* Zero the command data */
3578184610Salfred	bzero(sc->sc_transfer.cmd_data, ATAPI_COMMAND_LENGTH);
3579184610Salfred
3580184610Salfred	switch (cmd_ptr[0]) {
3581184610Salfred		/*
3582184610Salfred		 * Commands of which the format has been verified. They
3583184610Salfred		 * should work. Copy the command into the destination
3584184610Salfred		 * buffer.
3585184610Salfred		 */
3586184610Salfred	case INQUIRY:
3587184610Salfred		/*
3588184610Salfred		 * some drives wedge when asked for full inquiry
3589184610Salfred		 * information.
3590184610Salfred		 */
3591184610Salfred		if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
3592184610Salfred			bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
3593184610Salfred
3594184610Salfred			sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
3595184610Salfred			return (1);
3596184610Salfred		}
3597184610Salfred		break;
3598184610Salfred
3599184610Salfred	case TEST_UNIT_READY:
3600184610Salfred		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
3601184610Salfred			DPRINTF(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY "
3602184610Salfred			    "to START_UNIT\n");
3603184610Salfred			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
3604184610Salfred			sc->sc_transfer.cmd_data[4] = SSS_START;
3605184610Salfred			return (1);
3606184610Salfred		}
3607184610Salfred		break;
3608184610Salfred
3609184610Salfred	case REZERO_UNIT:
3610184610Salfred	case REQUEST_SENSE:
3611184610Salfred	case START_STOP_UNIT:
3612184610Salfred	case SEND_DIAGNOSTIC:
3613184610Salfred	case PREVENT_ALLOW:
3614184610Salfred	case READ_CAPACITY:
3615184610Salfred	case READ_10:
3616184610Salfred	case WRITE_10:
3617184610Salfred	case POSITION_TO_ELEMENT:	/* SEEK_10 */
3618184610Salfred	case SYNCHRONIZE_CACHE:
3619184610Salfred	case MODE_SELECT_10:
3620184610Salfred	case MODE_SENSE_10:
3621184610Salfred	case READ_BUFFER:
3622184610Salfred	case 0x42:			/* READ_SUBCHANNEL */
3623184610Salfred	case 0x43:			/* READ_TOC */
3624184610Salfred	case 0x44:			/* READ_HEADER */
3625184610Salfred	case 0x47:			/* PLAY_MSF (Play Minute/Second/Frame) */
3626184610Salfred	case 0x48:			/* PLAY_TRACK */
3627184610Salfred	case 0x49:			/* PLAY_TRACK_REL */
3628184610Salfred	case 0x4b:			/* PAUSE */
3629184610Salfred	case 0x51:			/* READ_DISK_INFO */
3630184610Salfred	case 0x52:			/* READ_TRACK_INFO */
3631184610Salfred	case 0x54:			/* SEND_OPC */
3632184610Salfred	case 0x59:			/* READ_MASTER_CUE */
3633184610Salfred	case 0x5b:			/* CLOSE_TR_SESSION */
3634184610Salfred	case 0x5c:			/* READ_BUFFER_CAP */
3635184610Salfred	case 0x5d:			/* SEND_CUE_SHEET */
3636184610Salfred	case 0xa1:			/* BLANK */
3637184610Salfred	case 0xa5:			/* PLAY_12 */
3638184610Salfred	case 0xa6:			/* EXCHANGE_MEDIUM */
3639184610Salfred	case 0xad:			/* READ_DVD_STRUCTURE */
3640184610Salfred	case 0xbb:			/* SET_CD_SPEED */
3641184610Salfred	case 0xe5:			/* READ_TRACK_INFO_PHILIPS */
3642184610Salfred		break;;
3643184610Salfred
3644184610Salfred	case READ_12:
3645184610Salfred	case WRITE_12:
3646184610Salfred	default:
3647184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Unsupported ATAPI "
3648184610Salfred		    "command 0x%02x - trying anyway\n",
3649184610Salfred		    cmd_ptr[0]);
3650184610Salfred		break;;
3651184610Salfred	}
3652184610Salfred
3653184610Salfred	bcopy(cmd_ptr, sc->sc_transfer.cmd_data, cmd_len);
3654184610Salfred	return (1);			/* success */
3655184610Salfred}
3656184610Salfred
3657184610Salfredstatic uint8_t
3658184610Salfredumass_no_transform(struct umass_softc *sc, uint8_t *cmd,
3659184610Salfred    uint8_t cmdlen)
3660184610Salfred{
3661184610Salfred	return (0);			/* failure */
3662184610Salfred}
3663184610Salfred
3664184610Salfredstatic uint8_t
3665184610Salfredumass_std_transform(struct umass_softc *sc, union ccb *ccb,
3666184610Salfred    uint8_t *cmd, uint8_t cmdlen)
3667184610Salfred{
3668184610Salfred	uint8_t retval;
3669184610Salfred
3670184610Salfred	retval = (sc->sc_transform) (sc, cmd, cmdlen);
3671184610Salfred
3672184610Salfred	if (retval == 2) {
3673184610Salfred		ccb->ccb_h.status = CAM_REQ_CMP;
3674184610Salfred		xpt_done(ccb);
3675184610Salfred		return (0);
3676184610Salfred	} else if (retval == 0) {
3677184610Salfred		ccb->ccb_h.status = CAM_REQ_INVALID;
3678184610Salfred		xpt_done(ccb);
3679184610Salfred		return (0);
3680184610Salfred	}
3681184610Salfred	/* Command should be executed */
3682184610Salfred	return (1);
3683184610Salfred}
3684184610Salfred
3685184610Salfred#if USB_DEBUG
3686184610Salfredstatic void
3687184610Salfredumass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw)
3688184610Salfred{
3689184610Salfred	uint8_t *c = cbw->CBWCDB;
3690184610Salfred
3691184610Salfred	uint32_t dlen = UGETDW(cbw->dCBWDataTransferLength);
3692184610Salfred	uint32_t tag = UGETDW(cbw->dCBWTag);
3693184610Salfred
3694184610Salfred	uint8_t clen = cbw->bCDBLength;
3695184610Salfred	uint8_t flags = cbw->bCBWFlags;
3696184610Salfred	uint8_t lun = cbw->bCBWLUN;
3697184610Salfred
3698184610Salfred	DPRINTF(sc, UDMASS_BBB, "CBW %d: cmd = %db "
3699184610Salfred	    "(0x%02x%02x%02x%02x%02x%02x%s), "
3700184610Salfred	    "data = %db, lun = %d, dir = %s\n",
3701184610Salfred	    tag, clen,
3702184610Salfred	    c[0], c[1], c[2], c[3], c[4], c[5], (clen > 6 ? "..." : ""),
3703184610Salfred	    dlen, lun, (flags == CBWFLAGS_IN ? "in" :
3704184610Salfred	    (flags == CBWFLAGS_OUT ? "out" : "<invalid>")));
3705184610Salfred}
3706184610Salfred
3707184610Salfredstatic void
3708184610Salfredumass_bbb_dump_csw(struct umass_softc *sc, umass_bbb_csw_t *csw)
3709184610Salfred{
3710184610Salfred	uint32_t sig = UGETDW(csw->dCSWSignature);
3711184610Salfred	uint32_t tag = UGETDW(csw->dCSWTag);
3712184610Salfred	uint32_t res = UGETDW(csw->dCSWDataResidue);
3713184610Salfred	uint8_t status = csw->bCSWStatus;
3714184610Salfred
3715184610Salfred	DPRINTF(sc, UDMASS_BBB, "CSW %d: sig = 0x%08x (%s), tag = 0x%08x, "
3716184610Salfred	    "res = %d, status = 0x%02x (%s)\n",
3717184610Salfred	    tag, sig, (sig == CSWSIGNATURE ? "valid" : "invalid"),
3718184610Salfred	    tag, res,
3719184610Salfred	    status, (status == CSWSTATUS_GOOD ? "good" :
3720184610Salfred	    (status == CSWSTATUS_FAILED ? "failed" :
3721184610Salfred	    (status == CSWSTATUS_PHASE ? "phase" : "<invalid>"))));
3722184610Salfred}
3723184610Salfred
3724184610Salfredstatic void
3725184610Salfredumass_cbi_dump_cmd(struct umass_softc *sc, void *cmd, uint8_t cmdlen)
3726184610Salfred{
3727184610Salfred	uint8_t *c = cmd;
3728184610Salfred	uint8_t dir = sc->sc_transfer.dir;
3729184610Salfred
3730184610Salfred	DPRINTF(sc, UDMASS_BBB, "cmd = %db "
3731184610Salfred	    "(0x%02x%02x%02x%02x%02x%02x%s), "
3732184610Salfred	    "data = %db, dir = %s\n",
3733184610Salfred	    cmdlen,
3734184610Salfred	    c[0], c[1], c[2], c[3], c[4], c[5], (cmdlen > 6 ? "..." : ""),
3735184610Salfred	    sc->sc_transfer.data_len,
3736184610Salfred	    (dir == DIR_IN ? "in" :
3737184610Salfred	    (dir == DIR_OUT ? "out" :
3738184610Salfred	    (dir == DIR_NONE ? "no data phase" : "<invalid>"))));
3739184610Salfred}
3740184610Salfred
3741184610Salfredstatic void
3742184610Salfredumass_dump_buffer(struct umass_softc *sc, uint8_t *buffer, uint32_t buflen,
3743184610Salfred    uint32_t printlen)
3744184610Salfred{
3745184610Salfred	uint32_t i, j;
3746184610Salfred	char s1[40];
3747184610Salfred	char s2[40];
3748184610Salfred	char s3[5];
3749184610Salfred
3750184610Salfred	s1[0] = '\0';
3751184610Salfred	s3[0] = '\0';
3752184610Salfred
3753184610Salfred	sprintf(s2, " buffer=%p, buflen=%d", buffer, buflen);
3754184610Salfred	for (i = 0; (i < buflen) && (i < printlen); i++) {
3755184610Salfred		j = i % 16;
3756184610Salfred		if (j == 0 && i != 0) {
3757184610Salfred			DPRINTF(sc, UDMASS_GEN, "0x %s%s\n",
3758184610Salfred			    s1, s2);
3759184610Salfred			s2[0] = '\0';
3760184610Salfred		}
3761184610Salfred		sprintf(&s1[j * 2], "%02x", buffer[i] & 0xff);
3762184610Salfred	}
3763184610Salfred	if (buflen > printlen)
3764184610Salfred		sprintf(s3, " ...");
3765184610Salfred	DPRINTF(sc, UDMASS_GEN, "0x %s%s%s\n",
3766184610Salfred	    s1, s2, s3);
3767184610Salfred}
3768184610Salfred
3769184610Salfred#endif
3770