umass.c revision 244491
1184610Salfred#include <sys/cdefs.h>
2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/storage/umass.c 244491 2012-12-20 17:14:10Z hselasky $");
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 244491 2012-12-20 17:14:10Z hselasky $
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/module.h>
114194677Sthompsa#include <sys/lock.h>
115194677Sthompsa#include <sys/mutex.h>
116194677Sthompsa#include <sys/condvar.h>
117194677Sthompsa#include <sys/sysctl.h>
118194677Sthompsa#include <sys/sx.h>
119194677Sthompsa#include <sys/unistd.h>
120194677Sthompsa#include <sys/callout.h>
121194677Sthompsa#include <sys/malloc.h>
122194677Sthompsa#include <sys/priv.h>
123194677Sthompsa
124194677Sthompsa#include <dev/usb/usb.h>
125194677Sthompsa#include <dev/usb/usbdi.h>
126212136Sthompsa#include <dev/usb/usbdi_util.h>
127188746Sthompsa#include "usbdevs.h"
128184610Salfred
129200886Sthompsa#include <dev/usb/quirk/usb_quirk.h>
130200886Sthompsa
131184610Salfred#include <cam/cam.h>
132184610Salfred#include <cam/cam_ccb.h>
133184610Salfred#include <cam/cam_sim.h>
134184610Salfred#include <cam/cam_xpt_sim.h>
135184610Salfred#include <cam/scsi/scsi_all.h>
136184610Salfred#include <cam/scsi/scsi_da.h>
137184610Salfred
138184610Salfred#include <cam/cam_periph.h>
139184610Salfred
140207077Sthompsa#ifdef USB_DEBUG
141184610Salfred#define	DIF(m, x)				\
142184610Salfred  do {						\
143184610Salfred    if (umass_debug & (m)) { x ; }		\
144184610Salfred  } while (0)
145184610Salfred
146184610Salfred#define	DPRINTF(sc, m, fmt, ...)			\
147184610Salfred  do {							\
148184610Salfred    if (umass_debug & (m)) {				\
149184610Salfred        printf("%s:%s: " fmt,				\
150184610Salfred	       (sc) ? (const char *)(sc)->sc_name :	\
151184610Salfred	       (const char *)"umassX",			\
152184610Salfred		__FUNCTION__ ,## __VA_ARGS__);		\
153184610Salfred    }							\
154184610Salfred  } while (0)
155184610Salfred
156184610Salfred#define	UDMASS_GEN	0x00010000	/* general */
157184610Salfred#define	UDMASS_SCSI	0x00020000	/* scsi */
158184610Salfred#define	UDMASS_UFI	0x00040000	/* ufi command set */
159184610Salfred#define	UDMASS_ATAPI	0x00080000	/* 8070i command set */
160184610Salfred#define	UDMASS_CMD	(UDMASS_SCSI|UDMASS_UFI|UDMASS_ATAPI)
161184610Salfred#define	UDMASS_USB	0x00100000	/* USB general */
162184610Salfred#define	UDMASS_BBB	0x00200000	/* Bulk-Only transfers */
163184610Salfred#define	UDMASS_CBI	0x00400000	/* CBI transfers */
164184610Salfred#define	UDMASS_WIRE	(UDMASS_BBB|UDMASS_CBI)
165184610Salfred#define	UDMASS_ALL	0xffff0000	/* all of the above */
166244491Shselaskystatic int umass_debug;
167244491Shselaskystatic int umass_throttle;
168184610Salfred
169227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass");
170242126ShselaskySYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
171184610Salfred    &umass_debug, 0, "umass debug level");
172199675SthompsaTUNABLE_INT("hw.usb.umass.debug", &umass_debug);
173244491ShselaskySYSCTL_INT(_hw_usb_umass, OID_AUTO, throttle, CTLFLAG_RW | CTLFLAG_TUN,
174244491Shselasky    &umass_throttle, 0, "Forced delay between commands in milliseconds");
175244491ShselaskyTUNABLE_INT("hw.usb.umass.throttle", &umass_throttle);
176184610Salfred#else
177184610Salfred#define	DIF(...) do { } while (0)
178184610Salfred#define	DPRINTF(...) do { } while (0)
179184610Salfred#endif
180184610Salfred
181184610Salfred#define	UMASS_BULK_SIZE (1 << 17)
182184610Salfred#define	UMASS_CBI_DIAGNOSTIC_CMDLEN 12	/* bytes */
183184610Salfred#define	UMASS_MAX_CMDLEN MAX(12, CAM_MAX_CDBLEN)	/* bytes */
184184610Salfred
185184610Salfred/* USB transfer definitions */
186184610Salfred
187184610Salfred#define	UMASS_T_BBB_RESET1      0	/* Bulk-Only */
188184610Salfred#define	UMASS_T_BBB_RESET2      1
189184610Salfred#define	UMASS_T_BBB_RESET3      2
190184610Salfred#define	UMASS_T_BBB_COMMAND     3
191184610Salfred#define	UMASS_T_BBB_DATA_READ   4
192184610Salfred#define	UMASS_T_BBB_DATA_RD_CS  5
193184610Salfred#define	UMASS_T_BBB_DATA_WRITE  6
194184610Salfred#define	UMASS_T_BBB_DATA_WR_CS  7
195184610Salfred#define	UMASS_T_BBB_STATUS      8
196184610Salfred#define	UMASS_T_BBB_MAX         9
197184610Salfred
198184610Salfred#define	UMASS_T_CBI_RESET1      0	/* CBI */
199184610Salfred#define	UMASS_T_CBI_RESET2      1
200184610Salfred#define	UMASS_T_CBI_RESET3      2
201184610Salfred#define	UMASS_T_CBI_COMMAND     3
202184610Salfred#define	UMASS_T_CBI_DATA_READ   4
203184610Salfred#define	UMASS_T_CBI_DATA_RD_CS  5
204184610Salfred#define	UMASS_T_CBI_DATA_WRITE  6
205184610Salfred#define	UMASS_T_CBI_DATA_WR_CS  7
206184610Salfred#define	UMASS_T_CBI_STATUS      8
207184610Salfred#define	UMASS_T_CBI_RESET4      9
208184610Salfred#define	UMASS_T_CBI_MAX        10
209184610Salfred
210184610Salfred#define	UMASS_T_MAX MAX(UMASS_T_CBI_MAX, UMASS_T_BBB_MAX)
211184610Salfred
212184610Salfred/* Generic definitions */
213184610Salfred
214184610Salfred/* Direction for transfer */
215184610Salfred#define	DIR_NONE	0
216184610Salfred#define	DIR_IN		1
217184610Salfred#define	DIR_OUT		2
218184610Salfred
219184610Salfred/* device name */
220184610Salfred#define	DEVNAME		"umass"
221184610Salfred#define	DEVNAME_SIM	"umass-sim"
222184610Salfred
223184610Salfred/* Approximate maximum transfer speeds (assumes 33% overhead). */
224184610Salfred#define	UMASS_FULL_TRANSFER_SPEED	1000
225184610Salfred#define	UMASS_HIGH_TRANSFER_SPEED	40000
226213439Shselasky#define	UMASS_SUPER_TRANSFER_SPEED	400000
227184610Salfred#define	UMASS_FLOPPY_TRANSFER_SPEED	20
228184610Salfred
229184610Salfred#define	UMASS_TIMEOUT			5000	/* ms */
230184610Salfred
231184610Salfred/* CAM specific definitions */
232184610Salfred
233184610Salfred#define	UMASS_SCSIID_MAX	1	/* maximum number of drives expected */
234184610Salfred#define	UMASS_SCSIID_HOST	UMASS_SCSIID_MAX
235184610Salfred
236184610Salfred/* Bulk-Only features */
237184610Salfred
238184610Salfred#define	UR_BBB_RESET		0xff	/* Bulk-Only reset */
239184610Salfred#define	UR_BBB_GET_MAX_LUN	0xfe	/* Get maximum lun */
240184610Salfred
241184610Salfred/* Command Block Wrapper */
242184610Salfredtypedef struct {
243184610Salfred	uDWord	dCBWSignature;
244184610Salfred#define	CBWSIGNATURE	0x43425355
245184610Salfred	uDWord	dCBWTag;
246184610Salfred	uDWord	dCBWDataTransferLength;
247184610Salfred	uByte	bCBWFlags;
248184610Salfred#define	CBWFLAGS_OUT	0x00
249184610Salfred#define	CBWFLAGS_IN	0x80
250184610Salfred	uByte	bCBWLUN;
251184610Salfred	uByte	bCDBLength;
252184610Salfred#define	CBWCDBLENGTH	16
253184610Salfred	uByte	CBWCDB[CBWCDBLENGTH];
254184610Salfred} __packed umass_bbb_cbw_t;
255184610Salfred
256184610Salfred#define	UMASS_BBB_CBW_SIZE	31
257184610Salfred
258184610Salfred/* Command Status Wrapper */
259184610Salfredtypedef struct {
260184610Salfred	uDWord	dCSWSignature;
261184610Salfred#define	CSWSIGNATURE	0x53425355
262184610Salfred#define	CSWSIGNATURE_IMAGINATION_DBX1	0x43425355
263184610Salfred#define	CSWSIGNATURE_OLYMPUS_C1	0x55425355
264184610Salfred	uDWord	dCSWTag;
265184610Salfred	uDWord	dCSWDataResidue;
266184610Salfred	uByte	bCSWStatus;
267184610Salfred#define	CSWSTATUS_GOOD	0x0
268184610Salfred#define	CSWSTATUS_FAILED	0x1
269184610Salfred#define	CSWSTATUS_PHASE	0x2
270184610Salfred} __packed umass_bbb_csw_t;
271184610Salfred
272184610Salfred#define	UMASS_BBB_CSW_SIZE	13
273184610Salfred
274184610Salfred/* CBI features */
275184610Salfred
276184610Salfred#define	UR_CBI_ADSC	0x00
277184610Salfred
278184610Salfredtypedef union {
279184610Salfred	struct {
280184610Salfred		uint8_t	type;
281184610Salfred#define	IDB_TYPE_CCI		0x00
282184610Salfred		uint8_t	value;
283184610Salfred#define	IDB_VALUE_PASS		0x00
284184610Salfred#define	IDB_VALUE_FAIL		0x01
285184610Salfred#define	IDB_VALUE_PHASE		0x02
286184610Salfred#define	IDB_VALUE_PERSISTENT	0x03
287184610Salfred#define	IDB_VALUE_STATUS_MASK	0x03
288184610Salfred	} __packed common;
289184610Salfred
290184610Salfred	struct {
291184610Salfred		uint8_t	asc;
292184610Salfred		uint8_t	ascq;
293184610Salfred	} __packed ufi;
294184610Salfred} __packed umass_cbi_sbl_t;
295184610Salfred
296184610Salfredstruct umass_softc;			/* see below */
297184610Salfred
298184610Salfredtypedef void (umass_callback_t)(struct umass_softc *sc, union ccb *ccb,
299184610Salfred    	uint32_t residue, uint8_t status);
300184610Salfred
301184610Salfred#define	STATUS_CMD_OK		0	/* everything ok */
302184610Salfred#define	STATUS_CMD_UNKNOWN	1	/* will have to fetch sense */
303184610Salfred#define	STATUS_CMD_FAILED	2	/* transfer was ok, command failed */
304184610Salfred#define	STATUS_WIRE_FAILED	3	/* couldn't even get command across */
305184610Salfred
306184610Salfredtypedef uint8_t (umass_transform_t)(struct umass_softc *sc, uint8_t *cmd_ptr,
307184610Salfred    	uint8_t cmd_len);
308184610Salfred
309200886Sthompsa/* Wire and command protocol */
310184610Salfred#define	UMASS_PROTO_BBB		0x0001	/* USB wire protocol */
311184610Salfred#define	UMASS_PROTO_CBI		0x0002
312184610Salfred#define	UMASS_PROTO_CBI_I	0x0004
313200886Sthompsa#define	UMASS_PROTO_WIRE	0x00ff	/* USB wire protocol mask */
314200886Sthompsa#define	UMASS_PROTO_SCSI	0x0100	/* command protocol */
315184610Salfred#define	UMASS_PROTO_ATAPI	0x0200
316184610Salfred#define	UMASS_PROTO_UFI		0x0400
317184610Salfred#define	UMASS_PROTO_RBC		0x0800
318184610Salfred#define	UMASS_PROTO_COMMAND	0xff00	/* command protocol mask */
319184610Salfred
320200886Sthompsa/* Device specific quirks */
321184610Salfred#define	NO_QUIRKS		0x0000
322184610Salfred	/*
323184610Salfred	 * The drive does not support Test Unit Ready. Convert to Start Unit
324184610Salfred	 */
325184610Salfred#define	NO_TEST_UNIT_READY	0x0001
326184610Salfred	/*
327184610Salfred	 * The drive does not reset the Unit Attention state after REQUEST
328184610Salfred	 * SENSE has been sent. The INQUIRY command does not reset the UA
329184610Salfred	 * either, and so CAM runs in circles trying to retrieve the initial
330184610Salfred	 * INQUIRY data.
331184610Salfred	 */
332184610Salfred#define	RS_NO_CLEAR_UA		0x0002
333184610Salfred	/* The drive does not support START STOP.  */
334184610Salfred#define	NO_START_STOP		0x0004
335184610Salfred	/* Don't ask for full inquiry data (255b).  */
336184610Salfred#define	FORCE_SHORT_INQUIRY	0x0008
337184610Salfred	/* Needs to be initialised the Shuttle way */
338184610Salfred#define	SHUTTLE_INIT		0x0010
339184610Salfred	/* Drive needs to be switched to alternate iface 1 */
340184610Salfred#define	ALT_IFACE_1		0x0020
341184610Salfred	/* Drive does not do 1Mb/s, but just floppy speeds (20kb/s) */
342184610Salfred#define	FLOPPY_SPEED		0x0040
343184610Salfred	/* The device can't count and gets the residue of transfers wrong */
344184610Salfred#define	IGNORE_RESIDUE		0x0080
345184610Salfred	/* No GetMaxLun call */
346184610Salfred#define	NO_GETMAXLUN		0x0100
347184610Salfred	/* The device uses a weird CSWSIGNATURE. */
348184610Salfred#define	WRONG_CSWSIG		0x0200
349184610Salfred	/* Device cannot handle INQUIRY so fake a generic response */
350184610Salfred#define	NO_INQUIRY		0x0400
351184610Salfred	/* Device cannot handle INQUIRY EVPD, return CHECK CONDITION */
352184610Salfred#define	NO_INQUIRY_EVPD		0x0800
353184610Salfred	/* Pad all RBC requests to 12 bytes. */
354184610Salfred#define	RBC_PAD_TO_12		0x1000
355184610Salfred	/*
356184610Salfred	 * Device reports number of sectors from READ_CAPACITY, not max
357184610Salfred	 * sector number.
358184610Salfred	 */
359184610Salfred#define	READ_CAPACITY_OFFBY1	0x2000
360184610Salfred	/*
361184610Salfred	 * Device cannot handle a SCSI synchronize cache command.  Normally
362184610Salfred	 * this quirk would be handled in the cam layer, but for IDE bridges
363184610Salfred	 * we need to associate the quirk with the bridge and not the
364184610Salfred	 * underlying disk device.  This is handled by faking a success
365184610Salfred	 * result.
366184610Salfred	 */
367184610Salfred#define	NO_SYNCHRONIZE_CACHE	0x4000
368242628Smarcel	/* Device does not support 'PREVENT/ALLOW MEDIUM REMOVAL'. */
369242628Smarcel#define	NO_PREVENT_ALLOW	0x8000
370184610Salfred
371184610Salfredstruct umass_softc {
372184610Salfred
373184610Salfred	struct scsi_sense cam_scsi_sense;
374184610Salfred	struct scsi_test_unit_ready cam_scsi_test_unit_ready;
375184610Salfred	struct mtx sc_mtx;
376184610Salfred	struct {
377184610Salfred		uint8_t *data_ptr;
378184610Salfred		union ccb *ccb;
379184610Salfred		umass_callback_t *callback;
380184610Salfred
381184610Salfred		uint32_t data_len;	/* bytes */
382184610Salfred		uint32_t data_rem;	/* bytes */
383184610Salfred		uint32_t data_timeout;	/* ms */
384184610Salfred		uint32_t actlen;	/* bytes */
385184610Salfred
386184610Salfred		uint8_t	cmd_data[UMASS_MAX_CMDLEN];
387184610Salfred		uint8_t	cmd_len;	/* bytes */
388184610Salfred		uint8_t	dir;
389184610Salfred		uint8_t	lun;
390184610Salfred	}	sc_transfer;
391184610Salfred
392184610Salfred	/* Bulk specific variables for transfers in progress */
393184610Salfred	umass_bbb_cbw_t cbw;		/* command block wrapper */
394184610Salfred	umass_bbb_csw_t csw;		/* command status wrapper */
395184610Salfred
396184610Salfred	/* CBI specific variables for transfers in progress */
397184610Salfred	umass_cbi_sbl_t sbl;		/* status block */
398184610Salfred
399184610Salfred	device_t sc_dev;
400192984Sthompsa	struct usb_device *sc_udev;
401184610Salfred	struct cam_sim *sc_sim;		/* SCSI Interface Module */
402192984Sthompsa	struct usb_xfer *sc_xfer[UMASS_T_MAX];
403184610Salfred
404184610Salfred	/*
405184610Salfred	 * The command transform function is used to convert the SCSI
406184610Salfred	 * commands into their derivatives, like UFI, ATAPI, and friends.
407184610Salfred	 */
408184610Salfred	umass_transform_t *sc_transform;
409184610Salfred
410184610Salfred	uint32_t sc_unit;
411200886Sthompsa	uint32_t sc_quirks;		/* they got it almost right */
412200886Sthompsa	uint32_t sc_proto;		/* wire and cmd protocol */
413184610Salfred
414184610Salfred	uint8_t	sc_name[16];
415184610Salfred	uint8_t	sc_iface_no;		/* interface number */
416184610Salfred	uint8_t	sc_maxlun;		/* maximum LUN number, inclusive */
417184610Salfred	uint8_t	sc_last_xfer_index;
418184610Salfred	uint8_t	sc_status_try;
419184610Salfred};
420184610Salfred
421184610Salfredstruct umass_probe_proto {
422200886Sthompsa	uint32_t quirks;
423200886Sthompsa	uint32_t proto;
424184610Salfred
425200886Sthompsa	int	error;
426184610Salfred};
427184610Salfred
428184610Salfred/* prototypes */
429184610Salfred
430184610Salfredstatic device_probe_t umass_probe;
431184610Salfredstatic device_attach_t umass_attach;
432184610Salfredstatic device_detach_t umass_detach;
433184610Salfred
434193045Sthompsastatic usb_callback_t umass_tr_error;
435193045Sthompsastatic usb_callback_t umass_t_bbb_reset1_callback;
436193045Sthompsastatic usb_callback_t umass_t_bbb_reset2_callback;
437193045Sthompsastatic usb_callback_t umass_t_bbb_reset3_callback;
438193045Sthompsastatic usb_callback_t umass_t_bbb_command_callback;
439193045Sthompsastatic usb_callback_t umass_t_bbb_data_read_callback;
440193045Sthompsastatic usb_callback_t umass_t_bbb_data_rd_cs_callback;
441193045Sthompsastatic usb_callback_t umass_t_bbb_data_write_callback;
442193045Sthompsastatic usb_callback_t umass_t_bbb_data_wr_cs_callback;
443193045Sthompsastatic usb_callback_t umass_t_bbb_status_callback;
444193045Sthompsastatic usb_callback_t umass_t_cbi_reset1_callback;
445193045Sthompsastatic usb_callback_t umass_t_cbi_reset2_callback;
446193045Sthompsastatic usb_callback_t umass_t_cbi_reset3_callback;
447193045Sthompsastatic usb_callback_t umass_t_cbi_reset4_callback;
448193045Sthompsastatic usb_callback_t umass_t_cbi_command_callback;
449193045Sthompsastatic usb_callback_t umass_t_cbi_data_read_callback;
450193045Sthompsastatic usb_callback_t umass_t_cbi_data_rd_cs_callback;
451193045Sthompsastatic usb_callback_t umass_t_cbi_data_write_callback;
452193045Sthompsastatic usb_callback_t umass_t_cbi_data_wr_cs_callback;
453193045Sthompsastatic usb_callback_t umass_t_cbi_status_callback;
454184610Salfred
455185948Sthompsastatic void	umass_cancel_ccb(struct umass_softc *);
456185948Sthompsastatic void	umass_init_shuttle(struct umass_softc *);
457185948Sthompsastatic void	umass_reset(struct umass_softc *);
458192984Sthompsastatic void	umass_t_bbb_data_clear_stall_callback(struct usb_xfer *,
459194677Sthompsa		    uint8_t, uint8_t, usb_error_t);
460185948Sthompsastatic void	umass_command_start(struct umass_softc *, uint8_t, void *,
461185948Sthompsa		    uint32_t, uint32_t, umass_callback_t *, union ccb *);
462185948Sthompsastatic uint8_t	umass_bbb_get_max_lun(struct umass_softc *);
463185948Sthompsastatic void	umass_cbi_start_status(struct umass_softc *);
464192984Sthompsastatic void	umass_t_cbi_data_clear_stall_callback(struct usb_xfer *,
465194677Sthompsa		    uint8_t, uint8_t, usb_error_t);
466185948Sthompsastatic int	umass_cam_attach_sim(struct umass_softc *);
467185948Sthompsastatic void	umass_cam_attach(struct umass_softc *);
468185948Sthompsastatic void	umass_cam_detach_sim(struct umass_softc *);
469185948Sthompsastatic void	umass_cam_action(struct cam_sim *, union ccb *);
470185948Sthompsastatic void	umass_cam_poll(struct cam_sim *);
471185948Sthompsastatic void	umass_cam_cb(struct umass_softc *, union ccb *, uint32_t,
472185948Sthompsa		    uint8_t);
473185948Sthompsastatic void	umass_cam_sense_cb(struct umass_softc *, union ccb *, uint32_t,
474185948Sthompsa		    uint8_t);
475185948Sthompsastatic void	umass_cam_quirk_cb(struct umass_softc *, union ccb *, uint32_t,
476185948Sthompsa		    uint8_t);
477185948Sthompsastatic uint8_t	umass_scsi_transform(struct umass_softc *, uint8_t *, uint8_t);
478185948Sthompsastatic uint8_t	umass_rbc_transform(struct umass_softc *, uint8_t *, uint8_t);
479185948Sthompsastatic uint8_t	umass_ufi_transform(struct umass_softc *, uint8_t *, uint8_t);
480185948Sthompsastatic uint8_t	umass_atapi_transform(struct umass_softc *, uint8_t *,
481185948Sthompsa		    uint8_t);
482185948Sthompsastatic uint8_t	umass_no_transform(struct umass_softc *, uint8_t *, uint8_t);
483185948Sthompsastatic uint8_t	umass_std_transform(struct umass_softc *, union ccb *, uint8_t
484185948Sthompsa		    *, uint8_t);
485184610Salfred
486207077Sthompsa#ifdef USB_DEBUG
487185948Sthompsastatic void	umass_bbb_dump_cbw(struct umass_softc *, umass_bbb_cbw_t *);
488185948Sthompsastatic void	umass_bbb_dump_csw(struct umass_softc *, umass_bbb_csw_t *);
489185948Sthompsastatic void	umass_cbi_dump_cmd(struct umass_softc *, void *, uint8_t);
490185948Sthompsastatic void	umass_dump_buffer(struct umass_softc *, uint8_t *, uint32_t,
491185948Sthompsa		    uint32_t);
492184610Salfred#endif
493184610Salfred
494194099Sthompsastatic struct usb_config umass_bbb_config[UMASS_T_BBB_MAX] = {
495184610Salfred
496184610Salfred	[UMASS_T_BBB_RESET1] = {
497184610Salfred		.type = UE_CONTROL,
498184610Salfred		.endpoint = 0x00,	/* Control pipe */
499184610Salfred		.direction = UE_DIR_ANY,
500192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
501190734Sthompsa		.callback = &umass_t_bbb_reset1_callback,
502190734Sthompsa		.timeout = 5000,	/* 5 seconds */
503190734Sthompsa		.interval = 500,	/* 500 milliseconds */
504184610Salfred	},
505184610Salfred
506184610Salfred	[UMASS_T_BBB_RESET2] = {
507184610Salfred		.type = UE_CONTROL,
508184610Salfred		.endpoint = 0x00,	/* Control pipe */
509184610Salfred		.direction = UE_DIR_ANY,
510192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
511190734Sthompsa		.callback = &umass_t_bbb_reset2_callback,
512190734Sthompsa		.timeout = 5000,	/* 5 seconds */
513190734Sthompsa		.interval = 50,	/* 50 milliseconds */
514184610Salfred	},
515184610Salfred
516184610Salfred	[UMASS_T_BBB_RESET3] = {
517184610Salfred		.type = UE_CONTROL,
518184610Salfred		.endpoint = 0x00,	/* Control pipe */
519184610Salfred		.direction = UE_DIR_ANY,
520192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
521190734Sthompsa		.callback = &umass_t_bbb_reset3_callback,
522190734Sthompsa		.timeout = 5000,	/* 5 seconds */
523190734Sthompsa		.interval = 50,	/* 50 milliseconds */
524184610Salfred	},
525184610Salfred
526184610Salfred	[UMASS_T_BBB_COMMAND] = {
527184610Salfred		.type = UE_BULK,
528184610Salfred		.endpoint = UE_ADDR_ANY,
529184610Salfred		.direction = UE_DIR_OUT,
530190734Sthompsa		.bufsize = sizeof(umass_bbb_cbw_t),
531190734Sthompsa		.callback = &umass_t_bbb_command_callback,
532190734Sthompsa		.timeout = 5000,	/* 5 seconds */
533184610Salfred	},
534184610Salfred
535184610Salfred	[UMASS_T_BBB_DATA_READ] = {
536184610Salfred		.type = UE_BULK,
537184610Salfred		.endpoint = UE_ADDR_ANY,
538184610Salfred		.direction = UE_DIR_IN,
539190734Sthompsa		.bufsize = UMASS_BULK_SIZE,
540232361Shselasky		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
541190734Sthompsa		.callback = &umass_t_bbb_data_read_callback,
542190734Sthompsa		.timeout = 0,	/* overwritten later */
543184610Salfred	},
544184610Salfred
545184610Salfred	[UMASS_T_BBB_DATA_RD_CS] = {
546184610Salfred		.type = UE_CONTROL,
547184610Salfred		.endpoint = 0x00,	/* Control pipe */
548184610Salfred		.direction = UE_DIR_ANY,
549192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
550190734Sthompsa		.callback = &umass_t_bbb_data_rd_cs_callback,
551190734Sthompsa		.timeout = 5000,	/* 5 seconds */
552184610Salfred	},
553184610Salfred
554184610Salfred	[UMASS_T_BBB_DATA_WRITE] = {
555184610Salfred		.type = UE_BULK,
556184610Salfred		.endpoint = UE_ADDR_ANY,
557184610Salfred		.direction = UE_DIR_OUT,
558190734Sthompsa		.bufsize = UMASS_BULK_SIZE,
559232361Shselasky		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
560190734Sthompsa		.callback = &umass_t_bbb_data_write_callback,
561190734Sthompsa		.timeout = 0,	/* overwritten later */
562184610Salfred	},
563184610Salfred
564184610Salfred	[UMASS_T_BBB_DATA_WR_CS] = {
565184610Salfred		.type = UE_CONTROL,
566184610Salfred		.endpoint = 0x00,	/* Control pipe */
567184610Salfred		.direction = UE_DIR_ANY,
568192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
569190734Sthompsa		.callback = &umass_t_bbb_data_wr_cs_callback,
570190734Sthompsa		.timeout = 5000,	/* 5 seconds */
571184610Salfred	},
572184610Salfred
573184610Salfred	[UMASS_T_BBB_STATUS] = {
574184610Salfred		.type = UE_BULK,
575184610Salfred		.endpoint = UE_ADDR_ANY,
576184610Salfred		.direction = UE_DIR_IN,
577190734Sthompsa		.bufsize = sizeof(umass_bbb_csw_t),
578190734Sthompsa		.flags = {.short_xfer_ok = 1,},
579190734Sthompsa		.callback = &umass_t_bbb_status_callback,
580190734Sthompsa		.timeout = 5000,	/* ms */
581184610Salfred	},
582184610Salfred};
583184610Salfred
584194099Sthompsastatic struct usb_config umass_cbi_config[UMASS_T_CBI_MAX] = {
585184610Salfred
586184610Salfred	[UMASS_T_CBI_RESET1] = {
587184610Salfred		.type = UE_CONTROL,
588184610Salfred		.endpoint = 0x00,	/* Control pipe */
589184610Salfred		.direction = UE_DIR_ANY,
590192984Sthompsa		.bufsize = (sizeof(struct usb_device_request) +
591184610Salfred		    UMASS_CBI_DIAGNOSTIC_CMDLEN),
592190734Sthompsa		.callback = &umass_t_cbi_reset1_callback,
593190734Sthompsa		.timeout = 5000,	/* 5 seconds */
594190734Sthompsa		.interval = 500,	/* 500 milliseconds */
595184610Salfred	},
596184610Salfred
597184610Salfred	[UMASS_T_CBI_RESET2] = {
598184610Salfred		.type = UE_CONTROL,
599184610Salfred		.endpoint = 0x00,	/* Control pipe */
600184610Salfred		.direction = UE_DIR_ANY,
601192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
602190734Sthompsa		.callback = &umass_t_cbi_reset2_callback,
603190734Sthompsa		.timeout = 5000,	/* 5 seconds */
604190734Sthompsa		.interval = 50,	/* 50 milliseconds */
605184610Salfred	},
606184610Salfred
607184610Salfred	[UMASS_T_CBI_RESET3] = {
608184610Salfred		.type = UE_CONTROL,
609184610Salfred		.endpoint = 0x00,	/* Control pipe */
610184610Salfred		.direction = UE_DIR_ANY,
611192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
612190734Sthompsa		.callback = &umass_t_cbi_reset3_callback,
613190734Sthompsa		.timeout = 5000,	/* 5 seconds */
614190734Sthompsa		.interval = 50,	/* 50 milliseconds */
615184610Salfred	},
616184610Salfred
617184610Salfred	[UMASS_T_CBI_COMMAND] = {
618184610Salfred		.type = UE_CONTROL,
619184610Salfred		.endpoint = 0x00,	/* Control pipe */
620184610Salfred		.direction = UE_DIR_ANY,
621192984Sthompsa		.bufsize = (sizeof(struct usb_device_request) +
622184610Salfred		    UMASS_MAX_CMDLEN),
623190734Sthompsa		.callback = &umass_t_cbi_command_callback,
624190734Sthompsa		.timeout = 5000,	/* 5 seconds */
625184610Salfred	},
626184610Salfred
627184610Salfred	[UMASS_T_CBI_DATA_READ] = {
628184610Salfred		.type = UE_BULK,
629184610Salfred		.endpoint = UE_ADDR_ANY,
630184610Salfred		.direction = UE_DIR_IN,
631190734Sthompsa		.bufsize = UMASS_BULK_SIZE,
632232361Shselasky		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
633190734Sthompsa		.callback = &umass_t_cbi_data_read_callback,
634190734Sthompsa		.timeout = 0,	/* overwritten later */
635184610Salfred	},
636184610Salfred
637184610Salfred	[UMASS_T_CBI_DATA_RD_CS] = {
638184610Salfred		.type = UE_CONTROL,
639184610Salfred		.endpoint = 0x00,	/* Control pipe */
640184610Salfred		.direction = UE_DIR_ANY,
641192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
642190734Sthompsa		.callback = &umass_t_cbi_data_rd_cs_callback,
643190734Sthompsa		.timeout = 5000,	/* 5 seconds */
644184610Salfred	},
645184610Salfred
646184610Salfred	[UMASS_T_CBI_DATA_WRITE] = {
647184610Salfred		.type = UE_BULK,
648184610Salfred		.endpoint = UE_ADDR_ANY,
649184610Salfred		.direction = UE_DIR_OUT,
650190734Sthompsa		.bufsize = UMASS_BULK_SIZE,
651232361Shselasky		.flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,},
652190734Sthompsa		.callback = &umass_t_cbi_data_write_callback,
653190734Sthompsa		.timeout = 0,	/* overwritten later */
654184610Salfred	},
655184610Salfred
656184610Salfred	[UMASS_T_CBI_DATA_WR_CS] = {
657184610Salfred		.type = UE_CONTROL,
658184610Salfred		.endpoint = 0x00,	/* Control pipe */
659184610Salfred		.direction = UE_DIR_ANY,
660192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
661190734Sthompsa		.callback = &umass_t_cbi_data_wr_cs_callback,
662190734Sthompsa		.timeout = 5000,	/* 5 seconds */
663184610Salfred	},
664184610Salfred
665184610Salfred	[UMASS_T_CBI_STATUS] = {
666184610Salfred		.type = UE_INTERRUPT,
667184610Salfred		.endpoint = UE_ADDR_ANY,
668184610Salfred		.direction = UE_DIR_IN,
669203145Sthompsa		.flags = {.short_xfer_ok = 1,.no_pipe_ok = 1,},
670190734Sthompsa		.bufsize = sizeof(umass_cbi_sbl_t),
671190734Sthompsa		.callback = &umass_t_cbi_status_callback,
672190734Sthompsa		.timeout = 5000,	/* ms */
673184610Salfred	},
674184610Salfred
675184610Salfred	[UMASS_T_CBI_RESET4] = {
676184610Salfred		.type = UE_CONTROL,
677184610Salfred		.endpoint = 0x00,	/* Control pipe */
678184610Salfred		.direction = UE_DIR_ANY,
679192984Sthompsa		.bufsize = sizeof(struct usb_device_request),
680190734Sthompsa		.callback = &umass_t_cbi_reset4_callback,
681190734Sthompsa		.timeout = 5000,	/* ms */
682184610Salfred	},
683184610Salfred};
684184610Salfred
685184610Salfred/* If device cannot return valid inquiry data, fake it */
686184610Salfredstatic const uint8_t fake_inq_data[SHORT_INQUIRY_LENGTH] = {
687184610Salfred	0, /* removable */ 0x80, SCSI_REV_2, SCSI_REV_2,
688184610Salfred	 /* additional_length */ 31, 0, 0, 0
689184610Salfred};
690184610Salfred
691184610Salfred#define	UFI_COMMAND_LENGTH	12	/* UFI commands are always 12 bytes */
692184610Salfred#define	ATAPI_COMMAND_LENGTH	12	/* ATAPI commands are always 12 bytes */
693184610Salfred
694184610Salfredstatic devclass_t umass_devclass;
695184610Salfred
696184610Salfredstatic device_method_t umass_methods[] = {
697184610Salfred	/* Device interface */
698184610Salfred	DEVMETHOD(device_probe, umass_probe),
699184610Salfred	DEVMETHOD(device_attach, umass_attach),
700184610Salfred	DEVMETHOD(device_detach, umass_detach),
701184610Salfred	{0, 0}
702184610Salfred};
703184610Salfred
704184610Salfredstatic driver_t umass_driver = {
705184610Salfred	.name = "umass",
706184610Salfred	.methods = umass_methods,
707184610Salfred	.size = sizeof(struct umass_softc),
708184610Salfred};
709184610Salfred
710189275SthompsaDRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, NULL, 0);
711188942SthompsaMODULE_DEPEND(umass, usb, 1, 1, 1);
712184610SalfredMODULE_DEPEND(umass, cam, 1, 1, 1);
713212122SthompsaMODULE_VERSION(umass, 1);
714184610Salfred
715184610Salfred/*
716184610Salfred * USB device probe/attach/detach
717184610Salfred */
718184610Salfred
719223486Shselaskystatic const STRUCT_USB_HOST_ID __used umass_devs[] = {
720223486Shselasky	/* generic mass storage class */
721223486Shselasky	{USB_IFACE_CLASS(UICLASS_MASS),},
722223486Shselasky};
723223486Shselasky
724192052Sthompsastatic uint16_t
725192984Sthompsaumass_get_proto(struct usb_interface *iface)
726192052Sthompsa{
727192984Sthompsa	struct usb_interface_descriptor *id;
728192052Sthompsa	uint16_t retval;
729192052Sthompsa
730192052Sthompsa	retval = 0;
731192052Sthompsa
732192052Sthompsa	/* Check for a standards compliant device */
733194228Sthompsa	id = usbd_get_interface_descriptor(iface);
734192052Sthompsa	if ((id == NULL) ||
735192052Sthompsa	    (id->bInterfaceClass != UICLASS_MASS)) {
736192052Sthompsa		goto done;
737192052Sthompsa	}
738192052Sthompsa	switch (id->bInterfaceSubClass) {
739192052Sthompsa	case UISUBCLASS_SCSI:
740192052Sthompsa		retval |= UMASS_PROTO_SCSI;
741192052Sthompsa		break;
742192052Sthompsa	case UISUBCLASS_UFI:
743192052Sthompsa		retval |= UMASS_PROTO_UFI;
744192052Sthompsa		break;
745192052Sthompsa	case UISUBCLASS_RBC:
746192052Sthompsa		retval |= UMASS_PROTO_RBC;
747192052Sthompsa		break;
748192052Sthompsa	case UISUBCLASS_SFF8020I:
749192052Sthompsa	case UISUBCLASS_SFF8070I:
750192052Sthompsa		retval |= UMASS_PROTO_ATAPI;
751192052Sthompsa		break;
752192052Sthompsa	default:
753192052Sthompsa		goto done;
754192052Sthompsa	}
755192052Sthompsa
756192052Sthompsa	switch (id->bInterfaceProtocol) {
757192052Sthompsa	case UIPROTO_MASS_CBI:
758192052Sthompsa		retval |= UMASS_PROTO_CBI;
759192052Sthompsa		break;
760192052Sthompsa	case UIPROTO_MASS_CBI_I:
761192052Sthompsa		retval |= UMASS_PROTO_CBI_I;
762192052Sthompsa		break;
763192052Sthompsa	case UIPROTO_MASS_BBB_OLD:
764192052Sthompsa	case UIPROTO_MASS_BBB:
765192052Sthompsa		retval |= UMASS_PROTO_BBB;
766192052Sthompsa		break;
767192052Sthompsa	default:
768192052Sthompsa		goto done;
769192052Sthompsa	}
770192052Sthompsadone:
771192052Sthompsa	return (retval);
772192052Sthompsa}
773192052Sthompsa
774184610Salfred/*
775200886Sthompsa * Match the device we are seeing with the devices supported.
776184610Salfred */
777184610Salfredstatic struct umass_probe_proto
778192984Sthompsaumass_probe_proto(device_t dev, struct usb_attach_arg *uaa)
779184610Salfred{
780184610Salfred	struct umass_probe_proto ret;
781200886Sthompsa	uint32_t quirks = NO_QUIRKS;
782200886Sthompsa	uint32_t proto = umass_get_proto(uaa->iface);
783184610Salfred
784192052Sthompsa	memset(&ret, 0, sizeof(ret));
785222051Savg	ret.error = BUS_PROBE_GENERIC;
786184610Salfred
787200886Sthompsa	/* Search for protocol enforcement */
788184610Salfred
789200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_BBB)) {
790200886Sthompsa		proto &= ~UMASS_PROTO_WIRE;
791200886Sthompsa		proto |= UMASS_PROTO_BBB;
792200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_CBI)) {
793200886Sthompsa		proto &= ~UMASS_PROTO_WIRE;
794200886Sthompsa		proto |= UMASS_PROTO_CBI;
795200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_CBI_I)) {
796200886Sthompsa		proto &= ~UMASS_PROTO_WIRE;
797200886Sthompsa		proto |= UMASS_PROTO_CBI_I;
798200886Sthompsa	}
799184610Salfred
800200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_SCSI)) {
801200886Sthompsa		proto &= ~UMASS_PROTO_COMMAND;
802200886Sthompsa		proto |= UMASS_PROTO_SCSI;
803200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_ATAPI)) {
804200886Sthompsa		proto &= ~UMASS_PROTO_COMMAND;
805200886Sthompsa		proto |= UMASS_PROTO_ATAPI;
806200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_UFI)) {
807200886Sthompsa		proto &= ~UMASS_PROTO_COMMAND;
808200886Sthompsa		proto |= UMASS_PROTO_UFI;
809200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_RBC)) {
810200886Sthompsa		proto &= ~UMASS_PROTO_COMMAND;
811200886Sthompsa		proto |= UMASS_PROTO_RBC;
812200886Sthompsa	}
813200886Sthompsa
814200886Sthompsa	/* Check if the protocol is invalid */
815200886Sthompsa
816200886Sthompsa	if ((proto & UMASS_PROTO_COMMAND) == 0) {
817200886Sthompsa		ret.error = ENXIO;
818184610Salfred		goto done;
819184610Salfred	}
820200886Sthompsa
821200886Sthompsa	if ((proto & UMASS_PROTO_WIRE) == 0) {
822200886Sthompsa		ret.error = ENXIO;
823200886Sthompsa		goto done;
824184610Salfred	}
825184610Salfred
826200886Sthompsa	/* Search for quirks */
827200886Sthompsa
828200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_TEST_UNIT_READY))
829200886Sthompsa		quirks |= NO_TEST_UNIT_READY;
830200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_RS_CLEAR_UA))
831200886Sthompsa		quirks |= RS_NO_CLEAR_UA;
832200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_START_STOP))
833200886Sthompsa		quirks |= NO_START_STOP;
834200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_GETMAXLUN))
835200886Sthompsa		quirks |= NO_GETMAXLUN;
836200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY))
837200886Sthompsa		quirks |= NO_INQUIRY;
838200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY_EVPD))
839200886Sthompsa		quirks |= NO_INQUIRY_EVPD;
840242628Smarcel	if (usb_test_quirk(uaa, UQ_MSC_NO_PREVENT_ALLOW))
841242628Smarcel		quirks |= NO_PREVENT_ALLOW;
842200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_SYNC_CACHE))
843200886Sthompsa		quirks |= NO_SYNCHRONIZE_CACHE;
844200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_SHUTTLE_INIT))
845200886Sthompsa		quirks |= SHUTTLE_INIT;
846200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_ALT_IFACE_1))
847200886Sthompsa		quirks |= ALT_IFACE_1;
848200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_FLOPPY_SPEED))
849200886Sthompsa		quirks |= FLOPPY_SPEED;
850200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_IGNORE_RESIDUE))
851200886Sthompsa		quirks |= IGNORE_RESIDUE;
852200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_WRONG_CSWSIG))
853200886Sthompsa		quirks |= WRONG_CSWSIG;
854200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_RBC_PAD_TO_12))
855200886Sthompsa		quirks |= RBC_PAD_TO_12;
856200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_READ_CAP_OFFBY1))
857200886Sthompsa		quirks |= READ_CAPACITY_OFFBY1;
858200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_FORCE_SHORT_INQ))
859200886Sthompsa		quirks |= FORCE_SHORT_INQUIRY;
860200886Sthompsa
861184610Salfreddone:
862200886Sthompsa	ret.quirks = quirks;
863200886Sthompsa	ret.proto = proto;
864184610Salfred	return (ret);
865184610Salfred}
866184610Salfred
867184610Salfredstatic int
868184610Salfredumass_probe(device_t dev)
869184610Salfred{
870192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
871184610Salfred	struct umass_probe_proto temp;
872184610Salfred
873192499Sthompsa	if (uaa->usb_mode != USB_MODE_HOST) {
874184610Salfred		return (ENXIO);
875184610Salfred	}
876184610Salfred	temp = umass_probe_proto(dev, uaa);
877184610Salfred
878184610Salfred	return (temp.error);
879184610Salfred}
880184610Salfred
881184610Salfredstatic int
882184610Salfredumass_attach(device_t dev)
883184610Salfred{
884184610Salfred	struct umass_softc *sc = device_get_softc(dev);
885192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
886184610Salfred	struct umass_probe_proto temp = umass_probe_proto(dev, uaa);
887192984Sthompsa	struct usb_interface_descriptor *id;
888244491Shselasky	int err;
889184610Salfred
890184610Salfred	/*
891227461Shselasky	 * NOTE: the softc struct is cleared in device_set_driver.
892184610Salfred	 * We can safely call umass_detach without specifically
893184610Salfred	 * initializing the struct.
894184610Salfred	 */
895184610Salfred
896184610Salfred	sc->sc_dev = dev;
897184610Salfred	sc->sc_udev = uaa->device;
898184610Salfred	sc->sc_proto = temp.proto;
899184610Salfred	sc->sc_quirks = temp.quirks;
900184610Salfred	sc->sc_unit = device_get_unit(dev);
901184610Salfred
902184610Salfred	snprintf(sc->sc_name, sizeof(sc->sc_name),
903184610Salfred	    "%s", device_get_nameunit(dev));
904184610Salfred
905194228Sthompsa	device_set_usb_desc(dev);
906184610Salfred
907188415Sthompsa        mtx_init(&sc->sc_mtx, device_get_nameunit(dev),
908188415Sthompsa	    NULL, MTX_DEF | MTX_RECURSE);
909188415Sthompsa
910184610Salfred	/* get interface index */
911184610Salfred
912194228Sthompsa	id = usbd_get_interface_descriptor(uaa->iface);
913184610Salfred	if (id == NULL) {
914184610Salfred		device_printf(dev, "failed to get "
915184610Salfred		    "interface number\n");
916184610Salfred		goto detach;
917184610Salfred	}
918184610Salfred	sc->sc_iface_no = id->bInterfaceNumber;
919184610Salfred
920207077Sthompsa#ifdef USB_DEBUG
921184610Salfred	device_printf(dev, " ");
922184610Salfred
923184610Salfred	switch (sc->sc_proto & UMASS_PROTO_COMMAND) {
924184610Salfred	case UMASS_PROTO_SCSI:
925184610Salfred		printf("SCSI");
926184610Salfred		break;
927184610Salfred	case UMASS_PROTO_ATAPI:
928184610Salfred		printf("8070i (ATAPI)");
929184610Salfred		break;
930184610Salfred	case UMASS_PROTO_UFI:
931184610Salfred		printf("UFI");
932184610Salfred		break;
933184610Salfred	case UMASS_PROTO_RBC:
934184610Salfred		printf("RBC");
935184610Salfred		break;
936184610Salfred	default:
937184610Salfred		printf("(unknown 0x%02x)",
938184610Salfred		    sc->sc_proto & UMASS_PROTO_COMMAND);
939184610Salfred		break;
940184610Salfred	}
941184610Salfred
942184610Salfred	printf(" over ");
943184610Salfred
944184610Salfred	switch (sc->sc_proto & UMASS_PROTO_WIRE) {
945184610Salfred	case UMASS_PROTO_BBB:
946184610Salfred		printf("Bulk-Only");
947184610Salfred		break;
948184610Salfred	case UMASS_PROTO_CBI:		/* uses Comand/Bulk pipes */
949184610Salfred		printf("CBI");
950184610Salfred		break;
951184610Salfred	case UMASS_PROTO_CBI_I:	/* uses Comand/Bulk/Interrupt pipes */
952184610Salfred		printf("CBI with CCI");
953184610Salfred		break;
954184610Salfred	default:
955184610Salfred		printf("(unknown 0x%02x)",
956184610Salfred		    sc->sc_proto & UMASS_PROTO_WIRE);
957184610Salfred	}
958184610Salfred
959184610Salfred	printf("; quirks = 0x%04x\n", sc->sc_quirks);
960184610Salfred#endif
961184610Salfred
962184610Salfred	if (sc->sc_quirks & ALT_IFACE_1) {
963194228Sthompsa		err = usbd_set_alt_interface_index
964184610Salfred		    (uaa->device, uaa->info.bIfaceIndex, 1);
965184610Salfred
966184610Salfred		if (err) {
967184610Salfred			DPRINTF(sc, UDMASS_USB, "could not switch to "
968184610Salfred			    "Alt Interface 1\n");
969184610Salfred			goto detach;
970184610Salfred		}
971184610Salfred	}
972184610Salfred	/* allocate all required USB transfers */
973184610Salfred
974184610Salfred	if (sc->sc_proto & UMASS_PROTO_BBB) {
975184610Salfred
976194228Sthompsa		err = usbd_transfer_setup(uaa->device,
977184610Salfred		    &uaa->info.bIfaceIndex, sc->sc_xfer, umass_bbb_config,
978188415Sthompsa		    UMASS_T_BBB_MAX, sc, &sc->sc_mtx);
979184610Salfred
980184610Salfred		/* skip reset first time */
981184610Salfred		sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
982184610Salfred
983184610Salfred	} else if (sc->sc_proto & (UMASS_PROTO_CBI | UMASS_PROTO_CBI_I)) {
984184610Salfred
985194228Sthompsa		err = usbd_transfer_setup(uaa->device,
986184610Salfred		    &uaa->info.bIfaceIndex, sc->sc_xfer, umass_cbi_config,
987203145Sthompsa		    UMASS_T_CBI_MAX, sc, &sc->sc_mtx);
988184610Salfred
989184610Salfred		/* skip reset first time */
990184610Salfred		sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
991184610Salfred
992184610Salfred	} else {
993184610Salfred		err = USB_ERR_INVAL;
994184610Salfred	}
995184610Salfred
996184610Salfred	if (err) {
997184610Salfred		device_printf(dev, "could not setup required "
998194228Sthompsa		    "transfers, %s\n", usbd_errstr(err));
999184610Salfred		goto detach;
1000184610Salfred	}
1001244491Shselasky#ifdef USB_DEBUG
1002244491Shselasky	if (umass_throttle > 0) {
1003244491Shselasky		uint8_t x;
1004244491Shselasky		int iv;
1005244491Shselasky
1006244491Shselasky		iv = umass_throttle;
1007244491Shselasky
1008244491Shselasky		if (iv < 1)
1009244491Shselasky			iv = 1;
1010244491Shselasky		else if (iv > 8000)
1011244491Shselasky			iv = 8000;
1012244491Shselasky
1013244491Shselasky		for (x = 0; x != UMASS_T_MAX; x++) {
1014244491Shselasky			if (sc->sc_xfer[x] != NULL)
1015244491Shselasky				usbd_xfer_set_interval(sc->sc_xfer[x], iv);
1016244491Shselasky		}
1017244491Shselasky	}
1018244491Shselasky#endif
1019184610Salfred	sc->sc_transform =
1020184610Salfred	    (sc->sc_proto & UMASS_PROTO_SCSI) ? &umass_scsi_transform :
1021184610Salfred	    (sc->sc_proto & UMASS_PROTO_UFI) ? &umass_ufi_transform :
1022184610Salfred	    (sc->sc_proto & UMASS_PROTO_ATAPI) ? &umass_atapi_transform :
1023184610Salfred	    (sc->sc_proto & UMASS_PROTO_RBC) ? &umass_rbc_transform :
1024184610Salfred	    &umass_no_transform;
1025184610Salfred
1026184610Salfred	/* from here onwards the device can be used. */
1027184610Salfred
1028184610Salfred	if (sc->sc_quirks & SHUTTLE_INIT) {
1029184610Salfred		umass_init_shuttle(sc);
1030184610Salfred	}
1031184610Salfred	/* get the maximum LUN supported by the device */
1032184610Salfred
1033184610Salfred	if (((sc->sc_proto & UMASS_PROTO_WIRE) == UMASS_PROTO_BBB) &&
1034184610Salfred	    !(sc->sc_quirks & NO_GETMAXLUN))
1035184610Salfred		sc->sc_maxlun = umass_bbb_get_max_lun(sc);
1036184610Salfred	else
1037184610Salfred		sc->sc_maxlun = 0;
1038184610Salfred
1039184610Salfred	/* Prepare the SCSI command block */
1040184610Salfred	sc->cam_scsi_sense.opcode = REQUEST_SENSE;
1041184610Salfred	sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY;
1042184610Salfred
1043184610Salfred	/* register the SIM */
1044184610Salfred	err = umass_cam_attach_sim(sc);
1045184610Salfred	if (err) {
1046184610Salfred		goto detach;
1047184610Salfred	}
1048184610Salfred	/* scan the SIM */
1049184610Salfred	umass_cam_attach(sc);
1050184610Salfred
1051184610Salfred	DPRINTF(sc, UDMASS_GEN, "Attach finished\n");
1052184610Salfred
1053184610Salfred	return (0);			/* success */
1054184610Salfred
1055184610Salfreddetach:
1056184610Salfred	umass_detach(dev);
1057184610Salfred	return (ENXIO);			/* failure */
1058184610Salfred}
1059184610Salfred
1060184610Salfredstatic int
1061184610Salfredumass_detach(device_t dev)
1062184610Salfred{
1063184610Salfred	struct umass_softc *sc = device_get_softc(dev);
1064184610Salfred
1065184610Salfred	DPRINTF(sc, UDMASS_USB, "\n");
1066184610Salfred
1067184610Salfred	/* teardown our statemachine */
1068184610Salfred
1069194228Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, UMASS_T_MAX);
1070184610Salfred
1071188415Sthompsa	mtx_lock(&sc->sc_mtx);
1072232358Shselasky
1073232358Shselasky	/* cancel any leftover CCB's */
1074232358Shselasky
1075232358Shselasky	umass_cancel_ccb(sc);
1076232358Shselasky
1077184610Salfred	umass_cam_detach_sim(sc);
1078184610Salfred
1079188415Sthompsa	mtx_unlock(&sc->sc_mtx);
1080232361Shselasky
1081199061Sthompsa	mtx_destroy(&sc->sc_mtx);
1082184610Salfred
1083184610Salfred	return (0);			/* success */
1084184610Salfred}
1085184610Salfred
1086184610Salfredstatic void
1087184610Salfredumass_init_shuttle(struct umass_softc *sc)
1088184610Salfred{
1089192984Sthompsa	struct usb_device_request req;
1090193045Sthompsa	usb_error_t err;
1091184610Salfred	uint8_t status[2] = {0, 0};
1092184610Salfred
1093184610Salfred	/*
1094184610Salfred	 * The Linux driver does this, but no one can tell us what the
1095184610Salfred	 * command does.
1096184610Salfred	 */
1097184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1098184610Salfred	req.bRequest = 1;		/* XXX unknown command */
1099184610Salfred	USETW(req.wValue, 0);
1100184610Salfred	req.wIndex[0] = sc->sc_iface_no;
1101184610Salfred	req.wIndex[1] = 0;
1102184610Salfred	USETW(req.wLength, sizeof(status));
1103194228Sthompsa	err = usbd_do_request(sc->sc_udev, NULL, &req, &status);
1104184610Salfred
1105184610Salfred	DPRINTF(sc, UDMASS_GEN, "Shuttle init returned 0x%02x%02x\n",
1106184610Salfred	    status[0], status[1]);
1107184610Salfred}
1108184610Salfred
1109184610Salfred/*
1110184610Salfred * Generic functions to handle transfers
1111184610Salfred */
1112184610Salfred
1113184610Salfredstatic void
1114184610Salfredumass_transfer_start(struct umass_softc *sc, uint8_t xfer_index)
1115184610Salfred{
1116184610Salfred	DPRINTF(sc, UDMASS_GEN, "transfer index = "
1117184610Salfred	    "%d\n", xfer_index);
1118184610Salfred
1119184610Salfred	if (sc->sc_xfer[xfer_index]) {
1120184610Salfred		sc->sc_last_xfer_index = xfer_index;
1121194228Sthompsa		usbd_transfer_start(sc->sc_xfer[xfer_index]);
1122184610Salfred	} else {
1123184610Salfred		umass_cancel_ccb(sc);
1124184610Salfred	}
1125184610Salfred}
1126184610Salfred
1127184610Salfredstatic void
1128184610Salfredumass_reset(struct umass_softc *sc)
1129184610Salfred{
1130184610Salfred	DPRINTF(sc, UDMASS_GEN, "resetting device\n");
1131184610Salfred
1132184610Salfred	/*
1133184610Salfred	 * stop the last transfer, if not already stopped:
1134184610Salfred	 */
1135194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[sc->sc_last_xfer_index]);
1136184610Salfred	umass_transfer_start(sc, 0);
1137184610Salfred}
1138184610Salfred
1139184610Salfredstatic void
1140184610Salfredumass_cancel_ccb(struct umass_softc *sc)
1141184610Salfred{
1142184610Salfred	union ccb *ccb;
1143184610Salfred
1144188415Sthompsa	mtx_assert(&sc->sc_mtx, MA_OWNED);
1145184610Salfred
1146184610Salfred	ccb = sc->sc_transfer.ccb;
1147184610Salfred	sc->sc_transfer.ccb = NULL;
1148184610Salfred	sc->sc_last_xfer_index = 0;
1149184610Salfred
1150184610Salfred	if (ccb) {
1151184610Salfred		(sc->sc_transfer.callback)
1152184610Salfred		    (sc, ccb, (sc->sc_transfer.data_len -
1153184610Salfred		    sc->sc_transfer.actlen), STATUS_WIRE_FAILED);
1154184610Salfred	}
1155184610Salfred}
1156184610Salfred
1157184610Salfredstatic void
1158194677Sthompsaumass_tr_error(struct usb_xfer *xfer, usb_error_t error)
1159184610Salfred{
1160194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1161184610Salfred
1162194677Sthompsa	if (error != USB_ERR_CANCELLED) {
1163184610Salfred
1164184610Salfred		DPRINTF(sc, UDMASS_GEN, "transfer error, %s -> "
1165194677Sthompsa		    "reset\n", usbd_errstr(error));
1166184610Salfred	}
1167184610Salfred	umass_cancel_ccb(sc);
1168184610Salfred}
1169184610Salfred
1170184610Salfred/*
1171184610Salfred * BBB protocol specific functions
1172184610Salfred */
1173184610Salfred
1174184610Salfredstatic void
1175194677Sthompsaumass_t_bbb_reset1_callback(struct usb_xfer *xfer, usb_error_t error)
1176184610Salfred{
1177194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1178192984Sthompsa	struct usb_device_request req;
1179194677Sthompsa	struct usb_page_cache *pc;
1180184610Salfred
1181184610Salfred	switch (USB_GET_STATE(xfer)) {
1182184610Salfred	case USB_ST_TRANSFERRED:
1183184610Salfred		umass_transfer_start(sc, UMASS_T_BBB_RESET2);
1184184610Salfred		return;
1185184610Salfred
1186184610Salfred	case USB_ST_SETUP:
1187184610Salfred		/*
1188184610Salfred		 * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
1189184610Salfred		 *
1190184610Salfred		 * For Reset Recovery the host shall issue in the following order:
1191184610Salfred		 * a) a Bulk-Only Mass Storage Reset
1192184610Salfred		 * b) a Clear Feature HALT to the Bulk-In endpoint
1193184610Salfred		 * c) a Clear Feature HALT to the Bulk-Out endpoint
1194184610Salfred		 *
1195184610Salfred		 * This is done in 3 steps, using 3 transfers:
1196184610Salfred		 * UMASS_T_BBB_RESET1
1197184610Salfred		 * UMASS_T_BBB_RESET2
1198184610Salfred		 * UMASS_T_BBB_RESET3
1199184610Salfred		 */
1200184610Salfred
1201184610Salfred		DPRINTF(sc, UDMASS_BBB, "BBB reset!\n");
1202184610Salfred
1203184610Salfred		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1204184610Salfred		req.bRequest = UR_BBB_RESET;	/* bulk only reset */
1205184610Salfred		USETW(req.wValue, 0);
1206184610Salfred		req.wIndex[0] = sc->sc_iface_no;
1207184610Salfred		req.wIndex[1] = 0;
1208184610Salfred		USETW(req.wLength, 0);
1209184610Salfred
1210194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1211194677Sthompsa		usbd_copy_in(pc, 0, &req, sizeof(req));
1212184610Salfred
1213194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1214194677Sthompsa		usbd_xfer_set_frames(xfer, 1);
1215194228Sthompsa		usbd_transfer_submit(xfer);
1216184610Salfred		return;
1217184610Salfred
1218184610Salfred	default:			/* Error */
1219194677Sthompsa		umass_tr_error(xfer, error);
1220184610Salfred		return;
1221184610Salfred	}
1222184610Salfred}
1223184610Salfred
1224184610Salfredstatic void
1225194677Sthompsaumass_t_bbb_reset2_callback(struct usb_xfer *xfer, usb_error_t error)
1226184610Salfred{
1227184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_RESET3,
1228194677Sthompsa	    UMASS_T_BBB_DATA_READ, error);
1229184610Salfred}
1230184610Salfred
1231184610Salfredstatic void
1232194677Sthompsaumass_t_bbb_reset3_callback(struct usb_xfer *xfer, usb_error_t error)
1233184610Salfred{
1234184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_COMMAND,
1235194677Sthompsa	    UMASS_T_BBB_DATA_WRITE, error);
1236184610Salfred}
1237184610Salfred
1238184610Salfredstatic void
1239192984Sthompsaumass_t_bbb_data_clear_stall_callback(struct usb_xfer *xfer,
1240194677Sthompsa    uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error)
1241184610Salfred{
1242194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1243184610Salfred
1244184610Salfred	switch (USB_GET_STATE(xfer)) {
1245184610Salfred	case USB_ST_TRANSFERRED:
1246184610Salfredtr_transferred:
1247184610Salfred		umass_transfer_start(sc, next_xfer);
1248184610Salfred		return;
1249184610Salfred
1250184610Salfred	case USB_ST_SETUP:
1251194228Sthompsa		if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) {
1252184610Salfred			goto tr_transferred;
1253184610Salfred		}
1254184610Salfred		return;
1255184610Salfred
1256184610Salfred	default:			/* Error */
1257194677Sthompsa		umass_tr_error(xfer, error);
1258184610Salfred		return;
1259184610Salfred	}
1260184610Salfred}
1261184610Salfred
1262184610Salfredstatic void
1263194677Sthompsaumass_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
1264184610Salfred{
1265194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1266184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
1267194677Sthompsa	struct usb_page_cache *pc;
1268184610Salfred	uint32_t tag;
1269184610Salfred
1270184610Salfred	switch (USB_GET_STATE(xfer)) {
1271184610Salfred	case USB_ST_TRANSFERRED:
1272184610Salfred		umass_transfer_start
1273184610Salfred		    (sc, ((sc->sc_transfer.dir == DIR_IN) ? UMASS_T_BBB_DATA_READ :
1274184610Salfred		    (sc->sc_transfer.dir == DIR_OUT) ? UMASS_T_BBB_DATA_WRITE :
1275184610Salfred		    UMASS_T_BBB_STATUS));
1276184610Salfred		return;
1277184610Salfred
1278184610Salfred	case USB_ST_SETUP:
1279184610Salfred
1280184610Salfred		sc->sc_status_try = 0;
1281184610Salfred
1282184610Salfred		if (ccb) {
1283184610Salfred
1284184610Salfred			/*
1285184610Salfred		         * the initial value is not important,
1286184610Salfred		         * as long as the values are unique:
1287184610Salfred		         */
1288184610Salfred			tag = UGETDW(sc->cbw.dCBWTag) + 1;
1289184610Salfred
1290184610Salfred			USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE);
1291184610Salfred			USETDW(sc->cbw.dCBWTag, tag);
1292184610Salfred
1293184610Salfred			/*
1294184610Salfred		         * dCBWDataTransferLength:
1295184610Salfred		         *   This field indicates the number of bytes of data that the host
1296184610Salfred		         *   intends to transfer on the IN or OUT Bulk endpoint(as indicated by
1297184610Salfred		         *   the Direction bit) during the execution of this command. If this
1298184610Salfred		         *   field is set to 0, the device will expect that no data will be
1299184610Salfred		         *   transferred IN or OUT during this command, regardless of the value
1300184610Salfred		         *   of the Direction bit defined in dCBWFlags.
1301184610Salfred		         */
1302184610Salfred			USETDW(sc->cbw.dCBWDataTransferLength, sc->sc_transfer.data_len);
1303184610Salfred
1304184610Salfred			/*
1305184610Salfred		         * dCBWFlags:
1306184610Salfred		         *   The bits of the Flags field are defined as follows:
1307184610Salfred		         *     Bits 0-6  reserved
1308184610Salfred		         *     Bit  7    Direction - this bit shall be ignored if the
1309184610Salfred		         *                           dCBWDataTransferLength field is zero.
1310184610Salfred		         *               0 = data Out from host to device
1311184610Salfred		         *               1 = data In from device to host
1312184610Salfred		         */
1313184610Salfred			sc->cbw.bCBWFlags = ((sc->sc_transfer.dir == DIR_IN) ?
1314184610Salfred			    CBWFLAGS_IN : CBWFLAGS_OUT);
1315184610Salfred			sc->cbw.bCBWLUN = sc->sc_transfer.lun;
1316184610Salfred
1317184610Salfred			if (sc->sc_transfer.cmd_len > sizeof(sc->cbw.CBWCDB)) {
1318184610Salfred				sc->sc_transfer.cmd_len = sizeof(sc->cbw.CBWCDB);
1319184610Salfred				DPRINTF(sc, UDMASS_BBB, "Truncating long command!\n");
1320184610Salfred			}
1321184610Salfred			sc->cbw.bCDBLength = sc->sc_transfer.cmd_len;
1322184610Salfred
1323227461Shselasky			memcpy(sc->cbw.CBWCDB, sc->sc_transfer.cmd_data,
1324184610Salfred			    sc->sc_transfer.cmd_len);
1325184610Salfred
1326227461Shselasky			memset(sc->sc_transfer.cmd_data +
1327227461Shselasky			    sc->sc_transfer.cmd_len, 0,
1328227461Shselasky			    sizeof(sc->cbw.CBWCDB) -
1329227461Shselasky			    sc->sc_transfer.cmd_len);
1330184610Salfred
1331184610Salfred			DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw));
1332184610Salfred
1333194677Sthompsa			pc = usbd_xfer_get_frame(xfer, 0);
1334194677Sthompsa			usbd_copy_in(pc, 0, &sc->cbw, sizeof(sc->cbw));
1335194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, sizeof(sc->cbw));
1336184610Salfred
1337194228Sthompsa			usbd_transfer_submit(xfer);
1338184610Salfred		}
1339184610Salfred		return;
1340184610Salfred
1341184610Salfred	default:			/* Error */
1342194677Sthompsa		umass_tr_error(xfer, error);
1343184610Salfred		return;
1344184610Salfred	}
1345184610Salfred}
1346184610Salfred
1347184610Salfredstatic void
1348194677Sthompsaumass_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
1349184610Salfred{
1350194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1351194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1352194677Sthompsa	int actlen, sumlen;
1353184610Salfred
1354194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1355194677Sthompsa
1356184610Salfred	switch (USB_GET_STATE(xfer)) {
1357184610Salfred	case USB_ST_TRANSFERRED:
1358194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
1359194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
1360194677Sthompsa		sc->sc_transfer.actlen += actlen;
1361184610Salfred
1362194677Sthompsa		if (actlen < sumlen) {
1363184610Salfred			/* short transfer */
1364184610Salfred			sc->sc_transfer.data_rem = 0;
1365184610Salfred		}
1366184610Salfred	case USB_ST_SETUP:
1367184610Salfred		DPRINTF(sc, UDMASS_BBB, "max_bulk=%d, data_rem=%d\n",
1368184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
1369184610Salfred
1370184610Salfred		if (sc->sc_transfer.data_rem == 0) {
1371184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_STATUS);
1372184610Salfred			return;
1373184610Salfred		}
1374184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
1375184610Salfred			max_bulk = sc->sc_transfer.data_rem;
1376184610Salfred		}
1377194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1378184610Salfred
1379194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1380194677Sthompsa		    max_bulk);
1381232361Shselasky
1382194228Sthompsa		usbd_transfer_submit(xfer);
1383184610Salfred		return;
1384184610Salfred
1385184610Salfred	default:			/* Error */
1386194677Sthompsa		if (error == USB_ERR_CANCELLED) {
1387194677Sthompsa			umass_tr_error(xfer, error);
1388184610Salfred		} else {
1389184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS);
1390184610Salfred		}
1391184610Salfred		return;
1392184610Salfred	}
1393184610Salfred}
1394184610Salfred
1395184610Salfredstatic void
1396194677Sthompsaumass_t_bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1397184610Salfred{
1398184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS,
1399194677Sthompsa	    UMASS_T_BBB_DATA_READ, error);
1400184610Salfred}
1401184610Salfred
1402184610Salfredstatic void
1403194677Sthompsaumass_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
1404184610Salfred{
1405194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1406194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1407194677Sthompsa	int actlen, sumlen;
1408184610Salfred
1409194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1410194677Sthompsa
1411184610Salfred	switch (USB_GET_STATE(xfer)) {
1412184610Salfred	case USB_ST_TRANSFERRED:
1413194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
1414194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
1415194677Sthompsa		sc->sc_transfer.actlen += actlen;
1416184610Salfred
1417194677Sthompsa		if (actlen < sumlen) {
1418184610Salfred			/* short transfer */
1419184610Salfred			sc->sc_transfer.data_rem = 0;
1420184610Salfred		}
1421184610Salfred	case USB_ST_SETUP:
1422184610Salfred		DPRINTF(sc, UDMASS_BBB, "max_bulk=%d, data_rem=%d\n",
1423184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
1424184610Salfred
1425184610Salfred		if (sc->sc_transfer.data_rem == 0) {
1426184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_STATUS);
1427184610Salfred			return;
1428184610Salfred		}
1429184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
1430184610Salfred			max_bulk = sc->sc_transfer.data_rem;
1431184610Salfred		}
1432194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1433184610Salfred
1434194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1435194677Sthompsa		    max_bulk);
1436184610Salfred
1437194228Sthompsa		usbd_transfer_submit(xfer);
1438184610Salfred		return;
1439184610Salfred
1440184610Salfred	default:			/* Error */
1441194677Sthompsa		if (error == USB_ERR_CANCELLED) {
1442194677Sthompsa			umass_tr_error(xfer, error);
1443184610Salfred		} else {
1444184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_DATA_WR_CS);
1445184610Salfred		}
1446184610Salfred		return;
1447184610Salfred	}
1448184610Salfred}
1449184610Salfred
1450184610Salfredstatic void
1451194677Sthompsaumass_t_bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1452184610Salfred{
1453184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS,
1454194677Sthompsa	    UMASS_T_BBB_DATA_WRITE, error);
1455184610Salfred}
1456184610Salfred
1457184610Salfredstatic void
1458194677Sthompsaumass_t_bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
1459184610Salfred{
1460194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1461184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
1462194677Sthompsa	struct usb_page_cache *pc;
1463184610Salfred	uint32_t residue;
1464194677Sthompsa	int actlen;
1465184610Salfred
1466194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1467194677Sthompsa
1468184610Salfred	switch (USB_GET_STATE(xfer)) {
1469184610Salfred	case USB_ST_TRANSFERRED:
1470184610Salfred
1471184610Salfred		/*
1472184610Salfred		 * Do a full reset if there is something wrong with the CSW:
1473184610Salfred		 */
1474184610Salfred		sc->sc_status_try = 1;
1475184610Salfred
1476184610Salfred		/* Zero missing parts of the CSW: */
1477184610Salfred
1478233774Shselasky		if (actlen < (int)sizeof(sc->csw))
1479227461Shselasky			memset(&sc->csw, 0, sizeof(sc->csw));
1480227461Shselasky
1481194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1482194677Sthompsa		usbd_copy_out(pc, 0, &sc->csw, actlen);
1483184610Salfred
1484184610Salfred		DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw));
1485184610Salfred
1486184610Salfred		residue = UGETDW(sc->csw.dCSWDataResidue);
1487184610Salfred
1488189905Sthompsa		if ((!residue) || (sc->sc_quirks & IGNORE_RESIDUE)) {
1489184610Salfred			residue = (sc->sc_transfer.data_len -
1490184610Salfred			    sc->sc_transfer.actlen);
1491184610Salfred		}
1492184610Salfred		if (residue > sc->sc_transfer.data_len) {
1493184610Salfred			DPRINTF(sc, UDMASS_BBB, "truncating residue from %d "
1494184610Salfred			    "to %d bytes\n", residue, sc->sc_transfer.data_len);
1495184610Salfred			residue = sc->sc_transfer.data_len;
1496184610Salfred		}
1497184610Salfred		/* translate weird command-status signatures: */
1498184610Salfred		if (sc->sc_quirks & WRONG_CSWSIG) {
1499184610Salfred
1500184610Salfred			uint32_t temp = UGETDW(sc->csw.dCSWSignature);
1501184610Salfred
1502184610Salfred			if ((temp == CSWSIGNATURE_OLYMPUS_C1) ||
1503184610Salfred			    (temp == CSWSIGNATURE_IMAGINATION_DBX1)) {
1504184610Salfred				USETDW(sc->csw.dCSWSignature, CSWSIGNATURE);
1505184610Salfred			}
1506184610Salfred		}
1507184610Salfred		/* check CSW and handle eventual error */
1508184610Salfred		if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) {
1509184610Salfred			DPRINTF(sc, UDMASS_BBB, "bad CSW signature 0x%08x != 0x%08x\n",
1510184610Salfred			    UGETDW(sc->csw.dCSWSignature), CSWSIGNATURE);
1511184610Salfred			/*
1512184610Salfred			 * Invalid CSW: Wrong signature or wrong tag might
1513184610Salfred			 * indicate that we lost synchronization. Reset the
1514184610Salfred			 * device.
1515184610Salfred			 */
1516184610Salfred			goto tr_error;
1517184610Salfred		} else if (UGETDW(sc->csw.dCSWTag) != UGETDW(sc->cbw.dCBWTag)) {
1518184610Salfred			DPRINTF(sc, UDMASS_BBB, "Invalid CSW: tag 0x%08x should be "
1519184610Salfred			    "0x%08x\n", UGETDW(sc->csw.dCSWTag),
1520184610Salfred			    UGETDW(sc->cbw.dCBWTag));
1521184610Salfred			goto tr_error;
1522184610Salfred		} else if (sc->csw.bCSWStatus > CSWSTATUS_PHASE) {
1523184610Salfred			DPRINTF(sc, UDMASS_BBB, "Invalid CSW: status %d > %d\n",
1524184610Salfred			    sc->csw.bCSWStatus, CSWSTATUS_PHASE);
1525184610Salfred			goto tr_error;
1526184610Salfred		} else if (sc->csw.bCSWStatus == CSWSTATUS_PHASE) {
1527184610Salfred			DPRINTF(sc, UDMASS_BBB, "Phase error, residue = "
1528184610Salfred			    "%d\n", residue);
1529184610Salfred			goto tr_error;
1530184610Salfred		} else if (sc->sc_transfer.actlen > sc->sc_transfer.data_len) {
1531184610Salfred			DPRINTF(sc, UDMASS_BBB, "Buffer overrun %d > %d\n",
1532184610Salfred			    sc->sc_transfer.actlen, sc->sc_transfer.data_len);
1533184610Salfred			goto tr_error;
1534184610Salfred		} else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) {
1535184610Salfred			DPRINTF(sc, UDMASS_BBB, "Command failed, residue = "
1536184610Salfred			    "%d\n", residue);
1537184610Salfred
1538184610Salfred			sc->sc_transfer.ccb = NULL;
1539184610Salfred
1540184610Salfred			sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
1541184610Salfred
1542184610Salfred			(sc->sc_transfer.callback)
1543184610Salfred			    (sc, ccb, residue, STATUS_CMD_FAILED);
1544184610Salfred		} else {
1545184610Salfred			sc->sc_transfer.ccb = NULL;
1546184610Salfred
1547184610Salfred			sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
1548184610Salfred
1549184610Salfred			(sc->sc_transfer.callback)
1550184610Salfred			    (sc, ccb, residue, STATUS_CMD_OK);
1551184610Salfred		}
1552184610Salfred		return;
1553184610Salfred
1554184610Salfred	case USB_ST_SETUP:
1555194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
1556194228Sthompsa		usbd_transfer_submit(xfer);
1557184610Salfred		return;
1558184610Salfred
1559184610Salfred	default:
1560184610Salfredtr_error:
1561184610Salfred		DPRINTF(sc, UDMASS_BBB, "Failed to read CSW: %s, try %d\n",
1562194677Sthompsa		    usbd_errstr(error), sc->sc_status_try);
1563184610Salfred
1564194677Sthompsa		if ((error == USB_ERR_CANCELLED) ||
1565184610Salfred		    (sc->sc_status_try)) {
1566194677Sthompsa			umass_tr_error(xfer, error);
1567184610Salfred		} else {
1568184610Salfred			sc->sc_status_try = 1;
1569184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS);
1570184610Salfred		}
1571184610Salfred		return;
1572184610Salfred	}
1573184610Salfred}
1574184610Salfred
1575184610Salfredstatic void
1576184610Salfredumass_command_start(struct umass_softc *sc, uint8_t dir,
1577184610Salfred    void *data_ptr, uint32_t data_len,
1578184610Salfred    uint32_t data_timeout, umass_callback_t *callback,
1579184610Salfred    union ccb *ccb)
1580184610Salfred{
1581184610Salfred	sc->sc_transfer.lun = ccb->ccb_h.target_lun;
1582184610Salfred
1583184610Salfred	/*
1584184610Salfred	 * NOTE: assumes that "sc->sc_transfer.cmd_data" and
1585184610Salfred	 * "sc->sc_transfer.cmd_len" has been properly
1586184610Salfred	 * initialized.
1587184610Salfred	 */
1588184610Salfred
1589184610Salfred	sc->sc_transfer.dir = data_len ? dir : DIR_NONE;
1590184610Salfred	sc->sc_transfer.data_ptr = data_ptr;
1591184610Salfred	sc->sc_transfer.data_len = data_len;
1592184610Salfred	sc->sc_transfer.data_rem = data_len;
1593184610Salfred	sc->sc_transfer.data_timeout = (data_timeout + UMASS_TIMEOUT);
1594184610Salfred
1595184610Salfred	sc->sc_transfer.actlen = 0;
1596184610Salfred	sc->sc_transfer.callback = callback;
1597184610Salfred	sc->sc_transfer.ccb = ccb;
1598184610Salfred
1599184610Salfred	if (sc->sc_xfer[sc->sc_last_xfer_index]) {
1600194228Sthompsa		usbd_transfer_start(sc->sc_xfer[sc->sc_last_xfer_index]);
1601184610Salfred	} else {
1602232358Shselasky		umass_cancel_ccb(sc);
1603184610Salfred	}
1604184610Salfred}
1605184610Salfred
1606184610Salfredstatic uint8_t
1607184610Salfredumass_bbb_get_max_lun(struct umass_softc *sc)
1608184610Salfred{
1609192984Sthompsa	struct usb_device_request req;
1610193045Sthompsa	usb_error_t err;
1611184610Salfred	uint8_t buf = 0;
1612184610Salfred
1613184610Salfred	/* The Get Max Lun command is a class-specific request. */
1614184610Salfred	req.bmRequestType = UT_READ_CLASS_INTERFACE;
1615184610Salfred	req.bRequest = UR_BBB_GET_MAX_LUN;
1616184610Salfred	USETW(req.wValue, 0);
1617184610Salfred	req.wIndex[0] = sc->sc_iface_no;
1618184610Salfred	req.wIndex[1] = 0;
1619184610Salfred	USETW(req.wLength, 1);
1620184610Salfred
1621194228Sthompsa	err = usbd_do_request(sc->sc_udev, NULL, &req, &buf);
1622184610Salfred	if (err) {
1623184610Salfred		buf = 0;
1624184610Salfred
1625184610Salfred		/* Device doesn't support Get Max Lun request. */
1626184610Salfred		printf("%s: Get Max Lun not supported (%s)\n",
1627194228Sthompsa		    sc->sc_name, usbd_errstr(err));
1628184610Salfred	}
1629184610Salfred	return (buf);
1630184610Salfred}
1631184610Salfred
1632184610Salfred/*
1633184610Salfred * Command/Bulk/Interrupt (CBI) specific functions
1634184610Salfred */
1635184610Salfred
1636184610Salfredstatic void
1637184610Salfredumass_cbi_start_status(struct umass_softc *sc)
1638184610Salfred{
1639184610Salfred	if (sc->sc_xfer[UMASS_T_CBI_STATUS]) {
1640184610Salfred		umass_transfer_start(sc, UMASS_T_CBI_STATUS);
1641184610Salfred	} else {
1642184610Salfred		union ccb *ccb = sc->sc_transfer.ccb;
1643184610Salfred
1644184610Salfred		sc->sc_transfer.ccb = NULL;
1645184610Salfred
1646184610Salfred		sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
1647184610Salfred
1648184610Salfred		(sc->sc_transfer.callback)
1649184610Salfred		    (sc, ccb, (sc->sc_transfer.data_len -
1650184610Salfred		    sc->sc_transfer.actlen), STATUS_CMD_UNKNOWN);
1651184610Salfred	}
1652184610Salfred}
1653184610Salfred
1654184610Salfredstatic void
1655194677Sthompsaumass_t_cbi_reset1_callback(struct usb_xfer *xfer, usb_error_t error)
1656184610Salfred{
1657194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1658192984Sthompsa	struct usb_device_request req;
1659194677Sthompsa	struct usb_page_cache *pc;
1660184610Salfred	uint8_t buf[UMASS_CBI_DIAGNOSTIC_CMDLEN];
1661184610Salfred
1662184610Salfred	uint8_t i;
1663184610Salfred
1664184610Salfred	switch (USB_GET_STATE(xfer)) {
1665184610Salfred	case USB_ST_TRANSFERRED:
1666184610Salfred		umass_transfer_start(sc, UMASS_T_CBI_RESET2);
1667203145Sthompsa		break;
1668184610Salfred
1669184610Salfred	case USB_ST_SETUP:
1670184610Salfred		/*
1671184610Salfred		 * Command Block Reset Protocol
1672184610Salfred		 *
1673184610Salfred		 * First send a reset request to the device. Then clear
1674184610Salfred		 * any possibly stalled bulk endpoints.
1675184610Salfred		 *
1676184610Salfred		 * This is done in 3 steps, using 3 transfers:
1677184610Salfred		 * UMASS_T_CBI_RESET1
1678184610Salfred		 * UMASS_T_CBI_RESET2
1679184610Salfred		 * UMASS_T_CBI_RESET3
1680184610Salfred		 * UMASS_T_CBI_RESET4 (only if there is an interrupt endpoint)
1681184610Salfred		 */
1682184610Salfred
1683184610Salfred		DPRINTF(sc, UDMASS_CBI, "CBI reset!\n");
1684184610Salfred
1685184610Salfred		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1686184610Salfred		req.bRequest = UR_CBI_ADSC;
1687184610Salfred		USETW(req.wValue, 0);
1688184610Salfred		req.wIndex[0] = sc->sc_iface_no;
1689184610Salfred		req.wIndex[1] = 0;
1690184610Salfred		USETW(req.wLength, UMASS_CBI_DIAGNOSTIC_CMDLEN);
1691184610Salfred
1692184610Salfred		/*
1693184610Salfred		 * The 0x1d code is the SEND DIAGNOSTIC command. To
1694184610Salfred		 * distinguish between the two, the last 10 bytes of the CBL
1695184610Salfred		 * is filled with 0xff (section 2.2 of the CBI
1696184610Salfred		 * specification)
1697184610Salfred		 */
1698184610Salfred		buf[0] = 0x1d;		/* Command Block Reset */
1699184610Salfred		buf[1] = 0x04;
1700184610Salfred
1701184610Salfred		for (i = 2; i < UMASS_CBI_DIAGNOSTIC_CMDLEN; i++) {
1702184610Salfred			buf[i] = 0xff;
1703184610Salfred		}
1704184610Salfred
1705194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1706194677Sthompsa		usbd_copy_in(pc, 0, &req, sizeof(req));
1707194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 1);
1708194677Sthompsa		usbd_copy_in(pc, 0, buf, sizeof(buf));
1709184610Salfred
1710194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1711194677Sthompsa		usbd_xfer_set_frame_len(xfer, 1, sizeof(buf));
1712194677Sthompsa		usbd_xfer_set_frames(xfer, 2);
1713194228Sthompsa		usbd_transfer_submit(xfer);
1714203145Sthompsa		break;
1715184610Salfred
1716184610Salfred	default:			/* Error */
1717203145Sthompsa		if (error == USB_ERR_CANCELLED)
1718203145Sthompsa			umass_tr_error(xfer, error);
1719203145Sthompsa		else
1720203145Sthompsa			umass_transfer_start(sc, UMASS_T_CBI_RESET2);
1721203145Sthompsa		break;
1722184610Salfred	}
1723184610Salfred}
1724184610Salfred
1725184610Salfredstatic void
1726194677Sthompsaumass_t_cbi_reset2_callback(struct usb_xfer *xfer, usb_error_t error)
1727184610Salfred{
1728184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_RESET3,
1729194677Sthompsa	    UMASS_T_CBI_DATA_READ, error);
1730184610Salfred}
1731184610Salfred
1732184610Salfredstatic void
1733194677Sthompsaumass_t_cbi_reset3_callback(struct usb_xfer *xfer, usb_error_t error)
1734184610Salfred{
1735194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1736184610Salfred
1737184610Salfred	umass_t_cbi_data_clear_stall_callback
1738184610Salfred	    (xfer, (sc->sc_xfer[UMASS_T_CBI_RESET4] &&
1739184610Salfred	    sc->sc_xfer[UMASS_T_CBI_STATUS]) ?
1740184610Salfred	    UMASS_T_CBI_RESET4 : UMASS_T_CBI_COMMAND,
1741194677Sthompsa	    UMASS_T_CBI_DATA_WRITE, error);
1742184610Salfred}
1743184610Salfred
1744184610Salfredstatic void
1745194677Sthompsaumass_t_cbi_reset4_callback(struct usb_xfer *xfer, usb_error_t error)
1746184610Salfred{
1747184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_COMMAND,
1748194677Sthompsa	    UMASS_T_CBI_STATUS, error);
1749184610Salfred}
1750184610Salfred
1751184610Salfredstatic void
1752192984Sthompsaumass_t_cbi_data_clear_stall_callback(struct usb_xfer *xfer,
1753194677Sthompsa    uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error)
1754184610Salfred{
1755194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1756184610Salfred
1757184610Salfred	switch (USB_GET_STATE(xfer)) {
1758184610Salfred	case USB_ST_TRANSFERRED:
1759184610Salfredtr_transferred:
1760184610Salfred		if (next_xfer == UMASS_T_CBI_STATUS) {
1761184610Salfred			umass_cbi_start_status(sc);
1762184610Salfred		} else {
1763184610Salfred			umass_transfer_start(sc, next_xfer);
1764184610Salfred		}
1765203145Sthompsa		break;
1766184610Salfred
1767184610Salfred	case USB_ST_SETUP:
1768194228Sthompsa		if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) {
1769184610Salfred			goto tr_transferred;	/* should not happen */
1770184610Salfred		}
1771203145Sthompsa		break;
1772184610Salfred
1773184610Salfred	default:			/* Error */
1774194677Sthompsa		umass_tr_error(xfer, error);
1775203145Sthompsa		break;
1776184610Salfred	}
1777184610Salfred}
1778184610Salfred
1779184610Salfredstatic void
1780194677Sthompsaumass_t_cbi_command_callback(struct usb_xfer *xfer, usb_error_t error)
1781184610Salfred{
1782194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1783184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
1784192984Sthompsa	struct usb_device_request req;
1785194677Sthompsa	struct usb_page_cache *pc;
1786184610Salfred
1787184610Salfred	switch (USB_GET_STATE(xfer)) {
1788184610Salfred	case USB_ST_TRANSFERRED:
1789184610Salfred
1790184610Salfred		if (sc->sc_transfer.dir == DIR_NONE) {
1791184610Salfred			umass_cbi_start_status(sc);
1792184610Salfred		} else {
1793184610Salfred			umass_transfer_start
1794184610Salfred			    (sc, (sc->sc_transfer.dir == DIR_IN) ?
1795184610Salfred			    UMASS_T_CBI_DATA_READ : UMASS_T_CBI_DATA_WRITE);
1796184610Salfred		}
1797203145Sthompsa		break;
1798184610Salfred
1799184610Salfred	case USB_ST_SETUP:
1800184610Salfred
1801184610Salfred		if (ccb) {
1802184610Salfred
1803184610Salfred			/*
1804184610Salfred		         * do a CBI transfer with cmd_len bytes from
1805184610Salfred		         * cmd_data, possibly a data phase of data_len
1806184610Salfred		         * bytes from/to the device and finally a status
1807184610Salfred		         * read phase.
1808184610Salfred		         */
1809184610Salfred
1810184610Salfred			req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1811184610Salfred			req.bRequest = UR_CBI_ADSC;
1812184610Salfred			USETW(req.wValue, 0);
1813184610Salfred			req.wIndex[0] = sc->sc_iface_no;
1814184610Salfred			req.wIndex[1] = 0;
1815184610Salfred			req.wLength[0] = sc->sc_transfer.cmd_len;
1816184610Salfred			req.wLength[1] = 0;
1817184610Salfred
1818194677Sthompsa			pc = usbd_xfer_get_frame(xfer, 0);
1819194677Sthompsa			usbd_copy_in(pc, 0, &req, sizeof(req));
1820194677Sthompsa			pc = usbd_xfer_get_frame(xfer, 1);
1821194677Sthompsa			usbd_copy_in(pc, 0, sc->sc_transfer.cmd_data,
1822184610Salfred			    sc->sc_transfer.cmd_len);
1823184610Salfred
1824194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1825194677Sthompsa			usbd_xfer_set_frame_len(xfer, 1, sc->sc_transfer.cmd_len);
1826194677Sthompsa			usbd_xfer_set_frames(xfer,
1827194677Sthompsa			    sc->sc_transfer.cmd_len ? 2 : 1);
1828184610Salfred
1829184610Salfred			DIF(UDMASS_CBI,
1830184610Salfred			    umass_cbi_dump_cmd(sc,
1831184610Salfred			    sc->sc_transfer.cmd_data,
1832184610Salfred			    sc->sc_transfer.cmd_len));
1833184610Salfred
1834194228Sthompsa			usbd_transfer_submit(xfer);
1835184610Salfred		}
1836203145Sthompsa		break;
1837184610Salfred
1838184610Salfred	default:			/* Error */
1839220535Smav		/*
1840220535Smav		 * STALL on the control pipe can be result of the command error.
1841220535Smav		 * Attempt to clear this STALL same as for bulk pipe also
1842220535Smav		 * results in command completion interrupt, but ASC/ASCQ there
1843220535Smav		 * look like not always valid, so don't bother about it.
1844220535Smav		 */
1845220535Smav		if ((error == USB_ERR_STALLED) ||
1846220535Smav		    (sc->sc_transfer.callback == &umass_cam_cb)) {
1847220535Smav			sc->sc_transfer.ccb = NULL;
1848220535Smav			(sc->sc_transfer.callback)
1849220535Smav			    (sc, ccb, sc->sc_transfer.data_len,
1850220535Smav			    STATUS_CMD_UNKNOWN);
1851220535Smav		} else {
1852220535Smav			umass_tr_error(xfer, error);
1853220535Smav			/* skip reset */
1854220535Smav			sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
1855220535Smav		}
1856203145Sthompsa		break;
1857184610Salfred	}
1858184610Salfred}
1859184610Salfred
1860184610Salfredstatic void
1861194677Sthompsaumass_t_cbi_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
1862184610Salfred{
1863194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1864194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1865194677Sthompsa	int actlen, sumlen;
1866184610Salfred
1867194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1868194677Sthompsa
1869184610Salfred	switch (USB_GET_STATE(xfer)) {
1870184610Salfred	case USB_ST_TRANSFERRED:
1871194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
1872194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
1873194677Sthompsa		sc->sc_transfer.actlen += actlen;
1874184610Salfred
1875194677Sthompsa		if (actlen < sumlen) {
1876184610Salfred			/* short transfer */
1877184610Salfred			sc->sc_transfer.data_rem = 0;
1878184610Salfred		}
1879184610Salfred	case USB_ST_SETUP:
1880184610Salfred		DPRINTF(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n",
1881184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
1882184610Salfred
1883184610Salfred		if (sc->sc_transfer.data_rem == 0) {
1884184610Salfred			umass_cbi_start_status(sc);
1885203145Sthompsa			break;
1886184610Salfred		}
1887184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
1888184610Salfred			max_bulk = sc->sc_transfer.data_rem;
1889184610Salfred		}
1890194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1891184610Salfred
1892194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1893194677Sthompsa		    max_bulk);
1894232361Shselasky
1895194228Sthompsa		usbd_transfer_submit(xfer);
1896203145Sthompsa		break;
1897184610Salfred
1898184610Salfred	default:			/* Error */
1899194677Sthompsa		if ((error == USB_ERR_CANCELLED) ||
1900184610Salfred		    (sc->sc_transfer.callback != &umass_cam_cb)) {
1901194677Sthompsa			umass_tr_error(xfer, error);
1902184610Salfred		} else {
1903184610Salfred			umass_transfer_start(sc, UMASS_T_CBI_DATA_RD_CS);
1904184610Salfred		}
1905203145Sthompsa		break;
1906184610Salfred	}
1907184610Salfred}
1908184610Salfred
1909184610Salfredstatic void
1910194677Sthompsaumass_t_cbi_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1911184610Salfred{
1912184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS,
1913194677Sthompsa	    UMASS_T_CBI_DATA_READ, error);
1914184610Salfred}
1915184610Salfred
1916184610Salfredstatic void
1917194677Sthompsaumass_t_cbi_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
1918184610Salfred{
1919194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1920194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1921194677Sthompsa	int actlen, sumlen;
1922184610Salfred
1923194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1924194677Sthompsa
1925184610Salfred	switch (USB_GET_STATE(xfer)) {
1926184610Salfred	case USB_ST_TRANSFERRED:
1927194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
1928194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
1929194677Sthompsa		sc->sc_transfer.actlen += actlen;
1930184610Salfred
1931194677Sthompsa		if (actlen < sumlen) {
1932184610Salfred			/* short transfer */
1933184610Salfred			sc->sc_transfer.data_rem = 0;
1934184610Salfred		}
1935184610Salfred	case USB_ST_SETUP:
1936184610Salfred		DPRINTF(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n",
1937184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
1938184610Salfred
1939184610Salfred		if (sc->sc_transfer.data_rem == 0) {
1940184610Salfred			umass_cbi_start_status(sc);
1941203145Sthompsa			break;
1942184610Salfred		}
1943184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
1944184610Salfred			max_bulk = sc->sc_transfer.data_rem;
1945184610Salfred		}
1946194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1947184610Salfred
1948194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1949194677Sthompsa		    max_bulk);
1950184610Salfred
1951194228Sthompsa		usbd_transfer_submit(xfer);
1952203145Sthompsa		break;
1953184610Salfred
1954184610Salfred	default:			/* Error */
1955194677Sthompsa		if ((error == USB_ERR_CANCELLED) ||
1956184610Salfred		    (sc->sc_transfer.callback != &umass_cam_cb)) {
1957194677Sthompsa			umass_tr_error(xfer, error);
1958184610Salfred		} else {
1959184610Salfred			umass_transfer_start(sc, UMASS_T_CBI_DATA_WR_CS);
1960184610Salfred		}
1961203145Sthompsa		break;
1962184610Salfred	}
1963184610Salfred}
1964184610Salfred
1965184610Salfredstatic void
1966194677Sthompsaumass_t_cbi_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1967184610Salfred{
1968184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS,
1969194677Sthompsa	    UMASS_T_CBI_DATA_WRITE, error);
1970184610Salfred}
1971184610Salfred
1972184610Salfredstatic void
1973194677Sthompsaumass_t_cbi_status_callback(struct usb_xfer *xfer, usb_error_t error)
1974184610Salfred{
1975194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1976184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
1977194677Sthompsa	struct usb_page_cache *pc;
1978184610Salfred	uint32_t residue;
1979184610Salfred	uint8_t status;
1980194677Sthompsa	int actlen;
1981184610Salfred
1982194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1983194677Sthompsa
1984184610Salfred	switch (USB_GET_STATE(xfer)) {
1985184610Salfred	case USB_ST_TRANSFERRED:
1986184610Salfred
1987233774Shselasky		if (actlen < (int)sizeof(sc->sbl)) {
1988184610Salfred			goto tr_setup;
1989184610Salfred		}
1990194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1991194677Sthompsa		usbd_copy_out(pc, 0, &sc->sbl, sizeof(sc->sbl));
1992184610Salfred
1993184610Salfred		residue = (sc->sc_transfer.data_len -
1994184610Salfred		    sc->sc_transfer.actlen);
1995184610Salfred
1996184610Salfred		/* dissect the information in the buffer */
1997184610Salfred
1998184610Salfred		if (sc->sc_proto & UMASS_PROTO_UFI) {
1999184610Salfred
2000184610Salfred			/*
2001184610Salfred			 * Section 3.4.3.1.3 specifies that the UFI command
2002184610Salfred			 * protocol returns an ASC and ASCQ in the interrupt
2003184610Salfred			 * data block.
2004184610Salfred			 */
2005184610Salfred
2006184610Salfred			DPRINTF(sc, UDMASS_CBI, "UFI CCI, ASC = 0x%02x, "
2007184610Salfred			    "ASCQ = 0x%02x\n", sc->sbl.ufi.asc,
2008184610Salfred			    sc->sbl.ufi.ascq);
2009184610Salfred
2010184610Salfred			status = (((sc->sbl.ufi.asc == 0) &&
2011184610Salfred			    (sc->sbl.ufi.ascq == 0)) ?
2012184610Salfred			    STATUS_CMD_OK : STATUS_CMD_FAILED);
2013184610Salfred
2014184610Salfred			sc->sc_transfer.ccb = NULL;
2015184610Salfred
2016184610Salfred			sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
2017184610Salfred
2018184610Salfred			(sc->sc_transfer.callback)
2019184610Salfred			    (sc, ccb, residue, status);
2020184610Salfred
2021203145Sthompsa			break;
2022184610Salfred
2023184610Salfred		} else {
2024184610Salfred
2025184610Salfred			/* Command Interrupt Data Block */
2026184610Salfred
2027184610Salfred			DPRINTF(sc, UDMASS_CBI, "type=0x%02x, value=0x%02x\n",
2028184610Salfred			    sc->sbl.common.type, sc->sbl.common.value);
2029184610Salfred
2030184610Salfred			if (sc->sbl.common.type == IDB_TYPE_CCI) {
2031184610Salfred
2032184610Salfred				status = (sc->sbl.common.value & IDB_VALUE_STATUS_MASK);
2033184610Salfred
2034184610Salfred				status = ((status == IDB_VALUE_PASS) ? STATUS_CMD_OK :
2035184610Salfred				    (status == IDB_VALUE_FAIL) ? STATUS_CMD_FAILED :
2036184610Salfred				    (status == IDB_VALUE_PERSISTENT) ? STATUS_CMD_FAILED :
2037184610Salfred				    STATUS_WIRE_FAILED);
2038184610Salfred
2039184610Salfred				sc->sc_transfer.ccb = NULL;
2040184610Salfred
2041184610Salfred				sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
2042184610Salfred
2043184610Salfred				(sc->sc_transfer.callback)
2044184610Salfred				    (sc, ccb, residue, status);
2045184610Salfred
2046203145Sthompsa				break;
2047184610Salfred			}
2048184610Salfred		}
2049184610Salfred
2050184610Salfred		/* fallthrough */
2051184610Salfred
2052184610Salfred	case USB_ST_SETUP:
2053184610Salfredtr_setup:
2054194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
2055194228Sthompsa		usbd_transfer_submit(xfer);
2056203145Sthompsa		break;
2057184610Salfred
2058184610Salfred	default:			/* Error */
2059184610Salfred		DPRINTF(sc, UDMASS_CBI, "Failed to read CSW: %s\n",
2060194677Sthompsa		    usbd_errstr(error));
2061194677Sthompsa		umass_tr_error(xfer, error);
2062203145Sthompsa		break;
2063184610Salfred	}
2064184610Salfred}
2065184610Salfred
2066184610Salfred/*
2067184610Salfred * CAM specific functions (used by SCSI, UFI, 8070i (ATAPI))
2068184610Salfred */
2069184610Salfred
2070184610Salfredstatic int
2071184610Salfredumass_cam_attach_sim(struct umass_softc *sc)
2072184610Salfred{
2073184610Salfred	struct cam_devq *devq;		/* Per device Queue */
2074184610Salfred
2075184610Salfred	/*
2076184610Salfred	 * A HBA is attached to the CAM layer.
2077184610Salfred	 *
2078184610Salfred	 * The CAM layer will then after a while start probing for devices on
2079184610Salfred	 * the bus. The number of SIMs is limited to one.
2080184610Salfred	 */
2081184610Salfred
2082184610Salfred	devq = cam_simq_alloc(1 /* maximum openings */ );
2083184610Salfred	if (devq == NULL) {
2084184610Salfred		return (ENOMEM);
2085184610Salfred	}
2086184610Salfred	sc->sc_sim = cam_sim_alloc
2087184610Salfred	    (&umass_cam_action, &umass_cam_poll,
2088184610Salfred	    DEVNAME_SIM,
2089184610Salfred	    sc /* priv */ ,
2090184610Salfred	    sc->sc_unit /* unit number */ ,
2091188415Sthompsa	    &sc->sc_mtx /* mutex */ ,
2092184610Salfred	    1 /* maximum device openings */ ,
2093184610Salfred	    0 /* maximum tagged device openings */ ,
2094184610Salfred	    devq);
2095184610Salfred
2096184610Salfred	if (sc->sc_sim == NULL) {
2097184610Salfred		cam_simq_free(devq);
2098184610Salfred		return (ENOMEM);
2099184610Salfred	}
2100184610Salfred
2101188415Sthompsa	mtx_lock(&sc->sc_mtx);
2102184610Salfred
2103232361Shselasky	if (xpt_bus_register(sc->sc_sim, sc->sc_dev,
2104232361Shselasky	    sc->sc_unit) != CAM_SUCCESS) {
2105188415Sthompsa		mtx_unlock(&sc->sc_mtx);
2106184610Salfred		return (ENOMEM);
2107184610Salfred	}
2108232361Shselasky	mtx_unlock(&sc->sc_mtx);
2109184610Salfred
2110184610Salfred	return (0);
2111184610Salfred}
2112184610Salfred
2113184610Salfredstatic void
2114184610Salfredumass_cam_attach(struct umass_softc *sc)
2115184610Salfred{
2116184610Salfred#ifndef USB_DEBUG
2117184610Salfred	if (bootverbose)
2118184610Salfred#endif
2119184610Salfred		printf("%s:%d:%d:%d: Attached to scbus%d\n",
2120184610Salfred		    sc->sc_name, cam_sim_path(sc->sc_sim),
2121184610Salfred		    sc->sc_unit, CAM_LUN_WILDCARD,
2122184610Salfred		    cam_sim_path(sc->sc_sim));
2123184610Salfred}
2124184610Salfred
2125184610Salfred/* umass_cam_detach
2126184610Salfred *	detach from the CAM layer
2127184610Salfred */
2128184610Salfred
2129184610Salfredstatic void
2130184610Salfredumass_cam_detach_sim(struct umass_softc *sc)
2131184610Salfred{
2132188415Sthompsa	if (sc->sc_sim != NULL) {
2133184610Salfred		if (xpt_bus_deregister(cam_sim_path(sc->sc_sim))) {
2134184610Salfred			/* accessing the softc is not possible after this */
2135241432Smav			sc->sc_sim->softc = NULL;
2136188415Sthompsa			cam_sim_free(sc->sc_sim, /* free_devq */ TRUE);
2137184610Salfred		} else {
2138199816Sthompsa			panic("%s: CAM layer is busy\n",
2139184610Salfred			    sc->sc_name);
2140184610Salfred		}
2141184610Salfred		sc->sc_sim = NULL;
2142184610Salfred	}
2143184610Salfred}
2144184610Salfred
2145184610Salfred/* umass_cam_action
2146184610Salfred * 	CAM requests for action come through here
2147184610Salfred */
2148184610Salfred
2149184610Salfredstatic void
2150184610Salfredumass_cam_action(struct cam_sim *sim, union ccb *ccb)
2151184610Salfred{
2152184610Salfred	struct umass_softc *sc = (struct umass_softc *)sim->softc;
2153184610Salfred
2154241432Smav	if (sc == NULL) {
2155198307Sthompsa		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
2156184610Salfred		xpt_done(ccb);
2157184610Salfred		return;
2158184610Salfred	}
2159184610Salfred
2160184610Salfred	/* Perform the requested action */
2161184610Salfred	switch (ccb->ccb_h.func_code) {
2162184610Salfred	case XPT_SCSI_IO:
2163184610Salfred		{
2164184610Salfred			uint8_t *cmd;
2165184610Salfred			uint8_t dir;
2166184610Salfred
2167184610Salfred			if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) {
2168184610Salfred				cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr);
2169184610Salfred			} else {
2170184610Salfred				cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes);
2171184610Salfred			}
2172184610Salfred
2173184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SCSI_IO: "
2174184610Salfred			    "cmd: 0x%02x, flags: 0x%02x, "
2175184610Salfred			    "%db cmd/%db data/%db sense\n",
2176184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2177184610Salfred			    ccb->ccb_h.target_lun, cmd[0],
2178184610Salfred			    ccb->ccb_h.flags & CAM_DIR_MASK, ccb->csio.cdb_len,
2179184610Salfred			    ccb->csio.dxfer_len, ccb->csio.sense_len);
2180184610Salfred
2181184610Salfred			if (sc->sc_transfer.ccb) {
2182184610Salfred				DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SCSI_IO: "
2183184610Salfred				    "I/O in progress, deferring\n",
2184184610Salfred				    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2185184610Salfred				    ccb->ccb_h.target_lun);
2186184610Salfred				ccb->ccb_h.status = CAM_SCSI_BUSY;
2187184610Salfred				xpt_done(ccb);
2188184610Salfred				goto done;
2189184610Salfred			}
2190184610Salfred			switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
2191184610Salfred			case CAM_DIR_IN:
2192184610Salfred				dir = DIR_IN;
2193184610Salfred				break;
2194184610Salfred			case CAM_DIR_OUT:
2195184610Salfred				dir = DIR_OUT;
2196184610Salfred				DIF(UDMASS_SCSI,
2197184610Salfred				    umass_dump_buffer(sc, ccb->csio.data_ptr,
2198184610Salfred				    ccb->csio.dxfer_len, 48));
2199184610Salfred				break;
2200184610Salfred			default:
2201184610Salfred				dir = DIR_NONE;
2202184610Salfred			}
2203184610Salfred
2204184610Salfred			ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED;
2205184610Salfred
2206184610Salfred			/*
2207184610Salfred			 * sc->sc_transform will convert the command to the
2208184610Salfred			 * command format needed by the specific command set
2209184610Salfred			 * and return the converted command in
2210184610Salfred			 * "sc->sc_transfer.cmd_data"
2211184610Salfred			 */
2212184610Salfred			if (umass_std_transform(sc, ccb, cmd, ccb->csio.cdb_len)) {
2213184610Salfred
2214184610Salfred				if (sc->sc_transfer.cmd_data[0] == INQUIRY) {
2215212136Sthompsa					const char *pserial;
2216184610Salfred
2217212136Sthompsa					pserial = usb_get_serial(sc->sc_udev);
2218212136Sthompsa
2219184610Salfred					/*
2220196826Strasz					 * Umass devices don't generally report their serial numbers
2221196826Strasz					 * in the usual SCSI way.  Emulate it here.
2222196826Strasz					 */
2223196826Strasz					if ((sc->sc_transfer.cmd_data[1] & SI_EVPD) &&
2224212136Sthompsa					    (sc->sc_transfer.cmd_data[2] == SVPD_UNIT_SERIAL_NUMBER) &&
2225212136Sthompsa					    (pserial[0] != '\0')) {
2226196826Strasz						struct scsi_vpd_unit_serial_number *vpd_serial;
2227196826Strasz
2228196826Strasz						vpd_serial = (struct scsi_vpd_unit_serial_number *)ccb->csio.data_ptr;
2229212136Sthompsa						vpd_serial->length = strlen(pserial);
2230196826Strasz						if (vpd_serial->length > sizeof(vpd_serial->serial_num))
2231196826Strasz							vpd_serial->length = sizeof(vpd_serial->serial_num);
2232212136Sthompsa						memcpy(vpd_serial->serial_num, pserial, vpd_serial->length);
2233196826Strasz						ccb->csio.scsi_status = SCSI_STATUS_OK;
2234196826Strasz						ccb->ccb_h.status = CAM_REQ_CMP;
2235196826Strasz						xpt_done(ccb);
2236196826Strasz						goto done;
2237196826Strasz					}
2238196826Strasz
2239196826Strasz					/*
2240184610Salfred					 * Handle EVPD inquiry for broken devices first
2241184610Salfred					 * NO_INQUIRY also implies NO_INQUIRY_EVPD
2242184610Salfred					 */
2243184610Salfred					if ((sc->sc_quirks & (NO_INQUIRY_EVPD | NO_INQUIRY)) &&
2244184610Salfred					    (sc->sc_transfer.cmd_data[1] & SI_EVPD)) {
2245184610Salfred
2246225950Sken						scsi_set_sense_data(&ccb->csio.sense_data,
2247225950Sken							/*sense_format*/ SSD_TYPE_NONE,
2248225950Sken							/*current_error*/ 1,
2249225950Sken							/*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
2250225950Sken							/*asc*/ 0x24,
2251225950Sken							/*ascq*/ 0x00,
2252225950Sken							/*extra args*/ SSD_ELEM_NONE);
2253184610Salfred						ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
2254184610Salfred						ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
2255184610Salfred						    CAM_AUTOSNS_VALID;
2256184610Salfred						xpt_done(ccb);
2257184610Salfred						goto done;
2258184610Salfred					}
2259184610Salfred					/*
2260184610Salfred					 * Return fake inquiry data for
2261184610Salfred					 * broken devices
2262184610Salfred					 */
2263184610Salfred					if (sc->sc_quirks & NO_INQUIRY) {
2264184610Salfred						memcpy(ccb->csio.data_ptr, &fake_inq_data,
2265184610Salfred						    sizeof(fake_inq_data));
2266184610Salfred						ccb->csio.scsi_status = SCSI_STATUS_OK;
2267184610Salfred						ccb->ccb_h.status = CAM_REQ_CMP;
2268184610Salfred						xpt_done(ccb);
2269184610Salfred						goto done;
2270184610Salfred					}
2271184610Salfred					if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
2272184610Salfred						ccb->csio.dxfer_len = SHORT_INQUIRY_LENGTH;
2273184610Salfred					}
2274242628Smarcel				} else if (sc->sc_transfer.cmd_data[0] == PREVENT_ALLOW) {
2275242628Smarcel					if (sc->sc_quirks & NO_PREVENT_ALLOW) {
2276242628Smarcel						ccb->csio.scsi_status = SCSI_STATUS_OK;
2277242628Smarcel						ccb->ccb_h.status = CAM_REQ_CMP;
2278242628Smarcel						xpt_done(ccb);
2279242628Smarcel						goto done;
2280242628Smarcel					}
2281184610Salfred				} else if (sc->sc_transfer.cmd_data[0] == SYNCHRONIZE_CACHE) {
2282184610Salfred					if (sc->sc_quirks & NO_SYNCHRONIZE_CACHE) {
2283184610Salfred						ccb->csio.scsi_status = SCSI_STATUS_OK;
2284184610Salfred						ccb->ccb_h.status = CAM_REQ_CMP;
2285184610Salfred						xpt_done(ccb);
2286184610Salfred						goto done;
2287184610Salfred					}
2288184610Salfred				}
2289184610Salfred				umass_command_start(sc, dir, ccb->csio.data_ptr,
2290184610Salfred				    ccb->csio.dxfer_len,
2291184610Salfred				    ccb->ccb_h.timeout,
2292184610Salfred				    &umass_cam_cb, ccb);
2293184610Salfred			}
2294184610Salfred			break;
2295184610Salfred		}
2296184610Salfred	case XPT_PATH_INQ:
2297184610Salfred		{
2298184610Salfred			struct ccb_pathinq *cpi = &ccb->cpi;
2299184610Salfred
2300184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_PATH_INQ:.\n",
2301184610Salfred			    sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id,
2302184610Salfred			    ccb->ccb_h.target_lun);
2303184610Salfred
2304184610Salfred			/* host specific information */
2305184610Salfred			cpi->version_num = 1;
2306184610Salfred			cpi->hba_inquiry = 0;
2307184610Salfred			cpi->target_sprt = 0;
2308184610Salfred			cpi->hba_misc = PIM_NO_6_BYTE;
2309184610Salfred			cpi->hba_eng_cnt = 0;
2310184610Salfred			cpi->max_target = UMASS_SCSIID_MAX;	/* one target */
2311184610Salfred			cpi->initiator_id = UMASS_SCSIID_HOST;
2312184610Salfred			strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
2313184610Salfred			strlcpy(cpi->hba_vid, "USB SCSI", HBA_IDLEN);
2314184610Salfred			strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
2315184610Salfred			cpi->unit_number = cam_sim_unit(sim);
2316184610Salfred			cpi->bus_id = sc->sc_unit;
2317184610Salfred			cpi->protocol = PROTO_SCSI;
2318184610Salfred			cpi->protocol_version = SCSI_REV_2;
2319184610Salfred			cpi->transport = XPORT_USB;
2320184610Salfred			cpi->transport_version = 0;
2321232361Shselasky
2322184610Salfred			if (sc == NULL) {
2323184610Salfred				cpi->base_transfer_speed = 0;
2324184610Salfred				cpi->max_lun = 0;
2325184610Salfred			} else {
2326184610Salfred				if (sc->sc_quirks & FLOPPY_SPEED) {
2327184610Salfred					cpi->base_transfer_speed =
2328184610Salfred					    UMASS_FLOPPY_TRANSFER_SPEED;
2329184610Salfred				} else {
2330213439Shselasky					switch (usbd_get_speed(sc->sc_udev)) {
2331213439Shselasky					case USB_SPEED_SUPER:
2332213439Shselasky						cpi->base_transfer_speed =
2333213439Shselasky						    UMASS_SUPER_TRANSFER_SPEED;
2334213931Smav						cpi->maxio = MAXPHYS;
2335213439Shselasky						break;
2336213439Shselasky					case USB_SPEED_HIGH:
2337213439Shselasky						cpi->base_transfer_speed =
2338213439Shselasky						    UMASS_HIGH_TRANSFER_SPEED;
2339213439Shselasky						break;
2340213439Shselasky					default:
2341213439Shselasky						cpi->base_transfer_speed =
2342213439Shselasky						    UMASS_FULL_TRANSFER_SPEED;
2343213439Shselasky						break;
2344213439Shselasky					}
2345184610Salfred				}
2346184610Salfred				cpi->max_lun = sc->sc_maxlun;
2347184610Salfred			}
2348184610Salfred
2349184610Salfred			cpi->ccb_h.status = CAM_REQ_CMP;
2350184610Salfred			xpt_done(ccb);
2351184610Salfred			break;
2352184610Salfred		}
2353184610Salfred	case XPT_RESET_DEV:
2354184610Salfred		{
2355184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_RESET_DEV:.\n",
2356184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2357184610Salfred			    ccb->ccb_h.target_lun);
2358184610Salfred
2359184610Salfred			umass_reset(sc);
2360184610Salfred
2361184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2362184610Salfred			xpt_done(ccb);
2363184610Salfred			break;
2364184610Salfred		}
2365184610Salfred	case XPT_GET_TRAN_SETTINGS:
2366184610Salfred		{
2367184610Salfred			struct ccb_trans_settings *cts = &ccb->cts;
2368184610Salfred
2369184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_GET_TRAN_SETTINGS:.\n",
2370184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2371184610Salfred			    ccb->ccb_h.target_lun);
2372184610Salfred
2373184610Salfred			cts->protocol = PROTO_SCSI;
2374184610Salfred			cts->protocol_version = SCSI_REV_2;
2375184610Salfred			cts->transport = XPORT_USB;
2376184610Salfred			cts->transport_version = 0;
2377184610Salfred			cts->xport_specific.valid = 0;
2378232361Shselasky
2379184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2380184610Salfred			xpt_done(ccb);
2381184610Salfred			break;
2382184610Salfred		}
2383184610Salfred	case XPT_SET_TRAN_SETTINGS:
2384184610Salfred		{
2385184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SET_TRAN_SETTINGS:.\n",
2386184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2387184610Salfred			    ccb->ccb_h.target_lun);
2388184610Salfred
2389184610Salfred			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
2390184610Salfred			xpt_done(ccb);
2391184610Salfred			break;
2392184610Salfred		}
2393184610Salfred	case XPT_CALC_GEOMETRY:
2394184610Salfred		{
2395184610Salfred			cam_calc_geometry(&ccb->ccg, /* extended */ 1);
2396184610Salfred			xpt_done(ccb);
2397184610Salfred			break;
2398184610Salfred		}
2399184610Salfred	case XPT_NOOP:
2400184610Salfred		{
2401184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_NOOP:.\n",
2402184610Salfred			    sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id,
2403184610Salfred			    ccb->ccb_h.target_lun);
2404184610Salfred
2405184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2406184610Salfred			xpt_done(ccb);
2407184610Salfred			break;
2408184610Salfred		}
2409184610Salfred	default:
2410184610Salfred		DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:func_code 0x%04x: "
2411184610Salfred		    "Not implemented\n",
2412184610Salfred		    sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id,
2413184610Salfred		    ccb->ccb_h.target_lun, ccb->ccb_h.func_code);
2414184610Salfred
2415184610Salfred		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
2416184610Salfred		xpt_done(ccb);
2417184610Salfred		break;
2418184610Salfred	}
2419184610Salfred
2420184610Salfreddone:
2421184610Salfred	return;
2422184610Salfred}
2423184610Salfred
2424184610Salfredstatic void
2425184610Salfredumass_cam_poll(struct cam_sim *sim)
2426184610Salfred{
2427184610Salfred	struct umass_softc *sc = (struct umass_softc *)sim->softc;
2428184610Salfred
2429241432Smav	if (sc == NULL)
2430184610Salfred		return;
2431184610Salfred
2432184610Salfred	DPRINTF(sc, UDMASS_SCSI, "CAM poll\n");
2433184610Salfred
2434194677Sthompsa	usbd_transfer_poll(sc->sc_xfer, UMASS_T_MAX);
2435184610Salfred}
2436184610Salfred
2437184610Salfred
2438184610Salfred/* umass_cam_cb
2439184610Salfred *	finalise a completed CAM command
2440184610Salfred */
2441184610Salfred
2442184610Salfredstatic void
2443184610Salfredumass_cam_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
2444184610Salfred    uint8_t status)
2445184610Salfred{
2446184610Salfred	ccb->csio.resid = residue;
2447184610Salfred
2448184610Salfred	switch (status) {
2449184610Salfred	case STATUS_CMD_OK:
2450184610Salfred		ccb->ccb_h.status = CAM_REQ_CMP;
2451184610Salfred		if ((sc->sc_quirks & READ_CAPACITY_OFFBY1) &&
2452184610Salfred		    (ccb->ccb_h.func_code == XPT_SCSI_IO) &&
2453184610Salfred		    (ccb->csio.cdb_io.cdb_bytes[0] == READ_CAPACITY)) {
2454184610Salfred			struct scsi_read_capacity_data *rcap;
2455184610Salfred			uint32_t maxsector;
2456184610Salfred
2457184610Salfred			rcap = (void *)(ccb->csio.data_ptr);
2458184610Salfred			maxsector = scsi_4btoul(rcap->addr) - 1;
2459184610Salfred			scsi_ulto4b(maxsector, rcap->addr);
2460184610Salfred		}
2461196826Strasz		/*
2462196826Strasz		 * We have to add SVPD_UNIT_SERIAL_NUMBER to the list
2463196826Strasz		 * of pages supported by the device - otherwise, CAM
2464196826Strasz		 * will never ask us for the serial number if the
2465196826Strasz		 * device cannot handle that by itself.
2466196826Strasz		 */
2467196826Strasz		if (ccb->ccb_h.func_code == XPT_SCSI_IO &&
2468196826Strasz		    sc->sc_transfer.cmd_data[0] == INQUIRY &&
2469196826Strasz		    (sc->sc_transfer.cmd_data[1] & SI_EVPD) &&
2470196826Strasz		    sc->sc_transfer.cmd_data[2] == SVPD_SUPPORTED_PAGE_LIST &&
2471212136Sthompsa		    (usb_get_serial(sc->sc_udev)[0] != '\0')) {
2472196826Strasz			struct ccb_scsiio *csio;
2473196826Strasz			struct scsi_vpd_supported_page_list *page_list;
2474196826Strasz
2475196826Strasz			csio = &ccb->csio;
2476196826Strasz			page_list = (struct scsi_vpd_supported_page_list *)csio->data_ptr;
2477196826Strasz			if (page_list->length + 1 < SVPD_SUPPORTED_PAGES_SIZE) {
2478196826Strasz				page_list->list[page_list->length] = SVPD_UNIT_SERIAL_NUMBER;
2479196826Strasz				page_list->length++;
2480196826Strasz			}
2481196826Strasz		}
2482184610Salfred		xpt_done(ccb);
2483184610Salfred		break;
2484184610Salfred
2485184610Salfred	case STATUS_CMD_UNKNOWN:
2486184610Salfred	case STATUS_CMD_FAILED:
2487184610Salfred
2488184610Salfred		/* fetch sense data */
2489184610Salfred
2490184610Salfred		/* the rest of the command was filled in at attach */
2491184610Salfred		sc->cam_scsi_sense.length = ccb->csio.sense_len;
2492184610Salfred
2493184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Fetching %d bytes of "
2494184610Salfred		    "sense data\n", ccb->csio.sense_len);
2495184610Salfred
2496184610Salfred		if (umass_std_transform(sc, ccb, &sc->cam_scsi_sense.opcode,
2497184610Salfred		    sizeof(sc->cam_scsi_sense))) {
2498184610Salfred
2499184610Salfred			if ((sc->sc_quirks & FORCE_SHORT_INQUIRY) &&
2500184610Salfred			    (sc->sc_transfer.cmd_data[0] == INQUIRY)) {
2501184610Salfred				ccb->csio.sense_len = SHORT_INQUIRY_LENGTH;
2502184610Salfred			}
2503184610Salfred			umass_command_start(sc, DIR_IN, &ccb->csio.sense_data.error_code,
2504184610Salfred			    ccb->csio.sense_len, ccb->ccb_h.timeout,
2505184610Salfred			    &umass_cam_sense_cb, ccb);
2506184610Salfred		}
2507184610Salfred		break;
2508184610Salfred
2509184610Salfred	default:
2510184610Salfred		/*
2511203146Sthompsa		 * The wire protocol failed and will hopefully have
2512203146Sthompsa		 * recovered. We return an error to CAM and let CAM
2513220535Smav		 * retry the command if necessary.
2514184610Salfred		 */
2515220535Smav		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2516184610Salfred		xpt_done(ccb);
2517184610Salfred		break;
2518184610Salfred	}
2519184610Salfred}
2520184610Salfred
2521184610Salfred/*
2522184610Salfred * Finalise a completed autosense operation
2523184610Salfred */
2524184610Salfredstatic void
2525184610Salfredumass_cam_sense_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
2526184610Salfred    uint8_t status)
2527184610Salfred{
2528184610Salfred	uint8_t *cmd;
2529184610Salfred
2530184610Salfred	switch (status) {
2531184610Salfred	case STATUS_CMD_OK:
2532184610Salfred	case STATUS_CMD_UNKNOWN:
2533225950Sken	case STATUS_CMD_FAILED: {
2534225950Sken		int key, sense_len;
2535184610Salfred
2536225950Sken		ccb->csio.sense_resid = residue;
2537225950Sken		sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
2538225950Sken		key = scsi_get_sense_key(&ccb->csio.sense_data, sense_len,
2539225950Sken					 /*show_errors*/ 1);
2540225950Sken
2541184610Salfred		if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) {
2542184610Salfred			cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr);
2543184610Salfred		} else {
2544184610Salfred			cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes);
2545184610Salfred		}
2546184610Salfred
2547184610Salfred		/*
2548184610Salfred		 * Getting sense data always succeeds (apart from wire
2549184610Salfred		 * failures):
2550184610Salfred		 */
2551184610Salfred		if ((sc->sc_quirks & RS_NO_CLEAR_UA) &&
2552184610Salfred		    (cmd[0] == INQUIRY) &&
2553184610Salfred		    (key == SSD_KEY_UNIT_ATTENTION)) {
2554184610Salfred			/*
2555184610Salfred			 * Ignore unit attention errors in the case where
2556184610Salfred			 * the Unit Attention state is not cleared on
2557184610Salfred			 * REQUEST SENSE. They will appear again at the next
2558184610Salfred			 * command.
2559184610Salfred			 */
2560184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2561184610Salfred		} else if (key == SSD_KEY_NO_SENSE) {
2562184610Salfred			/*
2563184610Salfred			 * No problem after all (in the case of CBI without
2564184610Salfred			 * CCI)
2565184610Salfred			 */
2566184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2567184610Salfred		} else if ((sc->sc_quirks & RS_NO_CLEAR_UA) &&
2568184610Salfred			    (cmd[0] == READ_CAPACITY) &&
2569184610Salfred		    (key == SSD_KEY_UNIT_ATTENTION)) {
2570184610Salfred			/*
2571184610Salfred			 * Some devices do not clear the unit attention error
2572184610Salfred			 * on request sense. We insert a test unit ready
2573184610Salfred			 * command to make sure we clear the unit attention
2574184610Salfred			 * condition, then allow the retry to proceed as
2575184610Salfred			 * usual.
2576184610Salfred			 */
2577184610Salfred
2578184610Salfred			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
2579184610Salfred			    | CAM_AUTOSNS_VALID;
2580184610Salfred			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
2581184610Salfred
2582184610Salfred#if 0
2583184610Salfred			DELAY(300000);
2584184610Salfred#endif
2585184610Salfred			DPRINTF(sc, UDMASS_SCSI, "Doing a sneaky"
2586184610Salfred			    "TEST_UNIT_READY\n");
2587184610Salfred
2588184610Salfred			/* the rest of the command was filled in at attach */
2589184610Salfred
2590184610Salfred			if (umass_std_transform(sc, ccb,
2591184610Salfred			    &sc->cam_scsi_test_unit_ready.opcode,
2592184610Salfred			    sizeof(sc->cam_scsi_test_unit_ready))) {
2593184610Salfred				umass_command_start(sc, DIR_NONE, NULL, 0,
2594184610Salfred				    ccb->ccb_h.timeout,
2595184610Salfred				    &umass_cam_quirk_cb, ccb);
2596184610Salfred			}
2597184610Salfred			break;
2598184610Salfred		} else {
2599184610Salfred			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
2600184610Salfred			    | CAM_AUTOSNS_VALID;
2601184610Salfred			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
2602184610Salfred		}
2603184610Salfred		xpt_done(ccb);
2604184610Salfred		break;
2605225950Sken	}
2606184610Salfred	default:
2607184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Autosense failed, "
2608184610Salfred		    "status %d\n", status);
2609184610Salfred		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
2610184610Salfred		xpt_done(ccb);
2611184610Salfred	}
2612184610Salfred}
2613184610Salfred
2614184610Salfred/*
2615184610Salfred * This completion code just handles the fact that we sent a test-unit-ready
2616184610Salfred * after having previously failed a READ CAPACITY with CHECK_COND.  Even
2617184610Salfred * though this command succeeded, we have to tell CAM to retry.
2618184610Salfred */
2619184610Salfredstatic void
2620184610Salfredumass_cam_quirk_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
2621184610Salfred    uint8_t status)
2622184610Salfred{
2623184610Salfred	DPRINTF(sc, UDMASS_SCSI, "Test unit ready "
2624184610Salfred	    "returned status %d\n", status);
2625184610Salfred
2626184610Salfred	ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
2627184610Salfred	    | CAM_AUTOSNS_VALID;
2628184610Salfred	ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
2629184610Salfred	xpt_done(ccb);
2630184610Salfred}
2631184610Salfred
2632184610Salfred/*
2633184610Salfred * SCSI specific functions
2634184610Salfred */
2635184610Salfred
2636184610Salfredstatic uint8_t
2637184610Salfredumass_scsi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
2638184610Salfred    uint8_t cmd_len)
2639184610Salfred{
2640184610Salfred	if ((cmd_len == 0) ||
2641184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2642184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
2643184610Salfred		    "length: %d bytes\n", cmd_len);
2644184610Salfred		return (0);		/* failure */
2645184610Salfred	}
2646184610Salfred	sc->sc_transfer.cmd_len = cmd_len;
2647184610Salfred
2648184610Salfred	switch (cmd_ptr[0]) {
2649184610Salfred	case TEST_UNIT_READY:
2650184610Salfred		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
2651184610Salfred			DPRINTF(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY "
2652184610Salfred			    "to START_UNIT\n");
2653227461Shselasky			memset(sc->sc_transfer.cmd_data, 0, cmd_len);
2654184610Salfred			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
2655184610Salfred			sc->sc_transfer.cmd_data[4] = SSS_START;
2656184610Salfred			return (1);
2657184610Salfred		}
2658184610Salfred		break;
2659184610Salfred
2660184610Salfred	case INQUIRY:
2661184610Salfred		/*
2662184610Salfred		 * some drives wedge when asked for full inquiry
2663184610Salfred		 * information.
2664184610Salfred		 */
2665184610Salfred		if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
2666227461Shselasky			memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2667184610Salfred			sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
2668184610Salfred			return (1);
2669184610Salfred		}
2670184610Salfred		break;
2671184610Salfred	}
2672184610Salfred
2673227461Shselasky	memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2674184610Salfred	return (1);
2675184610Salfred}
2676184610Salfred
2677184610Salfredstatic uint8_t
2678184610Salfredumass_rbc_transform(struct umass_softc *sc, uint8_t *cmd_ptr, uint8_t cmd_len)
2679184610Salfred{
2680184610Salfred	if ((cmd_len == 0) ||
2681184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2682184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
2683184610Salfred		    "length: %d bytes\n", cmd_len);
2684184610Salfred		return (0);		/* failure */
2685184610Salfred	}
2686184610Salfred	switch (cmd_ptr[0]) {
2687184610Salfred		/* these commands are defined in RBC: */
2688184610Salfred	case READ_10:
2689184610Salfred	case READ_CAPACITY:
2690184610Salfred	case START_STOP_UNIT:
2691184610Salfred	case SYNCHRONIZE_CACHE:
2692184610Salfred	case WRITE_10:
2693184610Salfred	case 0x2f:			/* VERIFY_10 is absent from
2694184610Salfred					 * scsi_all.h??? */
2695184610Salfred	case INQUIRY:
2696184610Salfred	case MODE_SELECT_10:
2697184610Salfred	case MODE_SENSE_10:
2698184610Salfred	case TEST_UNIT_READY:
2699184610Salfred	case WRITE_BUFFER:
2700184610Salfred		/*
2701184610Salfred		 * The following commands are not listed in my copy of the
2702184610Salfred		 * RBC specs. CAM however seems to want those, and at least
2703184610Salfred		 * the Sony DSC device appears to support those as well
2704184610Salfred		 */
2705184610Salfred	case REQUEST_SENSE:
2706184610Salfred	case PREVENT_ALLOW:
2707184610Salfred
2708227461Shselasky		memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2709184610Salfred
2710184610Salfred		if ((sc->sc_quirks & RBC_PAD_TO_12) && (cmd_len < 12)) {
2711227461Shselasky			memset(sc->sc_transfer.cmd_data + cmd_len,
2712227461Shselasky			    0, 12 - cmd_len);
2713184610Salfred			cmd_len = 12;
2714184610Salfred		}
2715184610Salfred		sc->sc_transfer.cmd_len = cmd_len;
2716184610Salfred		return (1);		/* sucess */
2717184610Salfred
2718184610Salfred		/* All other commands are not legal in RBC */
2719184610Salfred	default:
2720184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Unsupported RBC "
2721184610Salfred		    "command 0x%02x\n", cmd_ptr[0]);
2722184610Salfred		return (0);		/* failure */
2723184610Salfred	}
2724184610Salfred}
2725184610Salfred
2726184610Salfredstatic uint8_t
2727184610Salfredumass_ufi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
2728184610Salfred    uint8_t cmd_len)
2729184610Salfred{
2730184610Salfred	if ((cmd_len == 0) ||
2731184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2732184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
2733184610Salfred		    "length: %d bytes\n", cmd_len);
2734184610Salfred		return (0);		/* failure */
2735184610Salfred	}
2736184610Salfred	/* An UFI command is always 12 bytes in length */
2737184610Salfred	sc->sc_transfer.cmd_len = UFI_COMMAND_LENGTH;
2738184610Salfred
2739184610Salfred	/* Zero the command data */
2740227461Shselasky	memset(sc->sc_transfer.cmd_data, 0, UFI_COMMAND_LENGTH);
2741184610Salfred
2742184610Salfred	switch (cmd_ptr[0]) {
2743184610Salfred		/*
2744184610Salfred		 * Commands of which the format has been verified. They
2745184610Salfred		 * should work. Copy the command into the (zeroed out)
2746184610Salfred		 * destination buffer.
2747184610Salfred		 */
2748184610Salfred	case TEST_UNIT_READY:
2749184610Salfred		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
2750184610Salfred			/*
2751184610Salfred			 * Some devices do not support this command. Start
2752184610Salfred			 * Stop Unit should give the same results
2753184610Salfred			 */
2754184610Salfred			DPRINTF(sc, UDMASS_UFI, "Converted TEST_UNIT_READY "
2755184610Salfred			    "to START_UNIT\n");
2756184610Salfred
2757184610Salfred			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
2758184610Salfred			sc->sc_transfer.cmd_data[4] = SSS_START;
2759184610Salfred			return (1);
2760184610Salfred		}
2761184610Salfred		break;
2762184610Salfred
2763184610Salfred	case REZERO_UNIT:
2764184610Salfred	case REQUEST_SENSE:
2765184610Salfred	case FORMAT_UNIT:
2766184610Salfred	case INQUIRY:
2767184610Salfred	case START_STOP_UNIT:
2768184610Salfred	case SEND_DIAGNOSTIC:
2769184610Salfred	case PREVENT_ALLOW:
2770184610Salfred	case READ_CAPACITY:
2771184610Salfred	case READ_10:
2772184610Salfred	case WRITE_10:
2773184610Salfred	case POSITION_TO_ELEMENT:	/* SEEK_10 */
2774184610Salfred	case WRITE_AND_VERIFY:
2775184610Salfred	case VERIFY:
2776184610Salfred	case MODE_SELECT_10:
2777184610Salfred	case MODE_SENSE_10:
2778184610Salfred	case READ_12:
2779184610Salfred	case WRITE_12:
2780184610Salfred	case READ_FORMAT_CAPACITIES:
2781184610Salfred		break;
2782184610Salfred
2783184610Salfred		/*
2784184610Salfred		 * SYNCHRONIZE_CACHE isn't supported by UFI, nor should it be
2785184610Salfred		 * required for UFI devices, so it is appropriate to fake
2786184610Salfred		 * success.
2787184610Salfred		 */
2788184610Salfred	case SYNCHRONIZE_CACHE:
2789184610Salfred		return (2);
2790184610Salfred
2791184610Salfred	default:
2792184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Unsupported UFI "
2793184610Salfred		    "command 0x%02x\n", cmd_ptr[0]);
2794184610Salfred		return (0);		/* failure */
2795184610Salfred	}
2796184610Salfred
2797227461Shselasky	memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2798184610Salfred	return (1);			/* success */
2799184610Salfred}
2800184610Salfred
2801184610Salfred/*
2802184610Salfred * 8070i (ATAPI) specific functions
2803184610Salfred */
2804184610Salfredstatic uint8_t
2805184610Salfredumass_atapi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
2806184610Salfred    uint8_t cmd_len)
2807184610Salfred{
2808184610Salfred	if ((cmd_len == 0) ||
2809184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2810184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
2811184610Salfred		    "length: %d bytes\n", cmd_len);
2812184610Salfred		return (0);		/* failure */
2813184610Salfred	}
2814184610Salfred	/* An ATAPI command is always 12 bytes in length. */
2815184610Salfred	sc->sc_transfer.cmd_len = ATAPI_COMMAND_LENGTH;
2816184610Salfred
2817184610Salfred	/* Zero the command data */
2818227461Shselasky	memset(sc->sc_transfer.cmd_data, 0, ATAPI_COMMAND_LENGTH);
2819184610Salfred
2820184610Salfred	switch (cmd_ptr[0]) {
2821184610Salfred		/*
2822184610Salfred		 * Commands of which the format has been verified. They
2823184610Salfred		 * should work. Copy the command into the destination
2824184610Salfred		 * buffer.
2825184610Salfred		 */
2826184610Salfred	case INQUIRY:
2827184610Salfred		/*
2828184610Salfred		 * some drives wedge when asked for full inquiry
2829184610Salfred		 * information.
2830184610Salfred		 */
2831184610Salfred		if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
2832227461Shselasky			memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2833184610Salfred
2834184610Salfred			sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
2835184610Salfred			return (1);
2836184610Salfred		}
2837184610Salfred		break;
2838184610Salfred
2839184610Salfred	case TEST_UNIT_READY:
2840184610Salfred		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
2841184610Salfred			DPRINTF(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY "
2842184610Salfred			    "to START_UNIT\n");
2843184610Salfred			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
2844184610Salfred			sc->sc_transfer.cmd_data[4] = SSS_START;
2845184610Salfred			return (1);
2846184610Salfred		}
2847184610Salfred		break;
2848184610Salfred
2849184610Salfred	case REZERO_UNIT:
2850184610Salfred	case REQUEST_SENSE:
2851184610Salfred	case START_STOP_UNIT:
2852184610Salfred	case SEND_DIAGNOSTIC:
2853184610Salfred	case PREVENT_ALLOW:
2854184610Salfred	case READ_CAPACITY:
2855184610Salfred	case READ_10:
2856184610Salfred	case WRITE_10:
2857184610Salfred	case POSITION_TO_ELEMENT:	/* SEEK_10 */
2858184610Salfred	case SYNCHRONIZE_CACHE:
2859184610Salfred	case MODE_SELECT_10:
2860184610Salfred	case MODE_SENSE_10:
2861184610Salfred	case READ_BUFFER:
2862184610Salfred	case 0x42:			/* READ_SUBCHANNEL */
2863184610Salfred	case 0x43:			/* READ_TOC */
2864184610Salfred	case 0x44:			/* READ_HEADER */
2865184610Salfred	case 0x47:			/* PLAY_MSF (Play Minute/Second/Frame) */
2866184610Salfred	case 0x48:			/* PLAY_TRACK */
2867184610Salfred	case 0x49:			/* PLAY_TRACK_REL */
2868184610Salfred	case 0x4b:			/* PAUSE */
2869184610Salfred	case 0x51:			/* READ_DISK_INFO */
2870184610Salfred	case 0x52:			/* READ_TRACK_INFO */
2871184610Salfred	case 0x54:			/* SEND_OPC */
2872184610Salfred	case 0x59:			/* READ_MASTER_CUE */
2873184610Salfred	case 0x5b:			/* CLOSE_TR_SESSION */
2874184610Salfred	case 0x5c:			/* READ_BUFFER_CAP */
2875184610Salfred	case 0x5d:			/* SEND_CUE_SHEET */
2876184610Salfred	case 0xa1:			/* BLANK */
2877184610Salfred	case 0xa5:			/* PLAY_12 */
2878184610Salfred	case 0xa6:			/* EXCHANGE_MEDIUM */
2879184610Salfred	case 0xad:			/* READ_DVD_STRUCTURE */
2880184610Salfred	case 0xbb:			/* SET_CD_SPEED */
2881184610Salfred	case 0xe5:			/* READ_TRACK_INFO_PHILIPS */
2882201758Smbr		break;
2883184610Salfred
2884184610Salfred	case READ_12:
2885184610Salfred	case WRITE_12:
2886184610Salfred	default:
2887184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Unsupported ATAPI "
2888184610Salfred		    "command 0x%02x - trying anyway\n",
2889184610Salfred		    cmd_ptr[0]);
2890201758Smbr		break;
2891184610Salfred	}
2892184610Salfred
2893227461Shselasky	memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2894184610Salfred	return (1);			/* success */
2895184610Salfred}
2896184610Salfred
2897184610Salfredstatic uint8_t
2898184610Salfredumass_no_transform(struct umass_softc *sc, uint8_t *cmd,
2899184610Salfred    uint8_t cmdlen)
2900184610Salfred{
2901184610Salfred	return (0);			/* failure */
2902184610Salfred}
2903184610Salfred
2904184610Salfredstatic uint8_t
2905184610Salfredumass_std_transform(struct umass_softc *sc, union ccb *ccb,
2906184610Salfred    uint8_t *cmd, uint8_t cmdlen)
2907184610Salfred{
2908184610Salfred	uint8_t retval;
2909184610Salfred
2910184610Salfred	retval = (sc->sc_transform) (sc, cmd, cmdlen);
2911184610Salfred
2912184610Salfred	if (retval == 2) {
2913184610Salfred		ccb->ccb_h.status = CAM_REQ_CMP;
2914184610Salfred		xpt_done(ccb);
2915184610Salfred		return (0);
2916184610Salfred	} else if (retval == 0) {
2917184610Salfred		ccb->ccb_h.status = CAM_REQ_INVALID;
2918184610Salfred		xpt_done(ccb);
2919184610Salfred		return (0);
2920184610Salfred	}
2921184610Salfred	/* Command should be executed */
2922184610Salfred	return (1);
2923184610Salfred}
2924184610Salfred
2925207077Sthompsa#ifdef USB_DEBUG
2926184610Salfredstatic void
2927184610Salfredumass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw)
2928184610Salfred{
2929184610Salfred	uint8_t *c = cbw->CBWCDB;
2930184610Salfred
2931184610Salfred	uint32_t dlen = UGETDW(cbw->dCBWDataTransferLength);
2932184610Salfred	uint32_t tag = UGETDW(cbw->dCBWTag);
2933184610Salfred
2934184610Salfred	uint8_t clen = cbw->bCDBLength;
2935184610Salfred	uint8_t flags = cbw->bCBWFlags;
2936184610Salfred	uint8_t lun = cbw->bCBWLUN;
2937184610Salfred
2938184610Salfred	DPRINTF(sc, UDMASS_BBB, "CBW %d: cmd = %db "
2939184610Salfred	    "(0x%02x%02x%02x%02x%02x%02x%s), "
2940184610Salfred	    "data = %db, lun = %d, dir = %s\n",
2941184610Salfred	    tag, clen,
2942184610Salfred	    c[0], c[1], c[2], c[3], c[4], c[5], (clen > 6 ? "..." : ""),
2943184610Salfred	    dlen, lun, (flags == CBWFLAGS_IN ? "in" :
2944184610Salfred	    (flags == CBWFLAGS_OUT ? "out" : "<invalid>")));
2945184610Salfred}
2946184610Salfred
2947184610Salfredstatic void
2948184610Salfredumass_bbb_dump_csw(struct umass_softc *sc, umass_bbb_csw_t *csw)
2949184610Salfred{
2950184610Salfred	uint32_t sig = UGETDW(csw->dCSWSignature);
2951184610Salfred	uint32_t tag = UGETDW(csw->dCSWTag);
2952184610Salfred	uint32_t res = UGETDW(csw->dCSWDataResidue);
2953184610Salfred	uint8_t status = csw->bCSWStatus;
2954184610Salfred
2955184610Salfred	DPRINTF(sc, UDMASS_BBB, "CSW %d: sig = 0x%08x (%s), tag = 0x%08x, "
2956184610Salfred	    "res = %d, status = 0x%02x (%s)\n",
2957184610Salfred	    tag, sig, (sig == CSWSIGNATURE ? "valid" : "invalid"),
2958184610Salfred	    tag, res,
2959184610Salfred	    status, (status == CSWSTATUS_GOOD ? "good" :
2960184610Salfred	    (status == CSWSTATUS_FAILED ? "failed" :
2961184610Salfred	    (status == CSWSTATUS_PHASE ? "phase" : "<invalid>"))));
2962184610Salfred}
2963184610Salfred
2964184610Salfredstatic void
2965184610Salfredumass_cbi_dump_cmd(struct umass_softc *sc, void *cmd, uint8_t cmdlen)
2966184610Salfred{
2967184610Salfred	uint8_t *c = cmd;
2968184610Salfred	uint8_t dir = sc->sc_transfer.dir;
2969184610Salfred
2970184610Salfred	DPRINTF(sc, UDMASS_BBB, "cmd = %db "
2971184610Salfred	    "(0x%02x%02x%02x%02x%02x%02x%s), "
2972184610Salfred	    "data = %db, dir = %s\n",
2973184610Salfred	    cmdlen,
2974184610Salfred	    c[0], c[1], c[2], c[3], c[4], c[5], (cmdlen > 6 ? "..." : ""),
2975184610Salfred	    sc->sc_transfer.data_len,
2976184610Salfred	    (dir == DIR_IN ? "in" :
2977184610Salfred	    (dir == DIR_OUT ? "out" :
2978184610Salfred	    (dir == DIR_NONE ? "no data phase" : "<invalid>"))));
2979184610Salfred}
2980184610Salfred
2981184610Salfredstatic void
2982184610Salfredumass_dump_buffer(struct umass_softc *sc, uint8_t *buffer, uint32_t buflen,
2983184610Salfred    uint32_t printlen)
2984184610Salfred{
2985184610Salfred	uint32_t i, j;
2986184610Salfred	char s1[40];
2987184610Salfred	char s2[40];
2988184610Salfred	char s3[5];
2989184610Salfred
2990184610Salfred	s1[0] = '\0';
2991184610Salfred	s3[0] = '\0';
2992184610Salfred
2993184610Salfred	sprintf(s2, " buffer=%p, buflen=%d", buffer, buflen);
2994184610Salfred	for (i = 0; (i < buflen) && (i < printlen); i++) {
2995184610Salfred		j = i % 16;
2996184610Salfred		if (j == 0 && i != 0) {
2997184610Salfred			DPRINTF(sc, UDMASS_GEN, "0x %s%s\n",
2998184610Salfred			    s1, s2);
2999184610Salfred			s2[0] = '\0';
3000184610Salfred		}
3001184610Salfred		sprintf(&s1[j * 2], "%02x", buffer[i] & 0xff);
3002184610Salfred	}
3003184610Salfred	if (buflen > printlen)
3004184610Salfred		sprintf(s3, " ...");
3005184610Salfred	DPRINTF(sc, UDMASS_GEN, "0x %s%s%s\n",
3006184610Salfred	    s1, s2, s3);
3007184610Salfred}
3008184610Salfred
3009184610Salfred#endif
3010