/* rcsid[]="$Header: rfvar.h,v 820.1 86/12/04 19:56:20 root Exp $" */
/* sccsid[]="%W% %Y% %Q% %G%" */

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*
 * Rimfire 44/45 controller
 */

/*
 * Minor device configuration.
 *
 * For disks, the unit and partition combination is used.
 * For tapes, bits 0, 1, 4, and 7 are the unit number; bit 2, no rewind on
 * close; bit 3, 1600 bpi or QIC-24 format for mag tape or cartridge
 * tape, respectively.
 *
 * We must have exactly 16 partitions, to conform with DK_NSIZES
 * in dkioctl.h.
 *
 * These macros should really do minor(d) first,
 * but we know the minor device number is the low byte,
 * so we save a few instructions.
 */
#define IS_CTAPE(x)	(minor(x)&0x10)
#define rdunit(d)	((u_char)(d) >> 4)
#define rdpart(d)	((int)(d) & 15)
#define rtunit(d)	((minor(d) & 3) | (IS_CTAPE(d)>>2))
#define rdmkdev(u, p)	makedev(0, (u) << 4 | (p))
#define rtmkdev(u)	makedev(0, (((u)<<2) & 0x10) | (u) & 3)
#define RT_NOREWIND	0x04
#define RT_1600BPI	0x08	/* 1600 bpi if mag tape */
#define RT_QIC24	0x08	/* QIC-24 format if cartridge tape */

#define RD_NSLAVE	8		/* disks per controller */
#define RT_NSLAVE	8		/* tapes per controller */

/*
 * Debugging flags
 */
#ifdef DEBUG
char rfdebug;
char rtdebug;
char rftest;			/* exercise driver logic without hardware */
int rferrrate;			/* percent error rate if rftest */
union rf_pb *rf_pb0;
union rf_pb *rf_pb1;
#else
#define rfdebug 0
#define rtdebug 0
#define rftest 0
#define rferrrate 0
#endif

/*
 * Tunable variables
 */
int rdretry;			/* number of retries for disk */
int rtretry;			/* number of retries for tape */
int rtrewtime;			/* seconds to wait for rewind */
char rdautomap;			/* do automatic bad track mapping */
int rdrps;			/* rotations per second, should be per drive */

/*
 * Interface to autoconf()
 */
int rfprobe(), rfslave(), rdattach(), rtattach();
struct mb_ctlr *rfinfo[];
struct mb_device *rdinfo[];
struct mb_device *rtinfo[];
struct mb_driver rfdriver;

/*
 * Special commands to disk and tape drives (e.g. formatting) are
 * implemented by inserting a special buffer into the request queue.
 * This buffer is recognized by rfstart() and handled differently.
 * There is only one command buffer for all controllers.  We probably
 * want to make it per drive, so parallel operations can be done.
 * But it really doesn't matter.
 * To get disk sorting working correctly, we assign a special illegal
 * cylinder number to the command buffer.  This also insures that the command
 * won't be linked with other operations.
 */
struct buf rfcbuf;		/* the command buffer, for rfcmd() */
union rf_pb rfcpb;		/* the command parameter block */
#define CMDCYL 10000		/* an impossible cylinder number */

#define INF 10000000		/* very large block number */

/*
 * Per controller information:
 *
 * Rc_busy is the software controller busy bit.
 * Rc_disk and rc_tape are the currently active disk and tape drive.
 * We don't trust the ctl bits in rc_pb.  They are also used to
 * round robin among the drives.
 */
struct rf_ctlr {
	struct rf_device *rc_device;
	char rc_busy;			/* controller busy */
	char rc_ctape;			/* this controller is a 44 */
	int rc_ctlr;			/* this controller's number */
	int rc_ndisk;			/* number of disks */
	struct rf_info *rc_disk;	/* linked list of disks */
	struct rf_info *rc_dact;	/* last active disk */
	int rc_ntape;			/* number of tapes */
	struct rf_info *rc_tape;	/* linked list of tapes */
	struct rf_info *rc_tact;	/* last active tape */
	struct rf_scb rc_scb;
	struct rf_ccb rc_ccb;
	union rf_pb rc_pb[20];
	struct rf_rb rc_rb;
};
struct rf_ctlr rf_ctlr[];

	/* number of linked commands */
#define NCMD (sizeof rf_ctlr->rc_pb / sizeof *rf_ctlr->rc_pb)

	/* rc_busy values, 0 is not busy */
#define BUSY_TAPE	1	/* doing tape operation */
#define BUSY_DISK	2	/* doing disk operation */

