/*
 * Device-independent level for ATAPI drivers.
 *
 * Copyright (C) 1995 Cronyx Ltd.
 * Author Serge Vakulenko, <vak@cronyx.ru>
 *
 * This software is distributed with NO WARRANTIES, not even the implied
 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Authors grant any other persons or organizations permission to use
 * or modify this software as long as this message is kept with the software,
 * all derivative works or modified versions.
 *
 * Version 1.9, Thu Oct 12 15:53:50 MSK 1995
 */

/*
 * Disk Controller ATAPI register definitions.
 */
#ifdef PC98
#define AR_DATA         0x0             /* RW - data register (16 bits) */
#define AR_ERROR        0x2             /*  R - error register */
#define AR_FEATURES     0x2             /*  W - features */
#define AR_IREASON      0x4             /* RW - interrupt reason */
#define AR_TAG          0x6             /*    - reserved for SAM TAG byte */
#define AR_CNTLO        0x8             /* RW - byte count, low byte */
#define AR_CNTHI        0xa             /* RW - byte count, high byte */
#define AR_DRIVE        0xc             /* RW - drive select */
#define AR_COMMAND      0xe             /*  W - command register */
#define AR_STATUS       0xe             /*  R - immediate status */
#else
#define AR_DATA         0x0             /* RW - data register (16 bits) */
#define AR_ERROR        0x1             /*  R - error register */
#define AR_FEATURES     0x1             /*  W - features */
#define AR_IREASON      0x2             /* RW - interrupt reason */
#define AR_TAG          0x3             /*    - reserved for SAM TAG byte */
#define AR_CNTLO        0x4             /* RW - byte count, low byte */
#define AR_CNTHI        0x5             /* RW - byte count, high byte */
#define AR_DRIVE        0x6             /* RW - drive select */
#define AR_COMMAND      0x7             /*  W - command register */
#define AR_STATUS       0x7             /*  R - immediate status */
#endif

/*
 * Status register bits
 */
#define ARS_CHECK       0x01            /* error occured, see sense key/code */
					/* bit 0x02 reserved */
#define ARS_CORR        0x04            /* correctable error occured */
#define ARS_DRQ         0x08            /* data request / ireason valid */
#define ARS_DSC         0x10            /* immediate operation completed */
#define ARS_DF          0x20            /* drive fault */
#define ARS_DRDY        0x40            /* ready to get command */
#define ARS_BSY         0x80            /* registers busy */
					/* for overlap mode only: */
#define ARS_SERVICE     0x10            /* service is requested */
#define ARS_DMARDY      0x20            /* ready to start a DMA transfer */
#define ARS_BITS        "\20\010busy\7ready\6fault\5opdone\4drq\3corr\1check"

/*
 * Error register bits
 */
#define AER_ILI         0x01            /* illegal length indication */
#define AER_EOM         0x02            /* end of media detected */
#define AER_ABRT        0x04            /* command aborted */
#define AER_MCR         0x08            /* media change requested */
#define AER_SKEY        0xf0            /* sense key mask */
#define AER_SK_NO_SENSE         0x00    /* no specific sense key info */
#define AER_SK_RECOVERED_ERROR  0x10    /* command succeeded, data recovered */
#define AER_SK_NOT_READY        0x20    /* no access to drive */
#define AER_SK_MEDIUM_ERROR     0x30    /* non-recovered data error */
#define AER_SK_HARDWARE_ERROR   0x40    /* non-recoverable hardware failure */
#define AER_SK_ILLEGAL_REQUEST  0x50    /* invalid command parameter(s) */
#define AER_SK_UNIT_ATTENTION   0x60    /* media changed */
#define AER_SK_DATA_PROTECT     0x70    /* reading read-protected sector */
#define AER_SK_BLANK_CHECK  	0x80    /* blank check */
#define AER_SK_VENDOR_SPECIFIC 	0x90    /* vendor specific skey */
#define AER_SK_COPY_ABORTED  	0xa0    /* copy aborted */
#define AER_SK_ABORTED_COMMAND  0xb0    /* command aborted, try again */
#define AER_SK_EQUAL		0xc0	/* equal */
#define AER_SK_VOLUME_OVERFLOW	0xd0	/* volume overflow */
#define AER_SK_MISCOMPARE	0xe0    /* data did not match the medium */
#define AER_SK_RESERVED		0xf0
#define AER_BITS        "\20\4mchg\3abort\2eom\1ili"

/*
 * Feature register bits
 */
#define ARF_DMA         0x01            /* transfer data via DMA */
#define ARF_OVERLAP     0x02            /* release the bus until completion */

/*
 * Interrupt reason register bits
 */
#define ARI_CMD         0x01            /* command(1) or data(0) */
#define ARI_IN          0x02            /* transfer to(1) or from(0) the host */
#define ARI_RELEASE     0x04            /* bus released until completion */

