/*	$OpenBSD: umassvar.h,v 1.12 2007/06/13 06:25:03 mbalmer Exp $ */
/*	$NetBSD: umassvar.h,v 1.20 2003/09/08 19:31:01 mycroft Exp $	*/
/*-
 * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>,
 *		      Nick Hibma <n_hibma@freebsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *     $FreeBSD: src/sys/dev/usb/umass.c,v 1.13 2000/03/26 01:39:12 n_hibma Exp $
 */

#ifdef UMASS_DEBUG
#define DIF(m, x)	if (umassdebug & (m)) do { x ; } while (0)
#define DPRINTF(m, x)	do { if (umassdebug & (m)) printf x; } while (0)
#define UDMASS_UPPER	0x00008000	/* upper layer */
#define UDMASS_GEN	0x00010000	/* general */
#define UDMASS_SCSI	0x00020000	/* scsi */
#define UDMASS_UFI	0x00040000	/* ufi command set */
#define UDMASS_8070	0x00080000	/* 8070i command set */
#define UDMASS_USB	0x00100000	/* USB general */
#define UDMASS_BBB	0x00200000	/* Bulk-Only transfers */
#define UDMASS_CBI	0x00400000	/* CBI transfers */
#define UDMASS_ALL	0xffff0000	/* all of the above */

#define UDMASS_XFER	0x40000000	/* all transfers */
#define UDMASS_CMD	0x80000000

extern int umassdebug;
#else
#define DIF(m, x)	/* nop */
#define DPRINTF(m, x)	/* nop */
#endif

/* Generic definitions */

#define UFI_COMMAND_LENGTH 12

/* Direction for umass_*_transfer */
#define DIR_NONE	0
#define DIR_IN		1
#define DIR_OUT		2

/* Endpoints for umass */
#define	UMASS_BULKIN	0
#define	UMASS_BULKOUT	1
#define	UMASS_INTRIN	2
#define	UMASS_NEP	3

/* Bulk-Only features */

#define UR_BBB_RESET	0xff		/* Bulk-Only reset */
#define	UR_BBB_GET_MAX_LUN	0xfe

/* Command Block Wrapper */
typedef struct {
	uDWord		dCBWSignature;
#define CBWSIGNATURE	0x43425355
	uDWord		dCBWTag;
	uDWord		dCBWDataTransferLength;
	uByte		bCBWFlags;
#define CBWFLAGS_OUT	0x00
#define CBWFLAGS_IN	0x80
	uByte		bCBWLUN;
	uByte		bCDBLength;
#define CBWCDBLENGTH	16
	uByte		CBWCDB[CBWCDBLENGTH];
} umass_bbb_cbw_t;
#define UMASS_BBB_CBW_SIZE	31

/* Command Status Wrapper */
typedef struct {
	uDWord		dCSWSignature;
#define CSWSIGNATURE		0x53425355
#define CSWSIGNATURE_OLYMPUS_C1	0x55425355
	uDWord		dCSWTag;
	uDWord		dCSWDataResidue;
	uByte		bCSWStatus;
#define CSWSTATUS_GOOD	0x0
#define CSWSTATUS_FAILED 0x1
#define CSWSTATUS_PHASE	0x2
} umass_bbb_csw_t;
#define UMASS_BBB_CSW_SIZE	13

/* CBI features */

#define UR_CBI_ADSC	0x00

typedef unsigned char umass_cbi_cbl_t[16];	/* Command block */

typedef union {
	struct {
		uByte	type;
#define IDB_TYPE_CCI		0x00
		uByte	value;
#define IDB_VALUE_PASS		0x00
#define IDB_VALUE_FAIL		0x01
#define IDB_VALUE_PHASE		0x02
#define IDB_VALUE_PERSISTENT	0x03
#define IDB_VALUE_STATUS_MASK	0x03
	} common;

	struct {
		uByte	asc;
		uByte	ascq;
	} ufi;
} umass_cbi_sbl_t;

struct umass_softc;		/* see below */

typedef void (*umass_callback)(struct umass_softc *, void *, int, int);
#define STATUS_CMD_OK		0	/* everything ok */
#define STATUS_CMD_UNKNOWN	1	/* will have to fetch sense */
#define STATUS_CMD_FAILED	2	/* transfer was ok, command failed */
#define STATUS_WIRE_FAILED	3	/* couldn't even get command across */

typedef void (*umass_wire_xfer)(struct umass_softc *, int, void *, int, void *,
				int, int, u_int, umass_callback, void *);
typedef void (*umass_wire_reset)(struct umass_softc *, int);
typedef void (*umass_wire_state)(usbd_xfer_handle, usbd_private_handle,
				 usbd_status);

struct umass_wire_methods {
	umass_wire_xfer		wire_xfer;
	umass_wire_reset	wire_reset;
	umass_wire_state	wire_state;
};

struct umassbus_softc {
	struct device		*sc_child;	/* child device, for detach */
};

/* the per device structure */
struct umass_softc {
	struct device		sc_dev;		/* base device */
	usbd_device_handle	sc_udev;	/* device */
	usbd_interface_handle	sc_iface;	/* interface */
	int			sc_ifaceno;	/* interface number */

