/*      $NetBSD: umassvar.h,v 1.40 2021/12/31 14:24:16 riastradh Exp $  */

/*-
* Copyright (c) 1999 MAEKAWA Masahide <[email protected]>,
*                    Nick Hibma <[email protected]>
* 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)
extern int umassdebug;
#else
#define umassdebug      0
#define DIF(m, x)       /* nop */
#endif

#define DPRINTFM(M,FMT,A,B,C,D) USBHIST_LOGM(umassdebug,M,FMT,A,B,C,D)
#define UMASSHIST_FUNC()        USBHIST_FUNC()
#define UMASSHIST_CALLED(name)  USBHIST_CALLED(umassdebug)

#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

/* 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 */
#define STATUS_TIMEOUT          4       /* transfer aborted */

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

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

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

/* the per device structure */
struct umass_softc {
       device_t                sc_dev;         /* base device */
       struct usbd_device *    sc_udev;        /* device */
       struct usbd_interface * sc_iface;       /* interface */
       int                     sc_ifaceno;     /* interface number */

       uint8_t                 sc_epaddr[UMASS_NEP];
       struct usbd_pipe *      sc_pipe[UMASS_NEP];
       usb_device_request_t    sc_req;

       const struct umass_wire_methods *sc_methods;

       kmutex_t                sc_lock;

       uint8_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

       uint8_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

       uint32_t                sc_quirks;
#define UMASS_QUIRK_WRONG_CSWSIG        0x00000001
#define UMASS_QUIRK_WRONG_CSWTAG        0x00000002
#define UMASS_QUIRK_RBC_PAD_TO_12       0x00000004
#define UMASS_QUIRK_NOGETMAXLUN         0x00000008

#define UMASS_QUIRK_USE_DEFAULTMATCH    -1

       uint32_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 have to avoid
        * allocating them in the interrupt context as well.
        */
       /* indices into array below */
#define XFER_BBB_CBW            0       /* Bulk-Only */
#define XFER_BBB_DATAIN         1
#define XFER_BBB_DATAOUT        2
#define XFER_BBB_DCLEAR         3
#define XFER_BBB_CSW1           4
#define XFER_BBB_CSW2           5
#define XFER_BBB_SCLEAR         6
#define XFER_BBB_RESET1         7
#define XFER_BBB_RESET2         8
#define XFER_BBB_RESET3         9

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

#define XFER_NR                 10      /* maximum number */

       struct usbd_xfer        *transfer_xfer[XFER_NR]; /* for ctrl xfers */

       void                    *datain_buffer;
       void                    *dataout_buffer;
       void                    *cmd_buffer;
       void                    *s1_buffer;
       void                    *s2_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 */

       uint8_t                 maxlun;                 /* max lun supported */

#ifdef UMASS_DEBUG
       struct timeval tv;
#endif

       char                    sc_dying;
       int                     sc_sense;

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

#define UMASS_MAX_TRANSFER_SIZE MAXPHYS