1184610Salfred#include <sys/cdefs.h>
2184610Salfred__FBSDID("$FreeBSD: releng/10.2/sys/dev/usb/storage/umass.c 255472 2013-09-11 10:18:36Z 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: releng/10.2/sys/dev/usb/storage/umass.c 255472 2013-09-11 10:18:36Z 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),
701246128Ssbz
702246128Ssbz	DEVMETHOD_END
703184610Salfred};
704184610Salfred
705184610Salfredstatic driver_t umass_driver = {
706184610Salfred	.name = "umass",
707184610Salfred	.methods = umass_methods,
708184610Salfred	.size = sizeof(struct umass_softc),
709184610Salfred};
710184610Salfred
711189275SthompsaDRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, NULL, 0);
712188942SthompsaMODULE_DEPEND(umass, usb, 1, 1, 1);
713184610SalfredMODULE_DEPEND(umass, cam, 1, 1, 1);
714212122SthompsaMODULE_VERSION(umass, 1);
715184610Salfred
716184610Salfred/*
717184610Salfred * USB device probe/attach/detach
718184610Salfred */
719184610Salfred
720223486Shselaskystatic const STRUCT_USB_HOST_ID __used umass_devs[] = {
721223486Shselasky	/* generic mass storage class */
722223486Shselasky	{USB_IFACE_CLASS(UICLASS_MASS),},
723223486Shselasky};
724223486Shselasky
725192052Sthompsastatic uint16_t
726192984Sthompsaumass_get_proto(struct usb_interface *iface)
727192052Sthompsa{
728192984Sthompsa	struct usb_interface_descriptor *id;
729192052Sthompsa	uint16_t retval;
730192052Sthompsa
731192052Sthompsa	retval = 0;
732192052Sthompsa
733192052Sthompsa	/* Check for a standards compliant device */
734194228Sthompsa	id = usbd_get_interface_descriptor(iface);
735192052Sthompsa	if ((id == NULL) ||
736192052Sthompsa	    (id->bInterfaceClass != UICLASS_MASS)) {
737192052Sthompsa		goto done;
738192052Sthompsa	}
739192052Sthompsa	switch (id->bInterfaceSubClass) {
740192052Sthompsa	case UISUBCLASS_SCSI:
741192052Sthompsa		retval |= UMASS_PROTO_SCSI;
742192052Sthompsa		break;
743192052Sthompsa	case UISUBCLASS_UFI:
744192052Sthompsa		retval |= UMASS_PROTO_UFI;
745192052Sthompsa		break;
746192052Sthompsa	case UISUBCLASS_RBC:
747192052Sthompsa		retval |= UMASS_PROTO_RBC;
748192052Sthompsa		break;
749192052Sthompsa	case UISUBCLASS_SFF8020I:
750192052Sthompsa	case UISUBCLASS_SFF8070I:
751192052Sthompsa		retval |= UMASS_PROTO_ATAPI;
752192052Sthompsa		break;
753192052Sthompsa	default:
754192052Sthompsa		goto done;
755192052Sthompsa	}
756192052Sthompsa
757192052Sthompsa	switch (id->bInterfaceProtocol) {
758192052Sthompsa	case UIPROTO_MASS_CBI:
759192052Sthompsa		retval |= UMASS_PROTO_CBI;
760192052Sthompsa		break;
761192052Sthompsa	case UIPROTO_MASS_CBI_I:
762192052Sthompsa		retval |= UMASS_PROTO_CBI_I;
763192052Sthompsa		break;
764192052Sthompsa	case UIPROTO_MASS_BBB_OLD:
765192052Sthompsa	case UIPROTO_MASS_BBB:
766192052Sthompsa		retval |= UMASS_PROTO_BBB;
767192052Sthompsa		break;
768192052Sthompsa	default:
769192052Sthompsa		goto done;
770192052Sthompsa	}
771192052Sthompsadone:
772192052Sthompsa	return (retval);
773192052Sthompsa}
774192052Sthompsa
775184610Salfred/*
776200886Sthompsa * Match the device we are seeing with the devices supported.
777184610Salfred */
778184610Salfredstatic struct umass_probe_proto
779192984Sthompsaumass_probe_proto(device_t dev, struct usb_attach_arg *uaa)
780184610Salfred{
781184610Salfred	struct umass_probe_proto ret;
782200886Sthompsa	uint32_t quirks = NO_QUIRKS;
783200886Sthompsa	uint32_t proto = umass_get_proto(uaa->iface);
784184610Salfred
785192052Sthompsa	memset(&ret, 0, sizeof(ret));
786222051Savg	ret.error = BUS_PROBE_GENERIC;
787184610Salfred
788200886Sthompsa	/* Search for protocol enforcement */
789184610Salfred
790200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_BBB)) {
791200886Sthompsa		proto &= ~UMASS_PROTO_WIRE;
792200886Sthompsa		proto |= UMASS_PROTO_BBB;
793200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_CBI)) {
794200886Sthompsa		proto &= ~UMASS_PROTO_WIRE;
795200886Sthompsa		proto |= UMASS_PROTO_CBI;
796200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_CBI_I)) {
797200886Sthompsa		proto &= ~UMASS_PROTO_WIRE;
798200886Sthompsa		proto |= UMASS_PROTO_CBI_I;
799200886Sthompsa	}
800184610Salfred
801200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_SCSI)) {
802200886Sthompsa		proto &= ~UMASS_PROTO_COMMAND;
803200886Sthompsa		proto |= UMASS_PROTO_SCSI;
804200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_ATAPI)) {
805200886Sthompsa		proto &= ~UMASS_PROTO_COMMAND;
806200886Sthompsa		proto |= UMASS_PROTO_ATAPI;
807200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_UFI)) {
808200886Sthompsa		proto &= ~UMASS_PROTO_COMMAND;
809200886Sthompsa		proto |= UMASS_PROTO_UFI;
810200886Sthompsa	} else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_RBC)) {
811200886Sthompsa		proto &= ~UMASS_PROTO_COMMAND;
812200886Sthompsa		proto |= UMASS_PROTO_RBC;
813200886Sthompsa	}
814200886Sthompsa
815200886Sthompsa	/* Check if the protocol is invalid */
816200886Sthompsa
817200886Sthompsa	if ((proto & UMASS_PROTO_COMMAND) == 0) {
818200886Sthompsa		ret.error = ENXIO;
819184610Salfred		goto done;
820184610Salfred	}
821200886Sthompsa
822200886Sthompsa	if ((proto & UMASS_PROTO_WIRE) == 0) {
823200886Sthompsa		ret.error = ENXIO;
824200886Sthompsa		goto done;
825184610Salfred	}
826184610Salfred
827200886Sthompsa	/* Search for quirks */
828200886Sthompsa
829200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_TEST_UNIT_READY))
830200886Sthompsa		quirks |= NO_TEST_UNIT_READY;
831200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_RS_CLEAR_UA))
832200886Sthompsa		quirks |= RS_NO_CLEAR_UA;
833200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_START_STOP))
834200886Sthompsa		quirks |= NO_START_STOP;
835200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_GETMAXLUN))
836200886Sthompsa		quirks |= NO_GETMAXLUN;
837200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY))
838200886Sthompsa		quirks |= NO_INQUIRY;
839200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY_EVPD))
840200886Sthompsa		quirks |= NO_INQUIRY_EVPD;
841242628Smarcel	if (usb_test_quirk(uaa, UQ_MSC_NO_PREVENT_ALLOW))
842242628Smarcel		quirks |= NO_PREVENT_ALLOW;
843200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_NO_SYNC_CACHE))
844200886Sthompsa		quirks |= NO_SYNCHRONIZE_CACHE;
845200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_SHUTTLE_INIT))
846200886Sthompsa		quirks |= SHUTTLE_INIT;
847200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_ALT_IFACE_1))
848200886Sthompsa		quirks |= ALT_IFACE_1;
849200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_FLOPPY_SPEED))
850200886Sthompsa		quirks |= FLOPPY_SPEED;
851200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_IGNORE_RESIDUE))
852200886Sthompsa		quirks |= IGNORE_RESIDUE;
853200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_WRONG_CSWSIG))
854200886Sthompsa		quirks |= WRONG_CSWSIG;
855200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_RBC_PAD_TO_12))
856200886Sthompsa		quirks |= RBC_PAD_TO_12;
857200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_READ_CAP_OFFBY1))
858200886Sthompsa		quirks |= READ_CAPACITY_OFFBY1;
859200886Sthompsa	if (usb_test_quirk(uaa, UQ_MSC_FORCE_SHORT_INQ))
860200886Sthompsa		quirks |= FORCE_SHORT_INQUIRY;
861200886Sthompsa
862184610Salfreddone:
863200886Sthompsa	ret.quirks = quirks;
864200886Sthompsa	ret.proto = proto;
865184610Salfred	return (ret);
866184610Salfred}
867184610Salfred
868184610Salfredstatic int
869184610Salfredumass_probe(device_t dev)
870184610Salfred{
871192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
872184610Salfred	struct umass_probe_proto temp;
873184610Salfred
874192499Sthompsa	if (uaa->usb_mode != USB_MODE_HOST) {
875184610Salfred		return (ENXIO);
876184610Salfred	}
877184610Salfred	temp = umass_probe_proto(dev, uaa);
878184610Salfred
879184610Salfred	return (temp.error);
880184610Salfred}
881184610Salfred
882184610Salfredstatic int
883184610Salfredumass_attach(device_t dev)
884184610Salfred{
885184610Salfred	struct umass_softc *sc = device_get_softc(dev);
886192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
887184610Salfred	struct umass_probe_proto temp = umass_probe_proto(dev, uaa);
888192984Sthompsa	struct usb_interface_descriptor *id;
889244491Shselasky	int err;
890184610Salfred
891184610Salfred	/*
892227461Shselasky	 * NOTE: the softc struct is cleared in device_set_driver.
893184610Salfred	 * We can safely call umass_detach without specifically
894184610Salfred	 * initializing the struct.
895184610Salfred	 */
896184610Salfred
897184610Salfred	sc->sc_dev = dev;
898184610Salfred	sc->sc_udev = uaa->device;
899184610Salfred	sc->sc_proto = temp.proto;
900184610Salfred	sc->sc_quirks = temp.quirks;
901184610Salfred	sc->sc_unit = device_get_unit(dev);
902184610Salfred
903184610Salfred	snprintf(sc->sc_name, sizeof(sc->sc_name),
904184610Salfred	    "%s", device_get_nameunit(dev));
905184610Salfred
906194228Sthompsa	device_set_usb_desc(dev);
907184610Salfred
908188415Sthompsa        mtx_init(&sc->sc_mtx, device_get_nameunit(dev),
909188415Sthompsa	    NULL, MTX_DEF | MTX_RECURSE);
910188415Sthompsa
911184610Salfred	/* get interface index */
912184610Salfred
913194228Sthompsa	id = usbd_get_interface_descriptor(uaa->iface);
914184610Salfred	if (id == NULL) {
915184610Salfred		device_printf(dev, "failed to get "
916184610Salfred		    "interface number\n");
917184610Salfred		goto detach;
918184610Salfred	}
919184610Salfred	sc->sc_iface_no = id->bInterfaceNumber;
920184610Salfred
921207077Sthompsa#ifdef USB_DEBUG
922184610Salfred	device_printf(dev, " ");
923184610Salfred
924184610Salfred	switch (sc->sc_proto & UMASS_PROTO_COMMAND) {
925184610Salfred	case UMASS_PROTO_SCSI:
926184610Salfred		printf("SCSI");
927184610Salfred		break;
928184610Salfred	case UMASS_PROTO_ATAPI:
929184610Salfred		printf("8070i (ATAPI)");
930184610Salfred		break;
931184610Salfred	case UMASS_PROTO_UFI:
932184610Salfred		printf("UFI");
933184610Salfred		break;
934184610Salfred	case UMASS_PROTO_RBC:
935184610Salfred		printf("RBC");
936184610Salfred		break;
937184610Salfred	default:
938184610Salfred		printf("(unknown 0x%02x)",
939184610Salfred		    sc->sc_proto & UMASS_PROTO_COMMAND);
940184610Salfred		break;
941184610Salfred	}
942184610Salfred
943184610Salfred	printf(" over ");
944184610Salfred
945184610Salfred	switch (sc->sc_proto & UMASS_PROTO_WIRE) {
946184610Salfred	case UMASS_PROTO_BBB:
947184610Salfred		printf("Bulk-Only");
948184610Salfred		break;
949184610Salfred	case UMASS_PROTO_CBI:		/* uses Comand/Bulk pipes */
950184610Salfred		printf("CBI");
951184610Salfred		break;
952184610Salfred	case UMASS_PROTO_CBI_I:	/* uses Comand/Bulk/Interrupt pipes */
953184610Salfred		printf("CBI with CCI");
954184610Salfred		break;
955184610Salfred	default:
956184610Salfred		printf("(unknown 0x%02x)",
957184610Salfred		    sc->sc_proto & UMASS_PROTO_WIRE);
958184610Salfred	}
959184610Salfred
960184610Salfred	printf("; quirks = 0x%04x\n", sc->sc_quirks);
961184610Salfred#endif
962184610Salfred
963184610Salfred	if (sc->sc_quirks & ALT_IFACE_1) {
964194228Sthompsa		err = usbd_set_alt_interface_index
965184610Salfred		    (uaa->device, uaa->info.bIfaceIndex, 1);
966184610Salfred
967184610Salfred		if (err) {
968184610Salfred			DPRINTF(sc, UDMASS_USB, "could not switch to "
969184610Salfred			    "Alt Interface 1\n");
970184610Salfred			goto detach;
971184610Salfred		}
972184610Salfred	}
973184610Salfred	/* allocate all required USB transfers */
974184610Salfred
975184610Salfred	if (sc->sc_proto & UMASS_PROTO_BBB) {
976184610Salfred
977194228Sthompsa		err = usbd_transfer_setup(uaa->device,
978184610Salfred		    &uaa->info.bIfaceIndex, sc->sc_xfer, umass_bbb_config,
979188415Sthompsa		    UMASS_T_BBB_MAX, sc, &sc->sc_mtx);
980184610Salfred
981184610Salfred		/* skip reset first time */
982184610Salfred		sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
983184610Salfred
984184610Salfred	} else if (sc->sc_proto & (UMASS_PROTO_CBI | UMASS_PROTO_CBI_I)) {
985184610Salfred
986194228Sthompsa		err = usbd_transfer_setup(uaa->device,
987184610Salfred		    &uaa->info.bIfaceIndex, sc->sc_xfer, umass_cbi_config,
988203145Sthompsa		    UMASS_T_CBI_MAX, sc, &sc->sc_mtx);
989184610Salfred
990184610Salfred		/* skip reset first time */
991184610Salfred		sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
992184610Salfred
993184610Salfred	} else {
994184610Salfred		err = USB_ERR_INVAL;
995184610Salfred	}
996184610Salfred
997184610Salfred	if (err) {
998184610Salfred		device_printf(dev, "could not setup required "
999194228Sthompsa		    "transfers, %s\n", usbd_errstr(err));
1000184610Salfred		goto detach;
1001184610Salfred	}
1002244491Shselasky#ifdef USB_DEBUG
1003244491Shselasky	if (umass_throttle > 0) {
1004244491Shselasky		uint8_t x;
1005244491Shselasky		int iv;
1006244491Shselasky
1007244491Shselasky		iv = umass_throttle;
1008244491Shselasky
1009244491Shselasky		if (iv < 1)
1010244491Shselasky			iv = 1;
1011244491Shselasky		else if (iv > 8000)
1012244491Shselasky			iv = 8000;
1013244491Shselasky
1014244491Shselasky		for (x = 0; x != UMASS_T_MAX; x++) {
1015244491Shselasky			if (sc->sc_xfer[x] != NULL)
1016244491Shselasky				usbd_xfer_set_interval(sc->sc_xfer[x], iv);
1017244491Shselasky		}
1018244491Shselasky	}
1019244491Shselasky#endif
1020184610Salfred	sc->sc_transform =
1021184610Salfred	    (sc->sc_proto & UMASS_PROTO_SCSI) ? &umass_scsi_transform :
1022184610Salfred	    (sc->sc_proto & UMASS_PROTO_UFI) ? &umass_ufi_transform :
1023184610Salfred	    (sc->sc_proto & UMASS_PROTO_ATAPI) ? &umass_atapi_transform :
1024184610Salfred	    (sc->sc_proto & UMASS_PROTO_RBC) ? &umass_rbc_transform :
1025184610Salfred	    &umass_no_transform;
1026184610Salfred
1027184610Salfred	/* from here onwards the device can be used. */
1028184610Salfred
1029184610Salfred	if (sc->sc_quirks & SHUTTLE_INIT) {
1030184610Salfred		umass_init_shuttle(sc);
1031184610Salfred	}
1032184610Salfred	/* get the maximum LUN supported by the device */
1033184610Salfred
1034184610Salfred	if (((sc->sc_proto & UMASS_PROTO_WIRE) == UMASS_PROTO_BBB) &&
1035184610Salfred	    !(sc->sc_quirks & NO_GETMAXLUN))
1036184610Salfred		sc->sc_maxlun = umass_bbb_get_max_lun(sc);
1037184610Salfred	else
1038184610Salfred		sc->sc_maxlun = 0;
1039184610Salfred
1040184610Salfred	/* Prepare the SCSI command block */
1041184610Salfred	sc->cam_scsi_sense.opcode = REQUEST_SENSE;
1042184610Salfred	sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY;
1043184610Salfred
1044184610Salfred	/* register the SIM */
1045184610Salfred	err = umass_cam_attach_sim(sc);
1046184610Salfred	if (err) {
1047184610Salfred		goto detach;
1048184610Salfred	}
1049184610Salfred	/* scan the SIM */
1050184610Salfred	umass_cam_attach(sc);
1051184610Salfred
1052184610Salfred	DPRINTF(sc, UDMASS_GEN, "Attach finished\n");
1053184610Salfred
1054184610Salfred	return (0);			/* success */
1055184610Salfred
1056184610Salfreddetach:
1057184610Salfred	umass_detach(dev);
1058184610Salfred	return (ENXIO);			/* failure */
1059184610Salfred}
1060184610Salfred
1061184610Salfredstatic int
1062184610Salfredumass_detach(device_t dev)
1063184610Salfred{
1064184610Salfred	struct umass_softc *sc = device_get_softc(dev);
1065184610Salfred
1066184610Salfred	DPRINTF(sc, UDMASS_USB, "\n");
1067184610Salfred
1068184610Salfred	/* teardown our statemachine */
1069184610Salfred
1070194228Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, UMASS_T_MAX);
1071184610Salfred
1072188415Sthompsa	mtx_lock(&sc->sc_mtx);
1073232358Shselasky
1074232358Shselasky	/* cancel any leftover CCB's */
1075232358Shselasky
1076232358Shselasky	umass_cancel_ccb(sc);
1077232358Shselasky
1078184610Salfred	umass_cam_detach_sim(sc);
1079184610Salfred
1080188415Sthompsa	mtx_unlock(&sc->sc_mtx);
1081232361Shselasky
1082199061Sthompsa	mtx_destroy(&sc->sc_mtx);
1083184610Salfred
1084184610Salfred	return (0);			/* success */
1085184610Salfred}
1086184610Salfred
1087184610Salfredstatic void
1088184610Salfredumass_init_shuttle(struct umass_softc *sc)
1089184610Salfred{
1090192984Sthompsa	struct usb_device_request req;
1091193045Sthompsa	usb_error_t err;
1092184610Salfred	uint8_t status[2] = {0, 0};
1093184610Salfred
1094184610Salfred	/*
1095184610Salfred	 * The Linux driver does this, but no one can tell us what the
1096184610Salfred	 * command does.
1097184610Salfred	 */
1098184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
1099184610Salfred	req.bRequest = 1;		/* XXX unknown command */
1100184610Salfred	USETW(req.wValue, 0);
1101184610Salfred	req.wIndex[0] = sc->sc_iface_no;
1102184610Salfred	req.wIndex[1] = 0;
1103184610Salfred	USETW(req.wLength, sizeof(status));
1104194228Sthompsa	err = usbd_do_request(sc->sc_udev, NULL, &req, &status);
1105184610Salfred
1106184610Salfred	DPRINTF(sc, UDMASS_GEN, "Shuttle init returned 0x%02x%02x\n",
1107184610Salfred	    status[0], status[1]);
1108184610Salfred}
1109184610Salfred
1110184610Salfred/*
1111184610Salfred * Generic functions to handle transfers
1112184610Salfred */
1113184610Salfred
1114184610Salfredstatic void
1115184610Salfredumass_transfer_start(struct umass_softc *sc, uint8_t xfer_index)
1116184610Salfred{
1117184610Salfred	DPRINTF(sc, UDMASS_GEN, "transfer index = "
1118184610Salfred	    "%d\n", xfer_index);
1119184610Salfred
1120184610Salfred	if (sc->sc_xfer[xfer_index]) {
1121184610Salfred		sc->sc_last_xfer_index = xfer_index;
1122194228Sthompsa		usbd_transfer_start(sc->sc_xfer[xfer_index]);
1123184610Salfred	} else {
1124184610Salfred		umass_cancel_ccb(sc);
1125184610Salfred	}
1126184610Salfred}
1127184610Salfred
1128184610Salfredstatic void
1129184610Salfredumass_reset(struct umass_softc *sc)
1130184610Salfred{
1131184610Salfred	DPRINTF(sc, UDMASS_GEN, "resetting device\n");
1132184610Salfred
1133184610Salfred	/*
1134184610Salfred	 * stop the last transfer, if not already stopped:
1135184610Salfred	 */
1136194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[sc->sc_last_xfer_index]);
1137184610Salfred	umass_transfer_start(sc, 0);
1138184610Salfred}
1139184610Salfred
1140184610Salfredstatic void
1141184610Salfredumass_cancel_ccb(struct umass_softc *sc)
1142184610Salfred{
1143184610Salfred	union ccb *ccb;
1144184610Salfred
1145188415Sthompsa	mtx_assert(&sc->sc_mtx, MA_OWNED);
1146184610Salfred
1147184610Salfred	ccb = sc->sc_transfer.ccb;
1148184610Salfred	sc->sc_transfer.ccb = NULL;
1149184610Salfred	sc->sc_last_xfer_index = 0;
1150184610Salfred
1151184610Salfred	if (ccb) {
1152184610Salfred		(sc->sc_transfer.callback)
1153184610Salfred		    (sc, ccb, (sc->sc_transfer.data_len -
1154184610Salfred		    sc->sc_transfer.actlen), STATUS_WIRE_FAILED);
1155184610Salfred	}
1156184610Salfred}
1157184610Salfred
1158184610Salfredstatic void
1159194677Sthompsaumass_tr_error(struct usb_xfer *xfer, usb_error_t error)
1160184610Salfred{
1161194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1162184610Salfred
1163194677Sthompsa	if (error != USB_ERR_CANCELLED) {
1164184610Salfred
1165184610Salfred		DPRINTF(sc, UDMASS_GEN, "transfer error, %s -> "
1166194677Sthompsa		    "reset\n", usbd_errstr(error));
1167184610Salfred	}
1168184610Salfred	umass_cancel_ccb(sc);
1169184610Salfred}
1170184610Salfred
1171184610Salfred/*
1172184610Salfred * BBB protocol specific functions
1173184610Salfred */
1174184610Salfred
1175184610Salfredstatic void
1176194677Sthompsaumass_t_bbb_reset1_callback(struct usb_xfer *xfer, usb_error_t error)
1177184610Salfred{
1178194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1179192984Sthompsa	struct usb_device_request req;
1180194677Sthompsa	struct usb_page_cache *pc;
1181184610Salfred
1182184610Salfred	switch (USB_GET_STATE(xfer)) {
1183184610Salfred	case USB_ST_TRANSFERRED:
1184184610Salfred		umass_transfer_start(sc, UMASS_T_BBB_RESET2);
1185184610Salfred		return;
1186184610Salfred
1187184610Salfred	case USB_ST_SETUP:
1188184610Salfred		/*
1189184610Salfred		 * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
1190184610Salfred		 *
1191184610Salfred		 * For Reset Recovery the host shall issue in the following order:
1192184610Salfred		 * a) a Bulk-Only Mass Storage Reset
1193184610Salfred		 * b) a Clear Feature HALT to the Bulk-In endpoint
1194184610Salfred		 * c) a Clear Feature HALT to the Bulk-Out endpoint
1195184610Salfred		 *
1196184610Salfred		 * This is done in 3 steps, using 3 transfers:
1197184610Salfred		 * UMASS_T_BBB_RESET1
1198184610Salfred		 * UMASS_T_BBB_RESET2
1199184610Salfred		 * UMASS_T_BBB_RESET3
1200184610Salfred		 */
1201184610Salfred
1202184610Salfred		DPRINTF(sc, UDMASS_BBB, "BBB reset!\n");
1203184610Salfred
1204184610Salfred		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1205184610Salfred		req.bRequest = UR_BBB_RESET;	/* bulk only reset */
1206184610Salfred		USETW(req.wValue, 0);
1207184610Salfred		req.wIndex[0] = sc->sc_iface_no;
1208184610Salfred		req.wIndex[1] = 0;
1209184610Salfred		USETW(req.wLength, 0);
1210184610Salfred
1211194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1212194677Sthompsa		usbd_copy_in(pc, 0, &req, sizeof(req));
1213184610Salfred
1214194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1215194677Sthompsa		usbd_xfer_set_frames(xfer, 1);
1216194228Sthompsa		usbd_transfer_submit(xfer);
1217184610Salfred		return;
1218184610Salfred
1219184610Salfred	default:			/* Error */
1220194677Sthompsa		umass_tr_error(xfer, error);
1221184610Salfred		return;
1222184610Salfred	}
1223184610Salfred}
1224184610Salfred
1225184610Salfredstatic void
1226194677Sthompsaumass_t_bbb_reset2_callback(struct usb_xfer *xfer, usb_error_t error)
1227184610Salfred{
1228184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_RESET3,
1229194677Sthompsa	    UMASS_T_BBB_DATA_READ, error);
1230184610Salfred}
1231184610Salfred
1232184610Salfredstatic void
1233194677Sthompsaumass_t_bbb_reset3_callback(struct usb_xfer *xfer, usb_error_t error)
1234184610Salfred{
1235184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_COMMAND,
1236194677Sthompsa	    UMASS_T_BBB_DATA_WRITE, error);
1237184610Salfred}
1238184610Salfred
1239184610Salfredstatic void
1240192984Sthompsaumass_t_bbb_data_clear_stall_callback(struct usb_xfer *xfer,
1241194677Sthompsa    uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error)
1242184610Salfred{
1243194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1244184610Salfred
1245184610Salfred	switch (USB_GET_STATE(xfer)) {
1246184610Salfred	case USB_ST_TRANSFERRED:
1247184610Salfredtr_transferred:
1248184610Salfred		umass_transfer_start(sc, next_xfer);
1249184610Salfred		return;
1250184610Salfred
1251184610Salfred	case USB_ST_SETUP:
1252194228Sthompsa		if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) {
1253184610Salfred			goto tr_transferred;
1254184610Salfred		}
1255184610Salfred		return;
1256184610Salfred
1257184610Salfred	default:			/* Error */
1258194677Sthompsa		umass_tr_error(xfer, error);
1259184610Salfred		return;
1260184610Salfred	}
1261184610Salfred}
1262184610Salfred
1263184610Salfredstatic void
1264194677Sthompsaumass_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
1265184610Salfred{
1266194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1267184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
1268194677Sthompsa	struct usb_page_cache *pc;
1269184610Salfred	uint32_t tag;
1270184610Salfred
1271184610Salfred	switch (USB_GET_STATE(xfer)) {
1272184610Salfred	case USB_ST_TRANSFERRED:
1273184610Salfred		umass_transfer_start
1274184610Salfred		    (sc, ((sc->sc_transfer.dir == DIR_IN) ? UMASS_T_BBB_DATA_READ :
1275184610Salfred		    (sc->sc_transfer.dir == DIR_OUT) ? UMASS_T_BBB_DATA_WRITE :
1276184610Salfred		    UMASS_T_BBB_STATUS));
1277184610Salfred		return;
1278184610Salfred
1279184610Salfred	case USB_ST_SETUP:
1280184610Salfred
1281184610Salfred		sc->sc_status_try = 0;
1282184610Salfred
1283184610Salfred		if (ccb) {
1284184610Salfred
1285184610Salfred			/*
1286184610Salfred		         * the initial value is not important,
1287184610Salfred		         * as long as the values are unique:
1288184610Salfred		         */
1289184610Salfred			tag = UGETDW(sc->cbw.dCBWTag) + 1;
1290184610Salfred
1291184610Salfred			USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE);
1292184610Salfred			USETDW(sc->cbw.dCBWTag, tag);
1293184610Salfred
1294184610Salfred			/*
1295184610Salfred		         * dCBWDataTransferLength:
1296184610Salfred		         *   This field indicates the number of bytes of data that the host
1297184610Salfred		         *   intends to transfer on the IN or OUT Bulk endpoint(as indicated by
1298184610Salfred		         *   the Direction bit) during the execution of this command. If this
1299184610Salfred		         *   field is set to 0, the device will expect that no data will be
1300184610Salfred		         *   transferred IN or OUT during this command, regardless of the value
1301184610Salfred		         *   of the Direction bit defined in dCBWFlags.
1302184610Salfred		         */
1303184610Salfred			USETDW(sc->cbw.dCBWDataTransferLength, sc->sc_transfer.data_len);
1304184610Salfred
1305184610Salfred			/*
1306184610Salfred		         * dCBWFlags:
1307184610Salfred		         *   The bits of the Flags field are defined as follows:
1308184610Salfred		         *     Bits 0-6  reserved
1309184610Salfred		         *     Bit  7    Direction - this bit shall be ignored if the
1310184610Salfred		         *                           dCBWDataTransferLength field is zero.
1311184610Salfred		         *               0 = data Out from host to device
1312184610Salfred		         *               1 = data In from device to host
1313184610Salfred		         */
1314184610Salfred			sc->cbw.bCBWFlags = ((sc->sc_transfer.dir == DIR_IN) ?
1315184610Salfred			    CBWFLAGS_IN : CBWFLAGS_OUT);
1316184610Salfred			sc->cbw.bCBWLUN = sc->sc_transfer.lun;
1317184610Salfred
1318184610Salfred			if (sc->sc_transfer.cmd_len > sizeof(sc->cbw.CBWCDB)) {
1319184610Salfred				sc->sc_transfer.cmd_len = sizeof(sc->cbw.CBWCDB);
1320184610Salfred				DPRINTF(sc, UDMASS_BBB, "Truncating long command!\n");
1321184610Salfred			}
1322184610Salfred			sc->cbw.bCDBLength = sc->sc_transfer.cmd_len;
1323184610Salfred
1324255472Shselasky			/* copy SCSI command data */
1325227461Shselasky			memcpy(sc->cbw.CBWCDB, sc->sc_transfer.cmd_data,
1326184610Salfred			    sc->sc_transfer.cmd_len);
1327184610Salfred
1328255472Shselasky			/* clear remaining command area */
1329255472Shselasky			memset(sc->cbw.CBWCDB +
1330227461Shselasky			    sc->sc_transfer.cmd_len, 0,
1331227461Shselasky			    sizeof(sc->cbw.CBWCDB) -
1332227461Shselasky			    sc->sc_transfer.cmd_len);
1333184610Salfred
1334184610Salfred			DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw));
1335184610Salfred
1336194677Sthompsa			pc = usbd_xfer_get_frame(xfer, 0);
1337194677Sthompsa			usbd_copy_in(pc, 0, &sc->cbw, sizeof(sc->cbw));
1338194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, sizeof(sc->cbw));
1339184610Salfred
1340194228Sthompsa			usbd_transfer_submit(xfer);
1341184610Salfred		}
1342184610Salfred		return;
1343184610Salfred
1344184610Salfred	default:			/* Error */
1345194677Sthompsa		umass_tr_error(xfer, error);
1346184610Salfred		return;
1347184610Salfred	}
1348184610Salfred}
1349184610Salfred
1350184610Salfredstatic void
1351194677Sthompsaumass_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
1352184610Salfred{
1353194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1354194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1355194677Sthompsa	int actlen, sumlen;
1356184610Salfred
1357194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1358194677Sthompsa
1359184610Salfred	switch (USB_GET_STATE(xfer)) {
1360184610Salfred	case USB_ST_TRANSFERRED:
1361194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
1362194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
1363194677Sthompsa		sc->sc_transfer.actlen += actlen;
1364184610Salfred
1365194677Sthompsa		if (actlen < sumlen) {
1366184610Salfred			/* short transfer */
1367184610Salfred			sc->sc_transfer.data_rem = 0;
1368184610Salfred		}
1369184610Salfred	case USB_ST_SETUP:
1370184610Salfred		DPRINTF(sc, UDMASS_BBB, "max_bulk=%d, data_rem=%d\n",
1371184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
1372184610Salfred
1373184610Salfred		if (sc->sc_transfer.data_rem == 0) {
1374184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_STATUS);
1375184610Salfred			return;
1376184610Salfred		}
1377184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
1378184610Salfred			max_bulk = sc->sc_transfer.data_rem;
1379184610Salfred		}
1380194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1381184610Salfred
1382194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1383194677Sthompsa		    max_bulk);
1384232361Shselasky
1385194228Sthompsa		usbd_transfer_submit(xfer);
1386184610Salfred		return;
1387184610Salfred
1388184610Salfred	default:			/* Error */
1389194677Sthompsa		if (error == USB_ERR_CANCELLED) {
1390194677Sthompsa			umass_tr_error(xfer, error);
1391184610Salfred		} else {
1392184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS);
1393184610Salfred		}
1394184610Salfred		return;
1395184610Salfred	}
1396184610Salfred}
1397184610Salfred
1398184610Salfredstatic void
1399194677Sthompsaumass_t_bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1400184610Salfred{
1401184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS,
1402194677Sthompsa	    UMASS_T_BBB_DATA_READ, error);
1403184610Salfred}
1404184610Salfred
1405184610Salfredstatic void
1406194677Sthompsaumass_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
1407184610Salfred{
1408194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1409194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1410194677Sthompsa	int actlen, sumlen;
1411184610Salfred
1412194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1413194677Sthompsa
1414184610Salfred	switch (USB_GET_STATE(xfer)) {
1415184610Salfred	case USB_ST_TRANSFERRED:
1416194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
1417194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
1418194677Sthompsa		sc->sc_transfer.actlen += actlen;
1419184610Salfred
1420194677Sthompsa		if (actlen < sumlen) {
1421184610Salfred			/* short transfer */
1422184610Salfred			sc->sc_transfer.data_rem = 0;
1423184610Salfred		}
1424184610Salfred	case USB_ST_SETUP:
1425184610Salfred		DPRINTF(sc, UDMASS_BBB, "max_bulk=%d, data_rem=%d\n",
1426184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
1427184610Salfred
1428184610Salfred		if (sc->sc_transfer.data_rem == 0) {
1429184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_STATUS);
1430184610Salfred			return;
1431184610Salfred		}
1432184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
1433184610Salfred			max_bulk = sc->sc_transfer.data_rem;
1434184610Salfred		}
1435194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1436184610Salfred
1437194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1438194677Sthompsa		    max_bulk);
1439184610Salfred
1440194228Sthompsa		usbd_transfer_submit(xfer);
1441184610Salfred		return;
1442184610Salfred
1443184610Salfred	default:			/* Error */
1444194677Sthompsa		if (error == USB_ERR_CANCELLED) {
1445194677Sthompsa			umass_tr_error(xfer, error);
1446184610Salfred		} else {
1447184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_DATA_WR_CS);
1448184610Salfred		}
1449184610Salfred		return;
1450184610Salfred	}
1451184610Salfred}
1452184610Salfred
1453184610Salfredstatic void
1454194677Sthompsaumass_t_bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1455184610Salfred{
1456184610Salfred	umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS,
1457194677Sthompsa	    UMASS_T_BBB_DATA_WRITE, error);
1458184610Salfred}
1459184610Salfred
1460184610Salfredstatic void
1461194677Sthompsaumass_t_bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
1462184610Salfred{
1463194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1464184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
1465194677Sthompsa	struct usb_page_cache *pc;
1466184610Salfred	uint32_t residue;
1467194677Sthompsa	int actlen;
1468184610Salfred
1469194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1470194677Sthompsa
1471184610Salfred	switch (USB_GET_STATE(xfer)) {
1472184610Salfred	case USB_ST_TRANSFERRED:
1473184610Salfred
1474184610Salfred		/*
1475184610Salfred		 * Do a full reset if there is something wrong with the CSW:
1476184610Salfred		 */
1477184610Salfred		sc->sc_status_try = 1;
1478184610Salfred
1479184610Salfred		/* Zero missing parts of the CSW: */
1480184610Salfred
1481233774Shselasky		if (actlen < (int)sizeof(sc->csw))
1482227461Shselasky			memset(&sc->csw, 0, sizeof(sc->csw));
1483227461Shselasky
1484194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1485194677Sthompsa		usbd_copy_out(pc, 0, &sc->csw, actlen);
1486184610Salfred
1487184610Salfred		DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw));
1488184610Salfred
1489184610Salfred		residue = UGETDW(sc->csw.dCSWDataResidue);
1490184610Salfred
1491189905Sthompsa		if ((!residue) || (sc->sc_quirks & IGNORE_RESIDUE)) {
1492184610Salfred			residue = (sc->sc_transfer.data_len -
1493184610Salfred			    sc->sc_transfer.actlen);
1494184610Salfred		}
1495184610Salfred		if (residue > sc->sc_transfer.data_len) {
1496184610Salfred			DPRINTF(sc, UDMASS_BBB, "truncating residue from %d "
1497184610Salfred			    "to %d bytes\n", residue, sc->sc_transfer.data_len);
1498184610Salfred			residue = sc->sc_transfer.data_len;
1499184610Salfred		}
1500184610Salfred		/* translate weird command-status signatures: */
1501184610Salfred		if (sc->sc_quirks & WRONG_CSWSIG) {
1502184610Salfred
1503184610Salfred			uint32_t temp = UGETDW(sc->csw.dCSWSignature);
1504184610Salfred
1505184610Salfred			if ((temp == CSWSIGNATURE_OLYMPUS_C1) ||
1506184610Salfred			    (temp == CSWSIGNATURE_IMAGINATION_DBX1)) {
1507184610Salfred				USETDW(sc->csw.dCSWSignature, CSWSIGNATURE);
1508184610Salfred			}
1509184610Salfred		}
1510184610Salfred		/* check CSW and handle eventual error */
1511184610Salfred		if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) {
1512184610Salfred			DPRINTF(sc, UDMASS_BBB, "bad CSW signature 0x%08x != 0x%08x\n",
1513184610Salfred			    UGETDW(sc->csw.dCSWSignature), CSWSIGNATURE);
1514184610Salfred			/*
1515184610Salfred			 * Invalid CSW: Wrong signature or wrong tag might
1516184610Salfred			 * indicate that we lost synchronization. Reset the
1517184610Salfred			 * device.
1518184610Salfred			 */
1519184610Salfred			goto tr_error;
1520184610Salfred		} else if (UGETDW(sc->csw.dCSWTag) != UGETDW(sc->cbw.dCBWTag)) {
1521184610Salfred			DPRINTF(sc, UDMASS_BBB, "Invalid CSW: tag 0x%08x should be "
1522184610Salfred			    "0x%08x\n", UGETDW(sc->csw.dCSWTag),
1523184610Salfred			    UGETDW(sc->cbw.dCBWTag));
1524184610Salfred			goto tr_error;
1525184610Salfred		} else if (sc->csw.bCSWStatus > CSWSTATUS_PHASE) {
1526184610Salfred			DPRINTF(sc, UDMASS_BBB, "Invalid CSW: status %d > %d\n",
1527184610Salfred			    sc->csw.bCSWStatus, CSWSTATUS_PHASE);
1528184610Salfred			goto tr_error;
1529184610Salfred		} else if (sc->csw.bCSWStatus == CSWSTATUS_PHASE) {
1530184610Salfred			DPRINTF(sc, UDMASS_BBB, "Phase error, residue = "
1531184610Salfred			    "%d\n", residue);
1532184610Salfred			goto tr_error;
1533184610Salfred		} else if (sc->sc_transfer.actlen > sc->sc_transfer.data_len) {
1534184610Salfred			DPRINTF(sc, UDMASS_BBB, "Buffer overrun %d > %d\n",
1535184610Salfred			    sc->sc_transfer.actlen, sc->sc_transfer.data_len);
1536184610Salfred			goto tr_error;
1537184610Salfred		} else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) {
1538184610Salfred			DPRINTF(sc, UDMASS_BBB, "Command failed, residue = "
1539184610Salfred			    "%d\n", residue);
1540184610Salfred
1541184610Salfred			sc->sc_transfer.ccb = NULL;
1542184610Salfred
1543184610Salfred			sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
1544184610Salfred
1545184610Salfred			(sc->sc_transfer.callback)
1546184610Salfred			    (sc, ccb, residue, STATUS_CMD_FAILED);
1547184610Salfred		} else {
1548184610Salfred			sc->sc_transfer.ccb = NULL;
1549184610Salfred
1550184610Salfred			sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND;
1551184610Salfred
1552184610Salfred			(sc->sc_transfer.callback)
1553184610Salfred			    (sc, ccb, residue, STATUS_CMD_OK);
1554184610Salfred		}
1555184610Salfred		return;
1556184610Salfred
1557184610Salfred	case USB_ST_SETUP:
1558194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
1559194228Sthompsa		usbd_transfer_submit(xfer);
1560184610Salfred		return;
1561184610Salfred
1562184610Salfred	default:
1563184610Salfredtr_error:
1564184610Salfred		DPRINTF(sc, UDMASS_BBB, "Failed to read CSW: %s, try %d\n",
1565194677Sthompsa		    usbd_errstr(error), sc->sc_status_try);
1566184610Salfred
1567194677Sthompsa		if ((error == USB_ERR_CANCELLED) ||
1568184610Salfred		    (sc->sc_status_try)) {
1569194677Sthompsa			umass_tr_error(xfer, error);
1570184610Salfred		} else {
1571184610Salfred			sc->sc_status_try = 1;
1572184610Salfred			umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS);
1573184610Salfred		}
1574184610Salfred		return;
1575184610Salfred	}
1576184610Salfred}
1577184610Salfred
1578184610Salfredstatic void
1579184610Salfredumass_command_start(struct umass_softc *sc, uint8_t dir,
1580184610Salfred    void *data_ptr, uint32_t data_len,
1581184610Salfred    uint32_t data_timeout, umass_callback_t *callback,
1582184610Salfred    union ccb *ccb)
1583184610Salfred{
1584184610Salfred	sc->sc_transfer.lun = ccb->ccb_h.target_lun;
1585184610Salfred
1586184610Salfred	/*
1587184610Salfred	 * NOTE: assumes that "sc->sc_transfer.cmd_data" and
1588184610Salfred	 * "sc->sc_transfer.cmd_len" has been properly
1589184610Salfred	 * initialized.
1590184610Salfred	 */
1591184610Salfred
1592184610Salfred	sc->sc_transfer.dir = data_len ? dir : DIR_NONE;
1593184610Salfred	sc->sc_transfer.data_ptr = data_ptr;
1594184610Salfred	sc->sc_transfer.data_len = data_len;
1595184610Salfred	sc->sc_transfer.data_rem = data_len;
1596184610Salfred	sc->sc_transfer.data_timeout = (data_timeout + UMASS_TIMEOUT);
1597184610Salfred
1598184610Salfred	sc->sc_transfer.actlen = 0;
1599184610Salfred	sc->sc_transfer.callback = callback;
1600184610Salfred	sc->sc_transfer.ccb = ccb;
1601184610Salfred
1602184610Salfred	if (sc->sc_xfer[sc->sc_last_xfer_index]) {
1603194228Sthompsa		usbd_transfer_start(sc->sc_xfer[sc->sc_last_xfer_index]);
1604184610Salfred	} else {
1605232358Shselasky		umass_cancel_ccb(sc);
1606184610Salfred	}
1607184610Salfred}
1608184610Salfred
1609184610Salfredstatic uint8_t
1610184610Salfredumass_bbb_get_max_lun(struct umass_softc *sc)
1611184610Salfred{
1612192984Sthompsa	struct usb_device_request req;
1613193045Sthompsa	usb_error_t err;
1614184610Salfred	uint8_t buf = 0;
1615184610Salfred
1616184610Salfred	/* The Get Max Lun command is a class-specific request. */
1617184610Salfred	req.bmRequestType = UT_READ_CLASS_INTERFACE;
1618184610Salfred	req.bRequest = UR_BBB_GET_MAX_LUN;
1619184610Salfred	USETW(req.wValue, 0);
1620184610Salfred	req.wIndex[0] = sc->sc_iface_no;
1621184610Salfred	req.wIndex[1] = 0;
1622184610Salfred	USETW(req.wLength, 1);
1623184610Salfred
1624194228Sthompsa	err = usbd_do_request(sc->sc_udev, NULL, &req, &buf);
1625184610Salfred	if (err) {
1626184610Salfred		buf = 0;
1627184610Salfred
1628184610Salfred		/* Device doesn't support Get Max Lun request. */
1629184610Salfred		printf("%s: Get Max Lun not supported (%s)\n",
1630194228Sthompsa		    sc->sc_name, usbd_errstr(err));
1631184610Salfred	}
1632184610Salfred	return (buf);
1633184610Salfred}
1634184610Salfred
1635184610Salfred/*
1636184610Salfred * Command/Bulk/Interrupt (CBI) specific functions
1637184610Salfred */
1638184610Salfred
1639184610Salfredstatic void
1640184610Salfredumass_cbi_start_status(struct umass_softc *sc)
1641184610Salfred{
1642184610Salfred	if (sc->sc_xfer[UMASS_T_CBI_STATUS]) {
1643184610Salfred		umass_transfer_start(sc, UMASS_T_CBI_STATUS);
1644184610Salfred	} else {
1645184610Salfred		union ccb *ccb = sc->sc_transfer.ccb;
1646184610Salfred
1647184610Salfred		sc->sc_transfer.ccb = NULL;
1648184610Salfred
1649184610Salfred		sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
1650184610Salfred
1651184610Salfred		(sc->sc_transfer.callback)
1652184610Salfred		    (sc, ccb, (sc->sc_transfer.data_len -
1653184610Salfred		    sc->sc_transfer.actlen), STATUS_CMD_UNKNOWN);
1654184610Salfred	}
1655184610Salfred}
1656184610Salfred
1657184610Salfredstatic void
1658194677Sthompsaumass_t_cbi_reset1_callback(struct usb_xfer *xfer, usb_error_t error)
1659184610Salfred{
1660194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1661192984Sthompsa	struct usb_device_request req;
1662194677Sthompsa	struct usb_page_cache *pc;
1663184610Salfred	uint8_t buf[UMASS_CBI_DIAGNOSTIC_CMDLEN];
1664184610Salfred
1665184610Salfred	uint8_t i;
1666184610Salfred
1667184610Salfred	switch (USB_GET_STATE(xfer)) {
1668184610Salfred	case USB_ST_TRANSFERRED:
1669184610Salfred		umass_transfer_start(sc, UMASS_T_CBI_RESET2);
1670203145Sthompsa		break;
1671184610Salfred
1672184610Salfred	case USB_ST_SETUP:
1673184610Salfred		/*
1674184610Salfred		 * Command Block Reset Protocol
1675184610Salfred		 *
1676184610Salfred		 * First send a reset request to the device. Then clear
1677184610Salfred		 * any possibly stalled bulk endpoints.
1678184610Salfred		 *
1679184610Salfred		 * This is done in 3 steps, using 3 transfers:
1680184610Salfred		 * UMASS_T_CBI_RESET1
1681184610Salfred		 * UMASS_T_CBI_RESET2
1682184610Salfred		 * UMASS_T_CBI_RESET3
1683184610Salfred		 * UMASS_T_CBI_RESET4 (only if there is an interrupt endpoint)
1684184610Salfred		 */
1685184610Salfred
1686184610Salfred		DPRINTF(sc, UDMASS_CBI, "CBI reset!\n");
1687184610Salfred
1688184610Salfred		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1689184610Salfred		req.bRequest = UR_CBI_ADSC;
1690184610Salfred		USETW(req.wValue, 0);
1691184610Salfred		req.wIndex[0] = sc->sc_iface_no;
1692184610Salfred		req.wIndex[1] = 0;
1693184610Salfred		USETW(req.wLength, UMASS_CBI_DIAGNOSTIC_CMDLEN);
1694184610Salfred
1695184610Salfred		/*
1696184610Salfred		 * The 0x1d code is the SEND DIAGNOSTIC command. To
1697184610Salfred		 * distinguish between the two, the last 10 bytes of the CBL
1698184610Salfred		 * is filled with 0xff (section 2.2 of the CBI
1699184610Salfred		 * specification)
1700184610Salfred		 */
1701184610Salfred		buf[0] = 0x1d;		/* Command Block Reset */
1702184610Salfred		buf[1] = 0x04;
1703184610Salfred
1704184610Salfred		for (i = 2; i < UMASS_CBI_DIAGNOSTIC_CMDLEN; i++) {
1705184610Salfred			buf[i] = 0xff;
1706184610Salfred		}
1707184610Salfred
1708194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1709194677Sthompsa		usbd_copy_in(pc, 0, &req, sizeof(req));
1710194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 1);
1711194677Sthompsa		usbd_copy_in(pc, 0, buf, sizeof(buf));
1712184610Salfred
1713194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1714194677Sthompsa		usbd_xfer_set_frame_len(xfer, 1, sizeof(buf));
1715194677Sthompsa		usbd_xfer_set_frames(xfer, 2);
1716194228Sthompsa		usbd_transfer_submit(xfer);
1717203145Sthompsa		break;
1718184610Salfred
1719184610Salfred	default:			/* Error */
1720203145Sthompsa		if (error == USB_ERR_CANCELLED)
1721203145Sthompsa			umass_tr_error(xfer, error);
1722203145Sthompsa		else
1723203145Sthompsa			umass_transfer_start(sc, UMASS_T_CBI_RESET2);
1724203145Sthompsa		break;
1725184610Salfred	}
1726184610Salfred}
1727184610Salfred
1728184610Salfredstatic void
1729194677Sthompsaumass_t_cbi_reset2_callback(struct usb_xfer *xfer, usb_error_t error)
1730184610Salfred{
1731184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_RESET3,
1732194677Sthompsa	    UMASS_T_CBI_DATA_READ, error);
1733184610Salfred}
1734184610Salfred
1735184610Salfredstatic void
1736194677Sthompsaumass_t_cbi_reset3_callback(struct usb_xfer *xfer, usb_error_t error)
1737184610Salfred{
1738194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1739184610Salfred
1740184610Salfred	umass_t_cbi_data_clear_stall_callback
1741184610Salfred	    (xfer, (sc->sc_xfer[UMASS_T_CBI_RESET4] &&
1742184610Salfred	    sc->sc_xfer[UMASS_T_CBI_STATUS]) ?
1743184610Salfred	    UMASS_T_CBI_RESET4 : UMASS_T_CBI_COMMAND,
1744194677Sthompsa	    UMASS_T_CBI_DATA_WRITE, error);
1745184610Salfred}
1746184610Salfred
1747184610Salfredstatic void
1748194677Sthompsaumass_t_cbi_reset4_callback(struct usb_xfer *xfer, usb_error_t error)
1749184610Salfred{
1750184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_COMMAND,
1751194677Sthompsa	    UMASS_T_CBI_STATUS, error);
1752184610Salfred}
1753184610Salfred
1754184610Salfredstatic void
1755192984Sthompsaumass_t_cbi_data_clear_stall_callback(struct usb_xfer *xfer,
1756194677Sthompsa    uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error)
1757184610Salfred{
1758194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1759184610Salfred
1760184610Salfred	switch (USB_GET_STATE(xfer)) {
1761184610Salfred	case USB_ST_TRANSFERRED:
1762184610Salfredtr_transferred:
1763184610Salfred		if (next_xfer == UMASS_T_CBI_STATUS) {
1764184610Salfred			umass_cbi_start_status(sc);
1765184610Salfred		} else {
1766184610Salfred			umass_transfer_start(sc, next_xfer);
1767184610Salfred		}
1768203145Sthompsa		break;
1769184610Salfred
1770184610Salfred	case USB_ST_SETUP:
1771194228Sthompsa		if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) {
1772184610Salfred			goto tr_transferred;	/* should not happen */
1773184610Salfred		}
1774203145Sthompsa		break;
1775184610Salfred
1776184610Salfred	default:			/* Error */
1777194677Sthompsa		umass_tr_error(xfer, error);
1778203145Sthompsa		break;
1779184610Salfred	}
1780184610Salfred}
1781184610Salfred
1782184610Salfredstatic void
1783194677Sthompsaumass_t_cbi_command_callback(struct usb_xfer *xfer, usb_error_t error)
1784184610Salfred{
1785194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1786184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
1787192984Sthompsa	struct usb_device_request req;
1788194677Sthompsa	struct usb_page_cache *pc;
1789184610Salfred
1790184610Salfred	switch (USB_GET_STATE(xfer)) {
1791184610Salfred	case USB_ST_TRANSFERRED:
1792184610Salfred
1793184610Salfred		if (sc->sc_transfer.dir == DIR_NONE) {
1794184610Salfred			umass_cbi_start_status(sc);
1795184610Salfred		} else {
1796184610Salfred			umass_transfer_start
1797184610Salfred			    (sc, (sc->sc_transfer.dir == DIR_IN) ?
1798184610Salfred			    UMASS_T_CBI_DATA_READ : UMASS_T_CBI_DATA_WRITE);
1799184610Salfred		}
1800203145Sthompsa		break;
1801184610Salfred
1802184610Salfred	case USB_ST_SETUP:
1803184610Salfred
1804184610Salfred		if (ccb) {
1805184610Salfred
1806184610Salfred			/*
1807184610Salfred		         * do a CBI transfer with cmd_len bytes from
1808184610Salfred		         * cmd_data, possibly a data phase of data_len
1809184610Salfred		         * bytes from/to the device and finally a status
1810184610Salfred		         * read phase.
1811184610Salfred		         */
1812184610Salfred
1813184610Salfred			req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1814184610Salfred			req.bRequest = UR_CBI_ADSC;
1815184610Salfred			USETW(req.wValue, 0);
1816184610Salfred			req.wIndex[0] = sc->sc_iface_no;
1817184610Salfred			req.wIndex[1] = 0;
1818184610Salfred			req.wLength[0] = sc->sc_transfer.cmd_len;
1819184610Salfred			req.wLength[1] = 0;
1820184610Salfred
1821194677Sthompsa			pc = usbd_xfer_get_frame(xfer, 0);
1822194677Sthompsa			usbd_copy_in(pc, 0, &req, sizeof(req));
1823194677Sthompsa			pc = usbd_xfer_get_frame(xfer, 1);
1824194677Sthompsa			usbd_copy_in(pc, 0, sc->sc_transfer.cmd_data,
1825184610Salfred			    sc->sc_transfer.cmd_len);
1826184610Salfred
1827194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
1828194677Sthompsa			usbd_xfer_set_frame_len(xfer, 1, sc->sc_transfer.cmd_len);
1829194677Sthompsa			usbd_xfer_set_frames(xfer,
1830194677Sthompsa			    sc->sc_transfer.cmd_len ? 2 : 1);
1831184610Salfred
1832184610Salfred			DIF(UDMASS_CBI,
1833184610Salfred			    umass_cbi_dump_cmd(sc,
1834184610Salfred			    sc->sc_transfer.cmd_data,
1835184610Salfred			    sc->sc_transfer.cmd_len));
1836184610Salfred
1837194228Sthompsa			usbd_transfer_submit(xfer);
1838184610Salfred		}
1839203145Sthompsa		break;
1840184610Salfred
1841184610Salfred	default:			/* Error */
1842220535Smav		/*
1843220535Smav		 * STALL on the control pipe can be result of the command error.
1844220535Smav		 * Attempt to clear this STALL same as for bulk pipe also
1845220535Smav		 * results in command completion interrupt, but ASC/ASCQ there
1846220535Smav		 * look like not always valid, so don't bother about it.
1847220535Smav		 */
1848220535Smav		if ((error == USB_ERR_STALLED) ||
1849220535Smav		    (sc->sc_transfer.callback == &umass_cam_cb)) {
1850220535Smav			sc->sc_transfer.ccb = NULL;
1851220535Smav			(sc->sc_transfer.callback)
1852220535Smav			    (sc, ccb, sc->sc_transfer.data_len,
1853220535Smav			    STATUS_CMD_UNKNOWN);
1854220535Smav		} else {
1855220535Smav			umass_tr_error(xfer, error);
1856220535Smav			/* skip reset */
1857220535Smav			sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
1858220535Smav		}
1859203145Sthompsa		break;
1860184610Salfred	}
1861184610Salfred}
1862184610Salfred
1863184610Salfredstatic void
1864194677Sthompsaumass_t_cbi_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
1865184610Salfred{
1866194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1867194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1868194677Sthompsa	int actlen, sumlen;
1869184610Salfred
1870194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1871194677Sthompsa
1872184610Salfred	switch (USB_GET_STATE(xfer)) {
1873184610Salfred	case USB_ST_TRANSFERRED:
1874194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
1875194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
1876194677Sthompsa		sc->sc_transfer.actlen += actlen;
1877184610Salfred
1878194677Sthompsa		if (actlen < sumlen) {
1879184610Salfred			/* short transfer */
1880184610Salfred			sc->sc_transfer.data_rem = 0;
1881184610Salfred		}
1882184610Salfred	case USB_ST_SETUP:
1883184610Salfred		DPRINTF(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n",
1884184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
1885184610Salfred
1886184610Salfred		if (sc->sc_transfer.data_rem == 0) {
1887184610Salfred			umass_cbi_start_status(sc);
1888203145Sthompsa			break;
1889184610Salfred		}
1890184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
1891184610Salfred			max_bulk = sc->sc_transfer.data_rem;
1892184610Salfred		}
1893194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1894184610Salfred
1895194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1896194677Sthompsa		    max_bulk);
1897232361Shselasky
1898194228Sthompsa		usbd_transfer_submit(xfer);
1899203145Sthompsa		break;
1900184610Salfred
1901184610Salfred	default:			/* Error */
1902194677Sthompsa		if ((error == USB_ERR_CANCELLED) ||
1903184610Salfred		    (sc->sc_transfer.callback != &umass_cam_cb)) {
1904194677Sthompsa			umass_tr_error(xfer, error);
1905184610Salfred		} else {
1906184610Salfred			umass_transfer_start(sc, UMASS_T_CBI_DATA_RD_CS);
1907184610Salfred		}
1908203145Sthompsa		break;
1909184610Salfred	}
1910184610Salfred}
1911184610Salfred
1912184610Salfredstatic void
1913194677Sthompsaumass_t_cbi_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1914184610Salfred{
1915184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS,
1916194677Sthompsa	    UMASS_T_CBI_DATA_READ, error);
1917184610Salfred}
1918184610Salfred
1919184610Salfredstatic void
1920194677Sthompsaumass_t_cbi_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
1921184610Salfred{
1922194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1923194677Sthompsa	uint32_t max_bulk = usbd_xfer_max_len(xfer);
1924194677Sthompsa	int actlen, sumlen;
1925184610Salfred
1926194677Sthompsa	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
1927194677Sthompsa
1928184610Salfred	switch (USB_GET_STATE(xfer)) {
1929184610Salfred	case USB_ST_TRANSFERRED:
1930194677Sthompsa		sc->sc_transfer.data_rem -= actlen;
1931194677Sthompsa		sc->sc_transfer.data_ptr += actlen;
1932194677Sthompsa		sc->sc_transfer.actlen += actlen;
1933184610Salfred
1934194677Sthompsa		if (actlen < sumlen) {
1935184610Salfred			/* short transfer */
1936184610Salfred			sc->sc_transfer.data_rem = 0;
1937184610Salfred		}
1938184610Salfred	case USB_ST_SETUP:
1939184610Salfred		DPRINTF(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n",
1940184610Salfred		    max_bulk, sc->sc_transfer.data_rem);
1941184610Salfred
1942184610Salfred		if (sc->sc_transfer.data_rem == 0) {
1943184610Salfred			umass_cbi_start_status(sc);
1944203145Sthompsa			break;
1945184610Salfred		}
1946184610Salfred		if (max_bulk > sc->sc_transfer.data_rem) {
1947184610Salfred			max_bulk = sc->sc_transfer.data_rem;
1948184610Salfred		}
1949194677Sthompsa		usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout);
1950184610Salfred
1951194677Sthompsa		usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr,
1952194677Sthompsa		    max_bulk);
1953184610Salfred
1954194228Sthompsa		usbd_transfer_submit(xfer);
1955203145Sthompsa		break;
1956184610Salfred
1957184610Salfred	default:			/* Error */
1958194677Sthompsa		if ((error == USB_ERR_CANCELLED) ||
1959184610Salfred		    (sc->sc_transfer.callback != &umass_cam_cb)) {
1960194677Sthompsa			umass_tr_error(xfer, error);
1961184610Salfred		} else {
1962184610Salfred			umass_transfer_start(sc, UMASS_T_CBI_DATA_WR_CS);
1963184610Salfred		}
1964203145Sthompsa		break;
1965184610Salfred	}
1966184610Salfred}
1967184610Salfred
1968184610Salfredstatic void
1969194677Sthompsaumass_t_cbi_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
1970184610Salfred{
1971184610Salfred	umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS,
1972194677Sthompsa	    UMASS_T_CBI_DATA_WRITE, error);
1973184610Salfred}
1974184610Salfred
1975184610Salfredstatic void
1976194677Sthompsaumass_t_cbi_status_callback(struct usb_xfer *xfer, usb_error_t error)
1977184610Salfred{
1978194677Sthompsa	struct umass_softc *sc = usbd_xfer_softc(xfer);
1979184610Salfred	union ccb *ccb = sc->sc_transfer.ccb;
1980194677Sthompsa	struct usb_page_cache *pc;
1981184610Salfred	uint32_t residue;
1982184610Salfred	uint8_t status;
1983194677Sthompsa	int actlen;
1984184610Salfred
1985194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1986194677Sthompsa
1987184610Salfred	switch (USB_GET_STATE(xfer)) {
1988184610Salfred	case USB_ST_TRANSFERRED:
1989184610Salfred
1990233774Shselasky		if (actlen < (int)sizeof(sc->sbl)) {
1991184610Salfred			goto tr_setup;
1992184610Salfred		}
1993194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
1994194677Sthompsa		usbd_copy_out(pc, 0, &sc->sbl, sizeof(sc->sbl));
1995184610Salfred
1996184610Salfred		residue = (sc->sc_transfer.data_len -
1997184610Salfred		    sc->sc_transfer.actlen);
1998184610Salfred
1999184610Salfred		/* dissect the information in the buffer */
2000184610Salfred
2001184610Salfred		if (sc->sc_proto & UMASS_PROTO_UFI) {
2002184610Salfred
2003184610Salfred			/*
2004184610Salfred			 * Section 3.4.3.1.3 specifies that the UFI command
2005184610Salfred			 * protocol returns an ASC and ASCQ in the interrupt
2006184610Salfred			 * data block.
2007184610Salfred			 */
2008184610Salfred
2009184610Salfred			DPRINTF(sc, UDMASS_CBI, "UFI CCI, ASC = 0x%02x, "
2010184610Salfred			    "ASCQ = 0x%02x\n", sc->sbl.ufi.asc,
2011184610Salfred			    sc->sbl.ufi.ascq);
2012184610Salfred
2013184610Salfred			status = (((sc->sbl.ufi.asc == 0) &&
2014184610Salfred			    (sc->sbl.ufi.ascq == 0)) ?
2015184610Salfred			    STATUS_CMD_OK : STATUS_CMD_FAILED);
2016184610Salfred
2017184610Salfred			sc->sc_transfer.ccb = NULL;
2018184610Salfred
2019184610Salfred			sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
2020184610Salfred
2021184610Salfred			(sc->sc_transfer.callback)
2022184610Salfred			    (sc, ccb, residue, status);
2023184610Salfred
2024203145Sthompsa			break;
2025184610Salfred
2026184610Salfred		} else {
2027184610Salfred
2028184610Salfred			/* Command Interrupt Data Block */
2029184610Salfred
2030184610Salfred			DPRINTF(sc, UDMASS_CBI, "type=0x%02x, value=0x%02x\n",
2031184610Salfred			    sc->sbl.common.type, sc->sbl.common.value);
2032184610Salfred
2033184610Salfred			if (sc->sbl.common.type == IDB_TYPE_CCI) {
2034184610Salfred
2035184610Salfred				status = (sc->sbl.common.value & IDB_VALUE_STATUS_MASK);
2036184610Salfred
2037184610Salfred				status = ((status == IDB_VALUE_PASS) ? STATUS_CMD_OK :
2038184610Salfred				    (status == IDB_VALUE_FAIL) ? STATUS_CMD_FAILED :
2039184610Salfred				    (status == IDB_VALUE_PERSISTENT) ? STATUS_CMD_FAILED :
2040184610Salfred				    STATUS_WIRE_FAILED);
2041184610Salfred
2042184610Salfred				sc->sc_transfer.ccb = NULL;
2043184610Salfred
2044184610Salfred				sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND;
2045184610Salfred
2046184610Salfred				(sc->sc_transfer.callback)
2047184610Salfred				    (sc, ccb, residue, status);
2048184610Salfred
2049203145Sthompsa				break;
2050184610Salfred			}
2051184610Salfred		}
2052184610Salfred
2053184610Salfred		/* fallthrough */
2054184610Salfred
2055184610Salfred	case USB_ST_SETUP:
2056184610Salfredtr_setup:
2057194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
2058194228Sthompsa		usbd_transfer_submit(xfer);
2059203145Sthompsa		break;
2060184610Salfred
2061184610Salfred	default:			/* Error */
2062184610Salfred		DPRINTF(sc, UDMASS_CBI, "Failed to read CSW: %s\n",
2063194677Sthompsa		    usbd_errstr(error));
2064194677Sthompsa		umass_tr_error(xfer, error);
2065203145Sthompsa		break;
2066184610Salfred	}
2067184610Salfred}
2068184610Salfred
2069184610Salfred/*
2070184610Salfred * CAM specific functions (used by SCSI, UFI, 8070i (ATAPI))
2071184610Salfred */
2072184610Salfred
2073184610Salfredstatic int
2074184610Salfredumass_cam_attach_sim(struct umass_softc *sc)
2075184610Salfred{
2076184610Salfred	struct cam_devq *devq;		/* Per device Queue */
2077184610Salfred
2078184610Salfred	/*
2079184610Salfred	 * A HBA is attached to the CAM layer.
2080184610Salfred	 *
2081184610Salfred	 * The CAM layer will then after a while start probing for devices on
2082184610Salfred	 * the bus. The number of SIMs is limited to one.
2083184610Salfred	 */
2084184610Salfred
2085184610Salfred	devq = cam_simq_alloc(1 /* maximum openings */ );
2086184610Salfred	if (devq == NULL) {
2087184610Salfred		return (ENOMEM);
2088184610Salfred	}
2089184610Salfred	sc->sc_sim = cam_sim_alloc
2090184610Salfred	    (&umass_cam_action, &umass_cam_poll,
2091184610Salfred	    DEVNAME_SIM,
2092184610Salfred	    sc /* priv */ ,
2093184610Salfred	    sc->sc_unit /* unit number */ ,
2094188415Sthompsa	    &sc->sc_mtx /* mutex */ ,
2095184610Salfred	    1 /* maximum device openings */ ,
2096184610Salfred	    0 /* maximum tagged device openings */ ,
2097184610Salfred	    devq);
2098184610Salfred
2099184610Salfred	if (sc->sc_sim == NULL) {
2100184610Salfred		cam_simq_free(devq);
2101184610Salfred		return (ENOMEM);
2102184610Salfred	}
2103184610Salfred
2104188415Sthompsa	mtx_lock(&sc->sc_mtx);
2105184610Salfred
2106232361Shselasky	if (xpt_bus_register(sc->sc_sim, sc->sc_dev,
2107232361Shselasky	    sc->sc_unit) != CAM_SUCCESS) {
2108188415Sthompsa		mtx_unlock(&sc->sc_mtx);
2109184610Salfred		return (ENOMEM);
2110184610Salfred	}
2111232361Shselasky	mtx_unlock(&sc->sc_mtx);
2112184610Salfred
2113184610Salfred	return (0);
2114184610Salfred}
2115184610Salfred
2116184610Salfredstatic void
2117184610Salfredumass_cam_attach(struct umass_softc *sc)
2118184610Salfred{
2119184610Salfred#ifndef USB_DEBUG
2120184610Salfred	if (bootverbose)
2121184610Salfred#endif
2122184610Salfred		printf("%s:%d:%d:%d: Attached to scbus%d\n",
2123184610Salfred		    sc->sc_name, cam_sim_path(sc->sc_sim),
2124184610Salfred		    sc->sc_unit, CAM_LUN_WILDCARD,
2125184610Salfred		    cam_sim_path(sc->sc_sim));
2126184610Salfred}
2127184610Salfred
2128184610Salfred/* umass_cam_detach
2129184610Salfred *	detach from the CAM layer
2130184610Salfred */
2131184610Salfred
2132184610Salfredstatic void
2133184610Salfredumass_cam_detach_sim(struct umass_softc *sc)
2134184610Salfred{
2135188415Sthompsa	if (sc->sc_sim != NULL) {
2136184610Salfred		if (xpt_bus_deregister(cam_sim_path(sc->sc_sim))) {
2137184610Salfred			/* accessing the softc is not possible after this */
2138241432Smav			sc->sc_sim->softc = NULL;
2139188415Sthompsa			cam_sim_free(sc->sc_sim, /* free_devq */ TRUE);
2140184610Salfred		} else {
2141199816Sthompsa			panic("%s: CAM layer is busy\n",
2142184610Salfred			    sc->sc_name);
2143184610Salfred		}
2144184610Salfred		sc->sc_sim = NULL;
2145184610Salfred	}
2146184610Salfred}
2147184610Salfred
2148184610Salfred/* umass_cam_action
2149184610Salfred * 	CAM requests for action come through here
2150184610Salfred */
2151184610Salfred
2152184610Salfredstatic void
2153184610Salfredumass_cam_action(struct cam_sim *sim, union ccb *ccb)
2154184610Salfred{
2155184610Salfred	struct umass_softc *sc = (struct umass_softc *)sim->softc;
2156184610Salfred
2157241432Smav	if (sc == NULL) {
2158198307Sthompsa		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
2159184610Salfred		xpt_done(ccb);
2160184610Salfred		return;
2161184610Salfred	}
2162184610Salfred
2163184610Salfred	/* Perform the requested action */
2164184610Salfred	switch (ccb->ccb_h.func_code) {
2165184610Salfred	case XPT_SCSI_IO:
2166184610Salfred		{
2167184610Salfred			uint8_t *cmd;
2168184610Salfred			uint8_t dir;
2169184610Salfred
2170184610Salfred			if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) {
2171184610Salfred				cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr);
2172184610Salfred			} else {
2173184610Salfred				cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes);
2174184610Salfred			}
2175184610Salfred
2176184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SCSI_IO: "
2177184610Salfred			    "cmd: 0x%02x, flags: 0x%02x, "
2178184610Salfred			    "%db cmd/%db data/%db sense\n",
2179184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2180184610Salfred			    ccb->ccb_h.target_lun, cmd[0],
2181184610Salfred			    ccb->ccb_h.flags & CAM_DIR_MASK, ccb->csio.cdb_len,
2182184610Salfred			    ccb->csio.dxfer_len, ccb->csio.sense_len);
2183184610Salfred
2184184610Salfred			if (sc->sc_transfer.ccb) {
2185184610Salfred				DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SCSI_IO: "
2186184610Salfred				    "I/O in progress, deferring\n",
2187184610Salfred				    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2188184610Salfred				    ccb->ccb_h.target_lun);
2189184610Salfred				ccb->ccb_h.status = CAM_SCSI_BUSY;
2190184610Salfred				xpt_done(ccb);
2191184610Salfred				goto done;
2192184610Salfred			}
2193184610Salfred			switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
2194184610Salfred			case CAM_DIR_IN:
2195184610Salfred				dir = DIR_IN;
2196184610Salfred				break;
2197184610Salfred			case CAM_DIR_OUT:
2198184610Salfred				dir = DIR_OUT;
2199184610Salfred				DIF(UDMASS_SCSI,
2200184610Salfred				    umass_dump_buffer(sc, ccb->csio.data_ptr,
2201184610Salfred				    ccb->csio.dxfer_len, 48));
2202184610Salfred				break;
2203184610Salfred			default:
2204184610Salfred				dir = DIR_NONE;
2205184610Salfred			}
2206184610Salfred
2207184610Salfred			ccb->ccb_h.status = CAM_REQ_INPROG | CAM_SIM_QUEUED;
2208184610Salfred
2209184610Salfred			/*
2210184610Salfred			 * sc->sc_transform will convert the command to the
2211184610Salfred			 * command format needed by the specific command set
2212184610Salfred			 * and return the converted command in
2213184610Salfred			 * "sc->sc_transfer.cmd_data"
2214184610Salfred			 */
2215184610Salfred			if (umass_std_transform(sc, ccb, cmd, ccb->csio.cdb_len)) {
2216184610Salfred
2217184610Salfred				if (sc->sc_transfer.cmd_data[0] == INQUIRY) {
2218212136Sthompsa					const char *pserial;
2219184610Salfred
2220212136Sthompsa					pserial = usb_get_serial(sc->sc_udev);
2221212136Sthompsa
2222184610Salfred					/*
2223196826Strasz					 * Umass devices don't generally report their serial numbers
2224196826Strasz					 * in the usual SCSI way.  Emulate it here.
2225196826Strasz					 */
2226196826Strasz					if ((sc->sc_transfer.cmd_data[1] & SI_EVPD) &&
2227212136Sthompsa					    (sc->sc_transfer.cmd_data[2] == SVPD_UNIT_SERIAL_NUMBER) &&
2228212136Sthompsa					    (pserial[0] != '\0')) {
2229196826Strasz						struct scsi_vpd_unit_serial_number *vpd_serial;
2230196826Strasz
2231196826Strasz						vpd_serial = (struct scsi_vpd_unit_serial_number *)ccb->csio.data_ptr;
2232212136Sthompsa						vpd_serial->length = strlen(pserial);
2233196826Strasz						if (vpd_serial->length > sizeof(vpd_serial->serial_num))
2234196826Strasz							vpd_serial->length = sizeof(vpd_serial->serial_num);
2235212136Sthompsa						memcpy(vpd_serial->serial_num, pserial, vpd_serial->length);
2236196826Strasz						ccb->csio.scsi_status = SCSI_STATUS_OK;
2237196826Strasz						ccb->ccb_h.status = CAM_REQ_CMP;
2238196826Strasz						xpt_done(ccb);
2239196826Strasz						goto done;
2240196826Strasz					}
2241196826Strasz
2242196826Strasz					/*
2243184610Salfred					 * Handle EVPD inquiry for broken devices first
2244184610Salfred					 * NO_INQUIRY also implies NO_INQUIRY_EVPD
2245184610Salfred					 */
2246184610Salfred					if ((sc->sc_quirks & (NO_INQUIRY_EVPD | NO_INQUIRY)) &&
2247184610Salfred					    (sc->sc_transfer.cmd_data[1] & SI_EVPD)) {
2248184610Salfred
2249225950Sken						scsi_set_sense_data(&ccb->csio.sense_data,
2250225950Sken							/*sense_format*/ SSD_TYPE_NONE,
2251225950Sken							/*current_error*/ 1,
2252225950Sken							/*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
2253225950Sken							/*asc*/ 0x24,
2254225950Sken							/*ascq*/ 0x00,
2255225950Sken							/*extra args*/ SSD_ELEM_NONE);
2256184610Salfred						ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
2257245328Smav						ccb->ccb_h.status =
2258245328Smav						    CAM_SCSI_STATUS_ERROR |
2259245328Smav						    CAM_AUTOSNS_VALID |
2260245328Smav						    CAM_DEV_QFRZN;
2261245328Smav						xpt_freeze_devq(ccb->ccb_h.path, 1);
2262184610Salfred						xpt_done(ccb);
2263184610Salfred						goto done;
2264184610Salfred					}
2265184610Salfred					/*
2266184610Salfred					 * Return fake inquiry data for
2267184610Salfred					 * broken devices
2268184610Salfred					 */
2269184610Salfred					if (sc->sc_quirks & NO_INQUIRY) {
2270184610Salfred						memcpy(ccb->csio.data_ptr, &fake_inq_data,
2271184610Salfred						    sizeof(fake_inq_data));
2272184610Salfred						ccb->csio.scsi_status = SCSI_STATUS_OK;
2273184610Salfred						ccb->ccb_h.status = CAM_REQ_CMP;
2274184610Salfred						xpt_done(ccb);
2275184610Salfred						goto done;
2276184610Salfred					}
2277184610Salfred					if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
2278184610Salfred						ccb->csio.dxfer_len = SHORT_INQUIRY_LENGTH;
2279184610Salfred					}
2280242628Smarcel				} else if (sc->sc_transfer.cmd_data[0] == PREVENT_ALLOW) {
2281242628Smarcel					if (sc->sc_quirks & NO_PREVENT_ALLOW) {
2282242628Smarcel						ccb->csio.scsi_status = SCSI_STATUS_OK;
2283242628Smarcel						ccb->ccb_h.status = CAM_REQ_CMP;
2284242628Smarcel						xpt_done(ccb);
2285242628Smarcel						goto done;
2286242628Smarcel					}
2287184610Salfred				} else if (sc->sc_transfer.cmd_data[0] == SYNCHRONIZE_CACHE) {
2288184610Salfred					if (sc->sc_quirks & NO_SYNCHRONIZE_CACHE) {
2289184610Salfred						ccb->csio.scsi_status = SCSI_STATUS_OK;
2290184610Salfred						ccb->ccb_h.status = CAM_REQ_CMP;
2291184610Salfred						xpt_done(ccb);
2292184610Salfred						goto done;
2293184610Salfred					}
2294184610Salfred				}
2295184610Salfred				umass_command_start(sc, dir, ccb->csio.data_ptr,
2296184610Salfred				    ccb->csio.dxfer_len,
2297184610Salfred				    ccb->ccb_h.timeout,
2298184610Salfred				    &umass_cam_cb, ccb);
2299184610Salfred			}
2300184610Salfred			break;
2301184610Salfred		}
2302184610Salfred	case XPT_PATH_INQ:
2303184610Salfred		{
2304184610Salfred			struct ccb_pathinq *cpi = &ccb->cpi;
2305184610Salfred
2306184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_PATH_INQ:.\n",
2307184610Salfred			    sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id,
2308184610Salfred			    ccb->ccb_h.target_lun);
2309184610Salfred
2310184610Salfred			/* host specific information */
2311184610Salfred			cpi->version_num = 1;
2312184610Salfred			cpi->hba_inquiry = 0;
2313184610Salfred			cpi->target_sprt = 0;
2314184610Salfred			cpi->hba_misc = PIM_NO_6_BYTE;
2315184610Salfred			cpi->hba_eng_cnt = 0;
2316184610Salfred			cpi->max_target = UMASS_SCSIID_MAX;	/* one target */
2317184610Salfred			cpi->initiator_id = UMASS_SCSIID_HOST;
2318184610Salfred			strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
2319184610Salfred			strlcpy(cpi->hba_vid, "USB SCSI", HBA_IDLEN);
2320184610Salfred			strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
2321184610Salfred			cpi->unit_number = cam_sim_unit(sim);
2322184610Salfred			cpi->bus_id = sc->sc_unit;
2323184610Salfred			cpi->protocol = PROTO_SCSI;
2324184610Salfred			cpi->protocol_version = SCSI_REV_2;
2325184610Salfred			cpi->transport = XPORT_USB;
2326184610Salfred			cpi->transport_version = 0;
2327232361Shselasky
2328184610Salfred			if (sc == NULL) {
2329184610Salfred				cpi->base_transfer_speed = 0;
2330184610Salfred				cpi->max_lun = 0;
2331184610Salfred			} else {
2332184610Salfred				if (sc->sc_quirks & FLOPPY_SPEED) {
2333184610Salfred					cpi->base_transfer_speed =
2334184610Salfred					    UMASS_FLOPPY_TRANSFER_SPEED;
2335184610Salfred				} else {
2336213439Shselasky					switch (usbd_get_speed(sc->sc_udev)) {
2337213439Shselasky					case USB_SPEED_SUPER:
2338213439Shselasky						cpi->base_transfer_speed =
2339213439Shselasky						    UMASS_SUPER_TRANSFER_SPEED;
2340213931Smav						cpi->maxio = MAXPHYS;
2341213439Shselasky						break;
2342213439Shselasky					case USB_SPEED_HIGH:
2343213439Shselasky						cpi->base_transfer_speed =
2344213439Shselasky						    UMASS_HIGH_TRANSFER_SPEED;
2345213439Shselasky						break;
2346213439Shselasky					default:
2347213439Shselasky						cpi->base_transfer_speed =
2348213439Shselasky						    UMASS_FULL_TRANSFER_SPEED;
2349213439Shselasky						break;
2350213439Shselasky					}
2351184610Salfred				}
2352184610Salfred				cpi->max_lun = sc->sc_maxlun;
2353184610Salfred			}
2354184610Salfred
2355184610Salfred			cpi->ccb_h.status = CAM_REQ_CMP;
2356184610Salfred			xpt_done(ccb);
2357184610Salfred			break;
2358184610Salfred		}
2359184610Salfred	case XPT_RESET_DEV:
2360184610Salfred		{
2361184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_RESET_DEV:.\n",
2362184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2363184610Salfred			    ccb->ccb_h.target_lun);
2364184610Salfred
2365184610Salfred			umass_reset(sc);
2366184610Salfred
2367184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2368184610Salfred			xpt_done(ccb);
2369184610Salfred			break;
2370184610Salfred		}
2371184610Salfred	case XPT_GET_TRAN_SETTINGS:
2372184610Salfred		{
2373184610Salfred			struct ccb_trans_settings *cts = &ccb->cts;
2374184610Salfred
2375184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_GET_TRAN_SETTINGS:.\n",
2376184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2377184610Salfred			    ccb->ccb_h.target_lun);
2378184610Salfred
2379184610Salfred			cts->protocol = PROTO_SCSI;
2380184610Salfred			cts->protocol_version = SCSI_REV_2;
2381184610Salfred			cts->transport = XPORT_USB;
2382184610Salfred			cts->transport_version = 0;
2383184610Salfred			cts->xport_specific.valid = 0;
2384232361Shselasky
2385184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2386184610Salfred			xpt_done(ccb);
2387184610Salfred			break;
2388184610Salfred		}
2389184610Salfred	case XPT_SET_TRAN_SETTINGS:
2390184610Salfred		{
2391184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_SET_TRAN_SETTINGS:.\n",
2392184610Salfred			    cam_sim_path(sc->sc_sim), ccb->ccb_h.target_id,
2393184610Salfred			    ccb->ccb_h.target_lun);
2394184610Salfred
2395184610Salfred			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
2396184610Salfred			xpt_done(ccb);
2397184610Salfred			break;
2398184610Salfred		}
2399184610Salfred	case XPT_CALC_GEOMETRY:
2400184610Salfred		{
2401184610Salfred			cam_calc_geometry(&ccb->ccg, /* extended */ 1);
2402184610Salfred			xpt_done(ccb);
2403184610Salfred			break;
2404184610Salfred		}
2405184610Salfred	case XPT_NOOP:
2406184610Salfred		{
2407184610Salfred			DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:XPT_NOOP:.\n",
2408184610Salfred			    sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id,
2409184610Salfred			    ccb->ccb_h.target_lun);
2410184610Salfred
2411184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2412184610Salfred			xpt_done(ccb);
2413184610Salfred			break;
2414184610Salfred		}
2415184610Salfred	default:
2416184610Salfred		DPRINTF(sc, UDMASS_SCSI, "%d:%d:%d:func_code 0x%04x: "
2417184610Salfred		    "Not implemented\n",
2418184610Salfred		    sc ? cam_sim_path(sc->sc_sim) : -1, ccb->ccb_h.target_id,
2419184610Salfred		    ccb->ccb_h.target_lun, ccb->ccb_h.func_code);
2420184610Salfred
2421184610Salfred		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
2422184610Salfred		xpt_done(ccb);
2423184610Salfred		break;
2424184610Salfred	}
2425184610Salfred
2426184610Salfreddone:
2427184610Salfred	return;
2428184610Salfred}
2429184610Salfred
2430184610Salfredstatic void
2431184610Salfredumass_cam_poll(struct cam_sim *sim)
2432184610Salfred{
2433184610Salfred	struct umass_softc *sc = (struct umass_softc *)sim->softc;
2434184610Salfred
2435241432Smav	if (sc == NULL)
2436184610Salfred		return;
2437184610Salfred
2438184610Salfred	DPRINTF(sc, UDMASS_SCSI, "CAM poll\n");
2439184610Salfred
2440194677Sthompsa	usbd_transfer_poll(sc->sc_xfer, UMASS_T_MAX);
2441184610Salfred}
2442184610Salfred
2443184610Salfred
2444184610Salfred/* umass_cam_cb
2445184610Salfred *	finalise a completed CAM command
2446184610Salfred */
2447184610Salfred
2448184610Salfredstatic void
2449184610Salfredumass_cam_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
2450184610Salfred    uint8_t status)
2451184610Salfred{
2452184610Salfred	ccb->csio.resid = residue;
2453184610Salfred
2454184610Salfred	switch (status) {
2455184610Salfred	case STATUS_CMD_OK:
2456184610Salfred		ccb->ccb_h.status = CAM_REQ_CMP;
2457184610Salfred		if ((sc->sc_quirks & READ_CAPACITY_OFFBY1) &&
2458184610Salfred		    (ccb->ccb_h.func_code == XPT_SCSI_IO) &&
2459184610Salfred		    (ccb->csio.cdb_io.cdb_bytes[0] == READ_CAPACITY)) {
2460184610Salfred			struct scsi_read_capacity_data *rcap;
2461184610Salfred			uint32_t maxsector;
2462184610Salfred
2463184610Salfred			rcap = (void *)(ccb->csio.data_ptr);
2464184610Salfred			maxsector = scsi_4btoul(rcap->addr) - 1;
2465184610Salfred			scsi_ulto4b(maxsector, rcap->addr);
2466184610Salfred		}
2467196826Strasz		/*
2468196826Strasz		 * We have to add SVPD_UNIT_SERIAL_NUMBER to the list
2469196826Strasz		 * of pages supported by the device - otherwise, CAM
2470196826Strasz		 * will never ask us for the serial number if the
2471196826Strasz		 * device cannot handle that by itself.
2472196826Strasz		 */
2473196826Strasz		if (ccb->ccb_h.func_code == XPT_SCSI_IO &&
2474196826Strasz		    sc->sc_transfer.cmd_data[0] == INQUIRY &&
2475196826Strasz		    (sc->sc_transfer.cmd_data[1] & SI_EVPD) &&
2476196826Strasz		    sc->sc_transfer.cmd_data[2] == SVPD_SUPPORTED_PAGE_LIST &&
2477212136Sthompsa		    (usb_get_serial(sc->sc_udev)[0] != '\0')) {
2478196826Strasz			struct ccb_scsiio *csio;
2479196826Strasz			struct scsi_vpd_supported_page_list *page_list;
2480196826Strasz
2481196826Strasz			csio = &ccb->csio;
2482196826Strasz			page_list = (struct scsi_vpd_supported_page_list *)csio->data_ptr;
2483196826Strasz			if (page_list->length + 1 < SVPD_SUPPORTED_PAGES_SIZE) {
2484196826Strasz				page_list->list[page_list->length] = SVPD_UNIT_SERIAL_NUMBER;
2485196826Strasz				page_list->length++;
2486196826Strasz			}
2487196826Strasz		}
2488184610Salfred		xpt_done(ccb);
2489184610Salfred		break;
2490184610Salfred
2491184610Salfred	case STATUS_CMD_UNKNOWN:
2492184610Salfred	case STATUS_CMD_FAILED:
2493184610Salfred
2494184610Salfred		/* fetch sense data */
2495184610Salfred
2496184610Salfred		/* the rest of the command was filled in at attach */
2497184610Salfred		sc->cam_scsi_sense.length = ccb->csio.sense_len;
2498184610Salfred
2499184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Fetching %d bytes of "
2500184610Salfred		    "sense data\n", ccb->csio.sense_len);
2501184610Salfred
2502184610Salfred		if (umass_std_transform(sc, ccb, &sc->cam_scsi_sense.opcode,
2503184610Salfred		    sizeof(sc->cam_scsi_sense))) {
2504184610Salfred
2505184610Salfred			if ((sc->sc_quirks & FORCE_SHORT_INQUIRY) &&
2506184610Salfred			    (sc->sc_transfer.cmd_data[0] == INQUIRY)) {
2507184610Salfred				ccb->csio.sense_len = SHORT_INQUIRY_LENGTH;
2508184610Salfred			}
2509184610Salfred			umass_command_start(sc, DIR_IN, &ccb->csio.sense_data.error_code,
2510184610Salfred			    ccb->csio.sense_len, ccb->ccb_h.timeout,
2511184610Salfred			    &umass_cam_sense_cb, ccb);
2512184610Salfred		}
2513184610Salfred		break;
2514184610Salfred
2515184610Salfred	default:
2516184610Salfred		/*
2517203146Sthompsa		 * The wire protocol failed and will hopefully have
2518203146Sthompsa		 * recovered. We return an error to CAM and let CAM
2519220535Smav		 * retry the command if necessary.
2520184610Salfred		 */
2521245328Smav		xpt_freeze_devq(ccb->ccb_h.path, 1);
2522245328Smav		ccb->ccb_h.status = CAM_REQ_CMP_ERR | CAM_DEV_QFRZN;
2523184610Salfred		xpt_done(ccb);
2524184610Salfred		break;
2525184610Salfred	}
2526184610Salfred}
2527184610Salfred
2528184610Salfred/*
2529184610Salfred * Finalise a completed autosense operation
2530184610Salfred */
2531184610Salfredstatic void
2532184610Salfredumass_cam_sense_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
2533184610Salfred    uint8_t status)
2534184610Salfred{
2535184610Salfred	uint8_t *cmd;
2536184610Salfred
2537184610Salfred	switch (status) {
2538184610Salfred	case STATUS_CMD_OK:
2539184610Salfred	case STATUS_CMD_UNKNOWN:
2540225950Sken	case STATUS_CMD_FAILED: {
2541225950Sken		int key, sense_len;
2542184610Salfred
2543225950Sken		ccb->csio.sense_resid = residue;
2544225950Sken		sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
2545225950Sken		key = scsi_get_sense_key(&ccb->csio.sense_data, sense_len,
2546225950Sken					 /*show_errors*/ 1);
2547225950Sken
2548184610Salfred		if (ccb->csio.ccb_h.flags & CAM_CDB_POINTER) {
2549184610Salfred			cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_ptr);
2550184610Salfred		} else {
2551184610Salfred			cmd = (uint8_t *)(ccb->csio.cdb_io.cdb_bytes);
2552184610Salfred		}
2553184610Salfred
2554184610Salfred		/*
2555184610Salfred		 * Getting sense data always succeeds (apart from wire
2556184610Salfred		 * failures):
2557184610Salfred		 */
2558184610Salfred		if ((sc->sc_quirks & RS_NO_CLEAR_UA) &&
2559184610Salfred		    (cmd[0] == INQUIRY) &&
2560184610Salfred		    (key == SSD_KEY_UNIT_ATTENTION)) {
2561184610Salfred			/*
2562184610Salfred			 * Ignore unit attention errors in the case where
2563184610Salfred			 * the Unit Attention state is not cleared on
2564184610Salfred			 * REQUEST SENSE. They will appear again at the next
2565184610Salfred			 * command.
2566184610Salfred			 */
2567184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2568184610Salfred		} else if (key == SSD_KEY_NO_SENSE) {
2569184610Salfred			/*
2570184610Salfred			 * No problem after all (in the case of CBI without
2571184610Salfred			 * CCI)
2572184610Salfred			 */
2573184610Salfred			ccb->ccb_h.status = CAM_REQ_CMP;
2574184610Salfred		} else if ((sc->sc_quirks & RS_NO_CLEAR_UA) &&
2575184610Salfred			    (cmd[0] == READ_CAPACITY) &&
2576184610Salfred		    (key == SSD_KEY_UNIT_ATTENTION)) {
2577184610Salfred			/*
2578184610Salfred			 * Some devices do not clear the unit attention error
2579184610Salfred			 * on request sense. We insert a test unit ready
2580184610Salfred			 * command to make sure we clear the unit attention
2581184610Salfred			 * condition, then allow the retry to proceed as
2582184610Salfred			 * usual.
2583184610Salfred			 */
2584184610Salfred
2585245328Smav			xpt_freeze_devq(ccb->ccb_h.path, 1);
2586184610Salfred			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
2587245328Smav			    | CAM_AUTOSNS_VALID | CAM_DEV_QFRZN;
2588184610Salfred			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
2589184610Salfred
2590184610Salfred#if 0
2591184610Salfred			DELAY(300000);
2592184610Salfred#endif
2593184610Salfred			DPRINTF(sc, UDMASS_SCSI, "Doing a sneaky"
2594184610Salfred			    "TEST_UNIT_READY\n");
2595184610Salfred
2596184610Salfred			/* the rest of the command was filled in at attach */
2597184610Salfred
2598245328Smav			if ((sc->sc_transform)(sc,
2599184610Salfred			    &sc->cam_scsi_test_unit_ready.opcode,
2600245328Smav			    sizeof(sc->cam_scsi_test_unit_ready)) == 1) {
2601184610Salfred				umass_command_start(sc, DIR_NONE, NULL, 0,
2602184610Salfred				    ccb->ccb_h.timeout,
2603184610Salfred				    &umass_cam_quirk_cb, ccb);
2604245328Smav				break;
2605184610Salfred			}
2606184610Salfred		} else {
2607245328Smav			xpt_freeze_devq(ccb->ccb_h.path, 1);
2608245647Skan			if (key >= 0) {
2609245647Skan				ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR
2610245647Skan				    | CAM_AUTOSNS_VALID | CAM_DEV_QFRZN;
2611245647Skan				ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
2612245647Skan			} else
2613245647Skan				ccb->ccb_h.status = CAM_AUTOSENSE_FAIL
2614245647Skan				    | CAM_DEV_QFRZN;
2615184610Salfred		}
2616184610Salfred		xpt_done(ccb);
2617184610Salfred		break;
2618225950Sken	}
2619184610Salfred	default:
2620184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Autosense failed, "
2621184610Salfred		    "status %d\n", status);
2622245328Smav		xpt_freeze_devq(ccb->ccb_h.path, 1);
2623245328Smav		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL | CAM_DEV_QFRZN;
2624184610Salfred		xpt_done(ccb);
2625184610Salfred	}
2626184610Salfred}
2627184610Salfred
2628184610Salfred/*
2629184610Salfred * This completion code just handles the fact that we sent a test-unit-ready
2630245328Smav * after having previously failed a READ CAPACITY with CHECK_COND.  The CCB
2631245328Smav * status for CAM is already set earlier.
2632184610Salfred */
2633184610Salfredstatic void
2634184610Salfredumass_cam_quirk_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue,
2635184610Salfred    uint8_t status)
2636184610Salfred{
2637184610Salfred	DPRINTF(sc, UDMASS_SCSI, "Test unit ready "
2638184610Salfred	    "returned status %d\n", status);
2639184610Salfred
2640184610Salfred	xpt_done(ccb);
2641184610Salfred}
2642184610Salfred
2643184610Salfred/*
2644184610Salfred * SCSI specific functions
2645184610Salfred */
2646184610Salfred
2647184610Salfredstatic uint8_t
2648184610Salfredumass_scsi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
2649184610Salfred    uint8_t cmd_len)
2650184610Salfred{
2651184610Salfred	if ((cmd_len == 0) ||
2652184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2653184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
2654184610Salfred		    "length: %d bytes\n", cmd_len);
2655184610Salfred		return (0);		/* failure */
2656184610Salfred	}
2657184610Salfred	sc->sc_transfer.cmd_len = cmd_len;
2658184610Salfred
2659184610Salfred	switch (cmd_ptr[0]) {
2660184610Salfred	case TEST_UNIT_READY:
2661184610Salfred		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
2662184610Salfred			DPRINTF(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY "
2663184610Salfred			    "to START_UNIT\n");
2664227461Shselasky			memset(sc->sc_transfer.cmd_data, 0, cmd_len);
2665184610Salfred			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
2666184610Salfred			sc->sc_transfer.cmd_data[4] = SSS_START;
2667184610Salfred			return (1);
2668184610Salfred		}
2669184610Salfred		break;
2670184610Salfred
2671184610Salfred	case INQUIRY:
2672184610Salfred		/*
2673184610Salfred		 * some drives wedge when asked for full inquiry
2674184610Salfred		 * information.
2675184610Salfred		 */
2676184610Salfred		if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
2677227461Shselasky			memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2678184610Salfred			sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
2679184610Salfred			return (1);
2680184610Salfred		}
2681184610Salfred		break;
2682184610Salfred	}
2683184610Salfred
2684227461Shselasky	memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2685184610Salfred	return (1);
2686184610Salfred}
2687184610Salfred
2688184610Salfredstatic uint8_t
2689184610Salfredumass_rbc_transform(struct umass_softc *sc, uint8_t *cmd_ptr, uint8_t cmd_len)
2690184610Salfred{
2691184610Salfred	if ((cmd_len == 0) ||
2692184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2693184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
2694184610Salfred		    "length: %d bytes\n", cmd_len);
2695184610Salfred		return (0);		/* failure */
2696184610Salfred	}
2697184610Salfred	switch (cmd_ptr[0]) {
2698184610Salfred		/* these commands are defined in RBC: */
2699184610Salfred	case READ_10:
2700184610Salfred	case READ_CAPACITY:
2701184610Salfred	case START_STOP_UNIT:
2702184610Salfred	case SYNCHRONIZE_CACHE:
2703184610Salfred	case WRITE_10:
2704184610Salfred	case 0x2f:			/* VERIFY_10 is absent from
2705184610Salfred					 * scsi_all.h??? */
2706184610Salfred	case INQUIRY:
2707184610Salfred	case MODE_SELECT_10:
2708184610Salfred	case MODE_SENSE_10:
2709184610Salfred	case TEST_UNIT_READY:
2710184610Salfred	case WRITE_BUFFER:
2711184610Salfred		/*
2712184610Salfred		 * The following commands are not listed in my copy of the
2713184610Salfred		 * RBC specs. CAM however seems to want those, and at least
2714184610Salfred		 * the Sony DSC device appears to support those as well
2715184610Salfred		 */
2716184610Salfred	case REQUEST_SENSE:
2717184610Salfred	case PREVENT_ALLOW:
2718184610Salfred
2719227461Shselasky		memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2720184610Salfred
2721184610Salfred		if ((sc->sc_quirks & RBC_PAD_TO_12) && (cmd_len < 12)) {
2722227461Shselasky			memset(sc->sc_transfer.cmd_data + cmd_len,
2723227461Shselasky			    0, 12 - cmd_len);
2724184610Salfred			cmd_len = 12;
2725184610Salfred		}
2726184610Salfred		sc->sc_transfer.cmd_len = cmd_len;
2727184610Salfred		return (1);		/* sucess */
2728184610Salfred
2729184610Salfred		/* All other commands are not legal in RBC */
2730184610Salfred	default:
2731184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Unsupported RBC "
2732184610Salfred		    "command 0x%02x\n", cmd_ptr[0]);
2733184610Salfred		return (0);		/* failure */
2734184610Salfred	}
2735184610Salfred}
2736184610Salfred
2737184610Salfredstatic uint8_t
2738184610Salfredumass_ufi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
2739184610Salfred    uint8_t cmd_len)
2740184610Salfred{
2741184610Salfred	if ((cmd_len == 0) ||
2742184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2743184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
2744184610Salfred		    "length: %d bytes\n", cmd_len);
2745184610Salfred		return (0);		/* failure */
2746184610Salfred	}
2747184610Salfred	/* An UFI command is always 12 bytes in length */
2748184610Salfred	sc->sc_transfer.cmd_len = UFI_COMMAND_LENGTH;
2749184610Salfred
2750184610Salfred	/* Zero the command data */
2751227461Shselasky	memset(sc->sc_transfer.cmd_data, 0, UFI_COMMAND_LENGTH);
2752184610Salfred
2753184610Salfred	switch (cmd_ptr[0]) {
2754184610Salfred		/*
2755184610Salfred		 * Commands of which the format has been verified. They
2756184610Salfred		 * should work. Copy the command into the (zeroed out)
2757184610Salfred		 * destination buffer.
2758184610Salfred		 */
2759184610Salfred	case TEST_UNIT_READY:
2760184610Salfred		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
2761184610Salfred			/*
2762184610Salfred			 * Some devices do not support this command. Start
2763184610Salfred			 * Stop Unit should give the same results
2764184610Salfred			 */
2765184610Salfred			DPRINTF(sc, UDMASS_UFI, "Converted TEST_UNIT_READY "
2766184610Salfred			    "to START_UNIT\n");
2767184610Salfred
2768184610Salfred			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
2769184610Salfred			sc->sc_transfer.cmd_data[4] = SSS_START;
2770184610Salfred			return (1);
2771184610Salfred		}
2772184610Salfred		break;
2773184610Salfred
2774184610Salfred	case REZERO_UNIT:
2775184610Salfred	case REQUEST_SENSE:
2776184610Salfred	case FORMAT_UNIT:
2777184610Salfred	case INQUIRY:
2778184610Salfred	case START_STOP_UNIT:
2779184610Salfred	case SEND_DIAGNOSTIC:
2780184610Salfred	case PREVENT_ALLOW:
2781184610Salfred	case READ_CAPACITY:
2782184610Salfred	case READ_10:
2783184610Salfred	case WRITE_10:
2784184610Salfred	case POSITION_TO_ELEMENT:	/* SEEK_10 */
2785184610Salfred	case WRITE_AND_VERIFY:
2786184610Salfred	case VERIFY:
2787184610Salfred	case MODE_SELECT_10:
2788184610Salfred	case MODE_SENSE_10:
2789184610Salfred	case READ_12:
2790184610Salfred	case WRITE_12:
2791184610Salfred	case READ_FORMAT_CAPACITIES:
2792184610Salfred		break;
2793184610Salfred
2794184610Salfred		/*
2795184610Salfred		 * SYNCHRONIZE_CACHE isn't supported by UFI, nor should it be
2796184610Salfred		 * required for UFI devices, so it is appropriate to fake
2797184610Salfred		 * success.
2798184610Salfred		 */
2799184610Salfred	case SYNCHRONIZE_CACHE:
2800184610Salfred		return (2);
2801184610Salfred
2802184610Salfred	default:
2803184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Unsupported UFI "
2804184610Salfred		    "command 0x%02x\n", cmd_ptr[0]);
2805184610Salfred		return (0);		/* failure */
2806184610Salfred	}
2807184610Salfred
2808227461Shselasky	memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2809184610Salfred	return (1);			/* success */
2810184610Salfred}
2811184610Salfred
2812184610Salfred/*
2813184610Salfred * 8070i (ATAPI) specific functions
2814184610Salfred */
2815184610Salfredstatic uint8_t
2816184610Salfredumass_atapi_transform(struct umass_softc *sc, uint8_t *cmd_ptr,
2817184610Salfred    uint8_t cmd_len)
2818184610Salfred{
2819184610Salfred	if ((cmd_len == 0) ||
2820184610Salfred	    (cmd_len > sizeof(sc->sc_transfer.cmd_data))) {
2821184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Invalid command "
2822184610Salfred		    "length: %d bytes\n", cmd_len);
2823184610Salfred		return (0);		/* failure */
2824184610Salfred	}
2825184610Salfred	/* An ATAPI command is always 12 bytes in length. */
2826184610Salfred	sc->sc_transfer.cmd_len = ATAPI_COMMAND_LENGTH;
2827184610Salfred
2828184610Salfred	/* Zero the command data */
2829227461Shselasky	memset(sc->sc_transfer.cmd_data, 0, ATAPI_COMMAND_LENGTH);
2830184610Salfred
2831184610Salfred	switch (cmd_ptr[0]) {
2832184610Salfred		/*
2833184610Salfred		 * Commands of which the format has been verified. They
2834184610Salfred		 * should work. Copy the command into the destination
2835184610Salfred		 * buffer.
2836184610Salfred		 */
2837184610Salfred	case INQUIRY:
2838184610Salfred		/*
2839184610Salfred		 * some drives wedge when asked for full inquiry
2840184610Salfred		 * information.
2841184610Salfred		 */
2842184610Salfred		if (sc->sc_quirks & FORCE_SHORT_INQUIRY) {
2843227461Shselasky			memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2844184610Salfred
2845184610Salfred			sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH;
2846184610Salfred			return (1);
2847184610Salfred		}
2848184610Salfred		break;
2849184610Salfred
2850184610Salfred	case TEST_UNIT_READY:
2851184610Salfred		if (sc->sc_quirks & NO_TEST_UNIT_READY) {
2852184610Salfred			DPRINTF(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY "
2853184610Salfred			    "to START_UNIT\n");
2854184610Salfred			sc->sc_transfer.cmd_data[0] = START_STOP_UNIT;
2855184610Salfred			sc->sc_transfer.cmd_data[4] = SSS_START;
2856184610Salfred			return (1);
2857184610Salfred		}
2858184610Salfred		break;
2859184610Salfred
2860184610Salfred	case REZERO_UNIT:
2861184610Salfred	case REQUEST_SENSE:
2862184610Salfred	case START_STOP_UNIT:
2863184610Salfred	case SEND_DIAGNOSTIC:
2864184610Salfred	case PREVENT_ALLOW:
2865184610Salfred	case READ_CAPACITY:
2866184610Salfred	case READ_10:
2867184610Salfred	case WRITE_10:
2868184610Salfred	case POSITION_TO_ELEMENT:	/* SEEK_10 */
2869184610Salfred	case SYNCHRONIZE_CACHE:
2870184610Salfred	case MODE_SELECT_10:
2871184610Salfred	case MODE_SENSE_10:
2872184610Salfred	case READ_BUFFER:
2873184610Salfred	case 0x42:			/* READ_SUBCHANNEL */
2874184610Salfred	case 0x43:			/* READ_TOC */
2875184610Salfred	case 0x44:			/* READ_HEADER */
2876184610Salfred	case 0x47:			/* PLAY_MSF (Play Minute/Second/Frame) */
2877184610Salfred	case 0x48:			/* PLAY_TRACK */
2878184610Salfred	case 0x49:			/* PLAY_TRACK_REL */
2879184610Salfred	case 0x4b:			/* PAUSE */
2880184610Salfred	case 0x51:			/* READ_DISK_INFO */
2881184610Salfred	case 0x52:			/* READ_TRACK_INFO */
2882184610Salfred	case 0x54:			/* SEND_OPC */
2883184610Salfred	case 0x59:			/* READ_MASTER_CUE */
2884184610Salfred	case 0x5b:			/* CLOSE_TR_SESSION */
2885184610Salfred	case 0x5c:			/* READ_BUFFER_CAP */
2886184610Salfred	case 0x5d:			/* SEND_CUE_SHEET */
2887184610Salfred	case 0xa1:			/* BLANK */
2888184610Salfred	case 0xa5:			/* PLAY_12 */
2889184610Salfred	case 0xa6:			/* EXCHANGE_MEDIUM */
2890184610Salfred	case 0xad:			/* READ_DVD_STRUCTURE */
2891184610Salfred	case 0xbb:			/* SET_CD_SPEED */
2892184610Salfred	case 0xe5:			/* READ_TRACK_INFO_PHILIPS */
2893201758Smbr		break;
2894184610Salfred
2895184610Salfred	case READ_12:
2896184610Salfred	case WRITE_12:
2897184610Salfred	default:
2898184610Salfred		DPRINTF(sc, UDMASS_SCSI, "Unsupported ATAPI "
2899184610Salfred		    "command 0x%02x - trying anyway\n",
2900184610Salfred		    cmd_ptr[0]);
2901201758Smbr		break;
2902184610Salfred	}
2903184610Salfred
2904227461Shselasky	memcpy(sc->sc_transfer.cmd_data, cmd_ptr, cmd_len);
2905184610Salfred	return (1);			/* success */
2906184610Salfred}
2907184610Salfred
2908184610Salfredstatic uint8_t
2909184610Salfredumass_no_transform(struct umass_softc *sc, uint8_t *cmd,
2910184610Salfred    uint8_t cmdlen)
2911184610Salfred{
2912184610Salfred	return (0);			/* failure */
2913184610Salfred}
2914184610Salfred
2915184610Salfredstatic uint8_t
2916184610Salfredumass_std_transform(struct umass_softc *sc, union ccb *ccb,
2917184610Salfred    uint8_t *cmd, uint8_t cmdlen)
2918184610Salfred{
2919184610Salfred	uint8_t retval;
2920184610Salfred
2921184610Salfred	retval = (sc->sc_transform) (sc, cmd, cmdlen);
2922184610Salfred
2923184610Salfred	if (retval == 2) {
2924184610Salfred		ccb->ccb_h.status = CAM_REQ_CMP;
2925184610Salfred		xpt_done(ccb);
2926184610Salfred		return (0);
2927184610Salfred	} else if (retval == 0) {
2928245328Smav		xpt_freeze_devq(ccb->ccb_h.path, 1);
2929245328Smav		ccb->ccb_h.status = CAM_REQ_INVALID | CAM_DEV_QFRZN;
2930184610Salfred		xpt_done(ccb);
2931184610Salfred		return (0);
2932184610Salfred	}
2933184610Salfred	/* Command should be executed */
2934184610Salfred	return (1);
2935184610Salfred}
2936184610Salfred
2937207077Sthompsa#ifdef USB_DEBUG
2938184610Salfredstatic void
2939184610Salfredumass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw)
2940184610Salfred{
2941184610Salfred	uint8_t *c = cbw->CBWCDB;
2942184610Salfred
2943184610Salfred	uint32_t dlen = UGETDW(cbw->dCBWDataTransferLength);
2944184610Salfred	uint32_t tag = UGETDW(cbw->dCBWTag);
2945184610Salfred
2946184610Salfred	uint8_t clen = cbw->bCDBLength;
2947184610Salfred	uint8_t flags = cbw->bCBWFlags;
2948184610Salfred	uint8_t lun = cbw->bCBWLUN;
2949184610Salfred
2950184610Salfred	DPRINTF(sc, UDMASS_BBB, "CBW %d: cmd = %db "
2951184610Salfred	    "(0x%02x%02x%02x%02x%02x%02x%s), "
2952184610Salfred	    "data = %db, lun = %d, dir = %s\n",
2953184610Salfred	    tag, clen,
2954184610Salfred	    c[0], c[1], c[2], c[3], c[4], c[5], (clen > 6 ? "..." : ""),
2955184610Salfred	    dlen, lun, (flags == CBWFLAGS_IN ? "in" :
2956184610Salfred	    (flags == CBWFLAGS_OUT ? "out" : "<invalid>")));
2957184610Salfred}
2958184610Salfred
2959184610Salfredstatic void
2960184610Salfredumass_bbb_dump_csw(struct umass_softc *sc, umass_bbb_csw_t *csw)
2961184610Salfred{
2962184610Salfred	uint32_t sig = UGETDW(csw->dCSWSignature);
2963184610Salfred	uint32_t tag = UGETDW(csw->dCSWTag);
2964184610Salfred	uint32_t res = UGETDW(csw->dCSWDataResidue);
2965184610Salfred	uint8_t status = csw->bCSWStatus;
2966184610Salfred
2967184610Salfred	DPRINTF(sc, UDMASS_BBB, "CSW %d: sig = 0x%08x (%s), tag = 0x%08x, "
2968184610Salfred	    "res = %d, status = 0x%02x (%s)\n",
2969184610Salfred	    tag, sig, (sig == CSWSIGNATURE ? "valid" : "invalid"),
2970184610Salfred	    tag, res,
2971184610Salfred	    status, (status == CSWSTATUS_GOOD ? "good" :
2972184610Salfred	    (status == CSWSTATUS_FAILED ? "failed" :
2973184610Salfred	    (status == CSWSTATUS_PHASE ? "phase" : "<invalid>"))));
2974184610Salfred}
2975184610Salfred
2976184610Salfredstatic void
2977184610Salfredumass_cbi_dump_cmd(struct umass_softc *sc, void *cmd, uint8_t cmdlen)
2978184610Salfred{
2979184610Salfred	uint8_t *c = cmd;
2980184610Salfred	uint8_t dir = sc->sc_transfer.dir;
2981184610Salfred
2982184610Salfred	DPRINTF(sc, UDMASS_BBB, "cmd = %db "
2983184610Salfred	    "(0x%02x%02x%02x%02x%02x%02x%s), "
2984184610Salfred	    "data = %db, dir = %s\n",
2985184610Salfred	    cmdlen,
2986184610Salfred	    c[0], c[1], c[2], c[3], c[4], c[5], (cmdlen > 6 ? "..." : ""),
2987184610Salfred	    sc->sc_transfer.data_len,
2988184610Salfred	    (dir == DIR_IN ? "in" :
2989184610Salfred	    (dir == DIR_OUT ? "out" :
2990184610Salfred	    (dir == DIR_NONE ? "no data phase" : "<invalid>"))));
2991184610Salfred}
2992184610Salfred
2993184610Salfredstatic void
2994184610Salfredumass_dump_buffer(struct umass_softc *sc, uint8_t *buffer, uint32_t buflen,
2995184610Salfred    uint32_t printlen)
2996184610Salfred{
2997184610Salfred	uint32_t i, j;
2998184610Salfred	char s1[40];
2999184610Salfred	char s2[40];
3000184610Salfred	char s3[5];
3001184610Salfred
3002184610Salfred	s1[0] = '\0';
3003184610Salfred	s3[0] = '\0';
3004184610Salfred
3005184610Salfred	sprintf(s2, " buffer=%p, buflen=%d", buffer, buflen);
3006184610Salfred	for (i = 0; (i < buflen) && (i < printlen); i++) {
3007184610Salfred		j = i % 16;
3008184610Salfred		if (j == 0 && i != 0) {
3009184610Salfred			DPRINTF(sc, UDMASS_GEN, "0x %s%s\n",
3010184610Salfred			    s1, s2);
3011184610Salfred			s2[0] = '\0';
3012184610Salfred		}
3013184610Salfred		sprintf(&s1[j * 2], "%02x", buffer[i] & 0xff);
3014184610Salfred	}
3015184610Salfred	if (buflen > printlen)
3016184610Salfred		sprintf(s3, " ...");
3017184610Salfred	DPRINTF(sc, UDMASS_GEN, "0x %s%s%s\n",
3018184610Salfred	    s1, s2, s3);
3019184610Salfred}
3020184610Salfred
3021184610Salfred#endif
3022