	u_int8_t		sc_epaddr[UMASS_NEP];
	usbd_pipe_handle	sc_pipe[UMASS_NEP];
	usb_device_request_t	sc_req;

	const struct umass_wire_methods *sc_methods;

	u_int8_t		sc_wire;	/* wire protocol */
#define	UMASS_WPROTO_UNSPEC	0
#define	UMASS_WPROTO_BBB	1
#define	UMASS_WPROTO_CBI	2
#define	UMASS_WPROTO_CBI_I	3

	u_int8_t		sc_cmd;		/* command protocol */
#define	UMASS_CPROTO_UNSPEC	0
#define	UMASS_CPROTO_SCSI	1
#define	UMASS_CPROTO_ATAPI	2
#define	UMASS_CPROTO_UFI	3
#define	UMASS_CPROTO_RBC	4
#define UMASS_CPROTO_ISD_ATA	5

	u_int32_t		sc_quirks;
#define UMASS_QUIRK_WRONG_CSWSIG	0x00000001
#define UMASS_QUIRK_WRONG_CSWTAG	0x00000002

	u_int32_t		sc_busquirks;

	/* Bulk specific variables for transfers in progress */
	umass_bbb_cbw_t		cbw;	/* command block wrapper */
	umass_bbb_csw_t		csw;	/* command status wrapper*/
	/* CBI specific variables for transfers in progress */
	umass_cbi_cbl_t		cbl;	/* command block */
	umass_cbi_sbl_t		sbl;	/* status block */

	/* xfer handles
	 * Most of our operations are initiated from interrupt context, so
	 * we need to avoid using the one that is in use. We want to avoid
	 * allocating them in the interrupt context as well.
	 */
	/* indices into array below */
#define XFER_BBB_CBW		0	/* Bulk-Only */
#define XFER_BBB_DATA		1
#define XFER_BBB_DCLEAR		2
#define XFER_BBB_CSW1		3
#define XFER_BBB_CSW2		4
#define XFER_BBB_SCLEAR		5
#define XFER_BBB_RESET1		6
#define XFER_BBB_RESET2		7
#define XFER_BBB_RESET3		8

#define XFER_CBI_CB		0	/* CBI */
#define XFER_CBI_DATA		1
#define XFER_CBI_STATUS		2
#define XFER_CBI_DCLEAR		3
#define XFER_CBI_SCLEAR		4
#define XFER_CBI_RESET1		5
#define XFER_CBI_RESET2		6
#define XFER_CBI_RESET3		7

#define XFER_NR			9	/* maximum number */

	usbd_xfer_handle	transfer_xfer[XFER_NR]; /* for ctrl xfers */

	void			*data_buffer;

	int			transfer_dir;		/* data direction */
	void			*transfer_data;		/* data buffer */
	int			transfer_datalen;	/* (maximum) length */
	int			transfer_actlen;	/* actual length */
	umass_callback		transfer_cb;		/* callback */
	void			*transfer_priv;		/* for callback */
	int			transfer_status;

	int			transfer_state;
#define TSTATE_IDLE			0
#define TSTATE_BBB_COMMAND		1	/* CBW transfer */
#define TSTATE_BBB_DATA			2	/* Data transfer */
#define TSTATE_BBB_DCLEAR		3	/* clear endpt stall */
#define TSTATE_BBB_STATUS1		4	/* clear endpt stall */
#define TSTATE_BBB_SCLEAR		5	/* clear endpt stall */
#define TSTATE_BBB_STATUS2		6	/* CSW transfer */
#define TSTATE_BBB_RESET1		7	/* reset command */
#define TSTATE_BBB_RESET2		8	/* in clear stall */
#define TSTATE_BBB_RESET3		9	/* out clear stall */
#define TSTATE_CBI_COMMAND		10	/* command transfer */
#define TSTATE_CBI_DATA			11	/* data transfer */
#define TSTATE_CBI_STATUS		12	/* status transfer */
#define TSTATE_CBI_DCLEAR		13	/* clear ep stall */
#define TSTATE_CBI_SCLEAR		14	/* clear ep stall */
#define TSTATE_CBI_RESET1		15	/* reset command */
#define TSTATE_CBI_RESET2		16	/* in clear stall */
#define TSTATE_CBI_RESET3		17	/* out clear stall */
#define TSTATE_STATES			18	/* # of states above */


	int			timeout;		/* in msecs */

	u_int8_t		maxlun;			/* max lun supported */

#ifdef UMASS_DEBUG
	struct timeval tv;
#endif

	int			sc_xfer_flags;
	char			sc_dying;
	int			sc_refcnt;
	int			sc_sense;

	struct umassbus_softc	*bus;		 /* bus dependent data */

	/* For polled transfers */
	int			polling_depth;
	usbd_status		polled_xfer_status;
	usbd_xfer_handle	next_polled_xfer;
};

#define UMASS_MAX_TRANSFER_SIZE	MAXBSIZE