/*
 * Drive register values
 */
#define ARD_DRIVE0      0xa0            /* drive 0 selected */
#define ARD_DRIVE1      0xb0            /* drive 1 selected */

/*
 * ATA commands
 */
#define ATAPIC_IDENTIFY         0xa1    /* get drive parameters */
#define ATAPIC_PACKET           0xa0    /* execute packet command */

/*
 * Mandatory packet commands
 */
#define ATAPI_TEST_UNIT_READY   0x00    /* check if the device is ready */
#define ATAPI_REZERO_UNIT   	0x01    /* reinit device */
#define ATAPI_REQUEST_SENSE     0x03    /* get sense data */
#define ATAPI_START_STOP        0x1b    /* start/stop the media */
#define ATAPI_PREVENT_ALLOW     0x1e    /* prevent/allow media removal */
#define ATAPI_READ_CAPACITY     0x25    /* get volume capacity */
#define ATAPI_READ_BIG          0x28    /* read data */
#define ATAPI_WRITE_BIG		0x2a    /* write data */
#define ATAPI_SYNCHRONIZE_CACHE	0x35    /* flush write buf, close write chan */
#define ATAPI_READ_SUBCHANNEL   0x42    /* get subchannel info */
#define ATAPI_READ_TOC          0x43    /* get table of contents */
#define ATAPI_READ_TRACK_INFO   0x52    /* get track information structure */
#define ATAPI_MODE_SELECT	0x55    /* set device parameters */
#define ATAPI_MODE_SENSE        0x5a    /* get device parameters */
#define ATAPI_CLOSE_TRACK       0x5b    /* close track/session */
#define ATAPI_LOAD_UNLOAD       0xa6    /* changer control command */
#define ATAPI_PLAY_CD           0xb4    /* universal play command */
#define ATAPI_MECH_STATUS       0xbd    /* get changer mechanism status */
#define ATAPI_READ_CD           0xbe    /* read data */
/*
 * Optional packet commands
 */
#define ATAPI_PLAY_MSF          0x47    /* play by MSF address */
#define ATAPI_PAUSE             0x4b    /* stop/start audio operation */

/*
 * Nonstandard packet commands
 */
#define ATAPI_PLAY_TRACK        0x48    /* play by track number */
#define ATAPI_PLAY_BIG          0xa5    /* play by logical block address */

#define DSC_POLL_INTERVAL	10

/*
 * Drive parameter information
 */
struct atapi_params {
	unsigned        cmdsz : 2;      /* packet command size */
#define AT_PSIZE_12     0               /* 12 bytes */
#define AT_PSIZE_16     1               /* 16 bytes */
	unsigned : 3;
	unsigned        drqtype : 2;    /* DRQ type */
#define AT_DRQT_MPROC   0               /* microprocessor DRQ - 3 msec delay */
#define AT_DRQT_INTR    1               /* interrupt DRQ - 10 msec delay */
#define AT_DRQT_ACCEL   2               /* accelerated DRQ - 50 usec delay */
	unsigned        removable : 1;  /* device is removable */
	unsigned        devtype : 5;    /* device type */
#define AT_TYPE_DIRECT  0               /* direct-access (magnetic disk) */
#define AT_TYPE_TAPE    1               /* streaming tape (QIC-121 model) */
#define AT_TYPE_CDROM   5               /* CD-ROM device */
#define AT_TYPE_OPTICAL 7               /* optical disk */
	unsigned : 1;
	unsigned        proto : 2;      /* command protocol */
#define AT_PROTO_ATAPI  2
	short reserved1[9];
	char            serial[20];     /* serial number - optional */
	short reserved2[3];
	char            revision[8];    /* firmware revision */
	char            model[40];      /* model name */
	short reserved3[2];
	u_char          vendor_cap;     /* vendor unique capabilities */
	unsigned        dmaflag : 1;    /* DMA supported */
	unsigned        lbaflag : 1;    /* LBA supported - always 1 */
	unsigned        iordydis : 1;   /* IORDY can be disabled */
	unsigned        iordyflag : 1;  /* IORDY supported */
	unsigned : 1;
	unsigned        ovlapflag : 1;  /* overlap operation supported */
	unsigned : 1;
	unsigned        idmaflag : 1;   /* interleaved DMA supported */
	short reserved4;
	u_short         pio_timing;     /* PIO cycle timing */
	u_short         dma_timing;     /* DMA cycle timing */
	u_short         flags;
#define AT_FLAG_54_58   1               /* words 54-58 valid */
#define AT_FLAG_64_70   2               /* words 64-70 valid */
	short reserved5[8];
	u_char          swdma_flag;     /* singleword DMA mode supported */
	u_char          swdma_active;   /* singleword DMA mode active */
	u_char          mwdma_flag;     /* multiword DMA mode supported */
	u_char          mwdma_active;   /* multiword DMA mode active */
	u_char          apio_flag;      /* advanced PIO mode supported */
	u_char reserved6;
	u_short         mwdma_min;      /* min. M/W DMA time per word (ns) */
	u_short         mwdma_dflt;     /* recommended M/W DMA time (ns) - optional */
	u_short         pio_nfctl_min;  /* min. PIO cycle time w/o flow ctl - optional */
	u_short         pio_iordy_min;  /* min. PIO c/t with IORDY flow ctl - optional */
	short reserved7[2];
	u_short         rls_ovlap;      /* release time (us) for overlap cmd - optional */
	u_short         rls_service;    /* release time (us) for service cmd - optional */
};