/*
 * Per disk information:
 *
 * The disk driver's handling of the request queue is somewhat unusual.
 * The requests are sorted by sector as well as by cylinder, on the
 * rd_actf list.  Rfstart() links all requests on the same cylinder
 * together into one controller operation.  These buffers are removed
 * from the rd_actf list, and put on the rd_io list.  Rfintr()
 * keeps the request with errors on the rd_io queue and removes
 * the successful requests.  Retries are done until the list becomes
 * empty or until 'rdretry' retries.
 * Because the active requests are removed from the list, rdsort()
 * can and does insert buffers at the head of rd_actf.
 * Rd_cylin is the current cylinder number of the drive, used by rdsort().
 * An rd_actl is not needed.
 * Bad track mapping is triggered automatically by certain read and
 * write errors on the block device.  Since several blocks on the same
 * track may be linked together, we remember the the cylinder and head
 * of the last track we mapped, to avoid mapping the same track twice
 * if two linked blocks on the same track both get errors.
 *
 * Per tape information:
 */
struct rf_info {
	char ri_istape;
	int ri_active;
	int ri_errcnt;
	struct buf ri_rbuf;
	struct mb_device *ri_md;
	struct rf_info *ri_link;
	union {
		struct rf_disk {
			int Rd_type;
			int Rd_nsec;
			int Rd_nhead;
			int Rd_ncyl;	/* number of data cylinders */
			int Rd_acyl;	/* number of alternate cylinders */
			int Rd_intrlv;	/* interleave factor for formatting */
			struct dk_sizes Rd_sizes[DK_NSIZES];
			int Rd_nsecpercyl;
			int Rd_cylin;	/* current cylinder number */
			int Rd_mapcyl;	/* cylinder of last track mapped out */
			int Rd_maphead;	/* head of last track mapped out */
			struct buf *Rd_actf;
			struct buf *Rd_io;
		} Ri_d;
		struct rf_tape {
			char Rt_open;		/* is open */
			char Rt_1600bpi;	/* last opened for 1600 bpi */
			char Rt_err;		/* can't recover from error */
			char Rt_lastiow;	/* last io was a write */
			u_char Rt_dst;		/* tp_dst from last command */
			u_short Rt_mst;		/* tp_mst from last command */
			time_t Rt_rewtime;	/* time of last rewind */
			daddr_t Rt_blkno;	/* current block number */
			daddr_t Rt_nxrec;	/* eof position, if known */
			struct buf *Rt_actf;
			struct buf *Rt_actl;
		} Ri_t;
	} ri_un;
};

#define ri_d		ri_un.Ri_d
#define ri_t		ri_un.Ri_t
#define ri_unit		ri_md->md_unit
#define ri_slave	ri_md->md_slave
#define ri_ctlr		ri_md->md_ctlr
#define ri_dk		ri_md->md_dk
#define ri_alive	ri_md->md_alive

#define rd_type		ri_d.Rd_type
#define rd_nsec		ri_d.Rd_nsec
#define rd_nhead	ri_d.Rd_nhead
#define rd_ncyl		ri_d.Rd_ncyl
#define rd_acyl		ri_d.Rd_acyl
#define rd_intrlv	ri_d.Rd_intrlv
#define rd_sizes	ri_d.Rd_sizes
#define rd_nsecpercyl	ri_d.Rd_nsecpercyl
#define rd_cylin	ri_d.Rd_cylin
#define rd_mapcyl	ri_d.Rd_mapcyl
#define rd_maphead	ri_d.Rd_maphead
#define rd_actf		ri_d.Rd_actf
#define rd_io		ri_d.Rd_io

#define rt_open		ri_t.Rt_open
#define rt_1600bpi	ri_t.Rt_1600bpi
#define rt_err		ri_t.Rt_err
#define rt_lastiow	ri_t.Rt_lastiow
#define rt_dst		ri_t.Rt_dst
#define rt_mst		ri_t.Rt_mst
#define rt_rewtime	ri_t.Rt_rewtime
#define rt_blkno	ri_t.Rt_blkno
#define rt_nxrec	ri_t.Rt_nxrec
#define rt_actf		ri_t.Rt_actf
#define rt_actl		ri_t.Rt_actl

	/* rd_active and rt_active values, 0 is not active */
#define ACTIVE_SEEK	1	/* seeking */
#define ACTIVE_SEEKDONE	2	/* seek completed */
#define ACTIVE_IO	3	/* doing io */
#define ACTIVE_CMD	4	/* doing command */

struct rf_info rf_disk[];
struct rf_info rf_tape[];

/*
 * Error messages.
 *
 * We try to be concise and to the point.  The error number is
 * always printed with the message, so the manual can be used
 * to look up the complete explanation.
 */
#define rferror(n) ((n) >= 0 && n < rf_nerr && rf_errlist[n] ? \
	rf_errlist[n] : "Unknown error")
char *rf_errlist[];
int rf_nerr;

	/* some statistics */
int rd_profile[NCMD];