/*
 * ATAPI operation result structure
 */
struct atapires {
	u_char code;                    /* result code */
#define RES_OK          0               /* i/o done */
#define RES_ERR         1               /* i/o finished with error */
#define RES_NOTRDY      2               /* controller not ready */
#define RES_NODRQ       3               /* no data request */
#define RES_INVDIR      4               /* invalid bus phase direction */
#define RES_OVERRUN     5               /* data overrun */
#define RES_UNDERRUN    6               /* data underrun */
	u_char status;                  /* status register contents */
	u_char error;                   /* error register contents */
};

struct atapidrv {                       /* delayed attach info */
	int ctlr;                       /* IDE controller, 0/1 */
	int unit;                       /* drive unit, 0/1 */
	int port;                       /* controller base port */
	int attached;                   /* the drive is attached */
};

struct buf;
struct wcd;
typedef void atapi_callback_t(struct wcd *, struct buf *, int, struct atapires);

struct atapicmd {                       /* ATAPI command block */
	struct atapicmd *next;          /* next command in queue */
	int              busy;          /* busy flag */
	u_char           cmd[16];       /* command and args */
	int              unit;          /* drive unit number */
	int              count;         /* byte count, >0 - read, <0 - write */
	char            *addr;          /* data to transfer */
	atapi_callback_t *callback;     /* call when done */
	void            *cbarg1;        /* callback arg 1 */
	void            *cbarg2;        /* callback arg 1 */
	struct atapires  result;        /* resulting error code */
};

struct atapi {                          /* ATAPI controller data */
	u_short          port;          /* i/o port base */
	u_char           ctrlr;         /* physical controller number */
	u_char           debug : 1;     /* trace enable flag */
	u_char           cmd16 : 1;     /* 16-byte command flag */
	u_char           intrcmd : 1;   /* interrupt before cmd flag */
	u_char           slow : 1;      /* slow reaction device */
	u_char           accel : 1;     /* accelerated reaction device */
	u_char           use_dsc : 1;	/* use DSC completition handeling */
	u_char 		 wait_for_dsc : 1;
	u_int		 dsc_timeout;
	u_char           attached[2];   /* units are attached to subdrivers */
	struct atapi_params *params[2]; /* params for units 0,1 */
	struct atapicmd *queue;         /* queue of commands to perform */
	struct atapicmd *tail;          /* tail of queue */
	struct atapicmd *free;          /* queue of free command blocks */
	struct atapicmd  cmdrq[16];     /* pool of command requests */
};

#ifdef KERNEL
struct atapi;

extern struct atapidrv atapi_drvtab[4]; /* delayed attach info */
extern int atapi_ndrv;                  /* the number of potential drives */
extern struct atapi *atapi_tab;         /* the table of atapi controllers */

#ifndef ATAPI_STATIC
#   define atapi_start             (*atapi_start_ptr)
#   define atapi_intr              (*atapi_intr_ptr)
#   define atapi_debug             (*atapi_debug_ptr)
#   define atapi_request_wait      (*atapi_request_wait_ptr)
#   define atapi_request_callback  (*atapi_request_callback_ptr)
#   define atapi_request_immediate (*atapi_request_immediate_ptr)
#endif

#ifndef ATAPI_MODULE
int atapi_attach (int ctlr, int unit, int port);
#endif

/*
 * These "functions" are declared with archaic `extern's because they are
 * actually pointers in the !ATAPI_STATIC case.
 */
extern int atapi_start (int ctrlr);
extern int atapi_intr (int ctrlr);
extern void atapi_debug (struct atapi *ata, int on);
extern struct atapires atapi_request_wait (struct atapi *ata, int unit,
	u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
	u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
	u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
	char *addr, int count);
extern void atapi_request_callback (struct atapi *ata, int unit,
	u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
	u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
	u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
	char *addr, int count, atapi_callback_t *done, void *x, void *y);
extern struct atapires atapi_request_immediate (struct atapi *ata, int unit,
	u_char cmd, u_char a1, u_char a2, u_char a3, u_char a4,
	u_char a5, u_char a6, u_char a7, u_char a8, u_char a9,
	u_char a10, u_char a11, u_char a12, u_char a13, u_char a14, u_char a15,
	char *addr, int count);
#endif
