/*	Convergent Technologies - System V - May 1983	*/
/*	"@(#)gdisk.h	1.19"	*/

#ifndef gdisk_h
#define gdisk_h
#include "sys/buf.h"
#include "sys/iobuf.h"
#include "sys/elog.h"

#define DISKS		3	/* the number of disks on MiniFrame */
#define MINIDENSITY 	2	/* MiniFrame floppy disks are double density */
#define GDRETRIES	10	/* 10 retries to recover operation */
#define GAPSZ		36	/* size of gap1 and gap3 for format */

/*	defines for manipulating the minor node number	*/
#define DRVSHIFT	4	/* slice number occupies the ls 4 bits */
#define DRVMSK		3	/* drive number is 2 bits */
#define SLCMSK		0xF	/* slice number is 4 bits */
#define MAXSLICE	16	/* maximum number of slices */

/*	bit ops to isolate fields in minor number */
#define	gddrive(X)	((X>>DRVSHIFT)&DRVMSK)
#define	gdslice(X)	(X&SLCMSK)

#define exchangeable(gdswptr)	(gdswptr->dsk.flags & EXCHANGEABLE)
#define winch(gdswptr)		(gdswptr->v_flags & WINCH)

/*
 *	data describing disk specific information held in the VHB and then
 *	loaded into the gdsw table
 */
struct gdswprt {
	char	name[6];	/* printf name */
	ushort	cyls;		/* the number of cylinders for this disk */
	ushort	heads;		/* number of heads per cylinder */
	ushort	psectrk;	/* number of physical sectors per track */
	ushort	pseccyl;	/* number of physical sectors per cylinder */
	char	flags;		/* floppy density and high tech drive flags */
	char	step;		/* stepper motor rate to controller */
	ushort	sectorsz;	/* physical sector size in bytes */
};

/*	flags in gdswprt	*/
#define FPDENSITY	0x01	/* 0=single 1=double density */
#define FPMIXDENS	0x02	/* 0=all tracks are the same density
				   1= cylinder zero is single density */
#define HITECH		0x04	/* 0= reduced write current is valid,
				   1= head select bit 3 is valid */
#define NEWPARTTAB	0x08	/* 0= old style partition table,
				   1= new style partition table */
#define RWCWPC		0x10	/* 0= avoid reduced write current/write precomp,
				   1= set reduced write current/write precomp.
				   write precomp is selected by HITECH */
#define EXCHANGEABLE	0x20	/* 0= not exchangeable (ignored for floppy for
				   compatibility reasons, so must check for
				   for drive == 2 at times)
				   1= exchangeable disk */

/*	disk slice table	*/
struct partit{				/* partition table */
	union {
		uint strk;	/* start track number (new style) */
		struct {
			ushort 	strk;	/* start track # */
			ushort	nsecs;	/* # logical blocks available to user */
		} old;
	} sz;
};

/*	disk slice table in memory	*/
struct mpartit{				/* partition table */
		uint 	strk;		/* start track # */
		uint	nsecs;		/* # of logical sectors available to user */
};

/*	bad block cell on disk	*/
struct bbcell {
	ushort	cyl;		/* the cylinder of the bad block */
	ushort	badblk;		/* the physical sector address of the bad block
					within the cylinder cyl */
	ushort	altblk;		/* track number of alternate */
	ushort	nxtind;		/* index into the cell array for next bad block
				   cell for this cylinder */
};

/*	bad block cell in memory	*/
struct bbmcell {
	ushort	badblk;		/* the physical sector address of the bad block
					within the cylinder cyl */
	ushort	altblk;		/* track number of alternate */
	ushort	nxtind;		/* index into the cell array for next bad block
				   cell for this cylinder */
};

/*	some defines for bad block support	*/
#define MAXBOFBBT	3			/* BBT is max of 3 blks */
#define NBBPERB 127	/* the # of bad blocks in each block of the bbt */
#define MAXBBT		(MAXBOFBBT*1024)	/* space in memory */
#define MAXBB		(MAXBOFBBT*NBBPERB)	/* max bad blocks */

/* internal switch for various disk parameters and device specific routines */
struct gdsw {
	uint	v_flags;	/* flags for this drive/disk */
	struct	gdswprt dsk;	/* disk specific information */
	ushort	curcyl;		/* current cylinder number */
	ushort	reqcyl;		/* cylinder number required for this transfer */
	ushort	sectrk;		/* actual number of physical data sectors
				   in the logical map per track.
				   i.e omitting the alternate sectors
				   located in the 17th sector of each track */
	ushort	seccyl;		/* actual number of physical data sectors
				   in the logical map per cylinder.
				   i.e omitting the alternate sectors
				   located in the 17th sector of each track */
	ushort	DMAto;	/* max duration of a disk operation (1/4 sec units) */
	int	(*intr)();
	int	(*start)();
	/*	more volume home block information	*/
	ushort	szbbq;		/* size of bad block cylinder index */
	ushort	szbb;		/* size of bad block table */
	ushort	*bbq;		/* bad block cylinder index */
	struct	bbmcell *bb;	/* bad block table */
	struct mpartit partab[MAXSLICE];	/* partition table */
	ushort	wpccyl;		/* write precompensation cylinder */
};

#define MNAMSZ	16		/* max length of name including null terminator */
struct mntnam {
	char	name[MNAMSZ];	/* full path name of mount point */
};

/*	volume home block on disk	*/
struct vhbd {
	uint	magic;			/* miniframe disk format code */
	int	chksum;			/* adjustment so 32 bit sum starting
					   from magic for 1K bytes sums to -1 */
	struct	gdswprt dsk;		/* specific description of this disk */
	struct partit partab[MAXSLICE];	/* partition table */
	struct	resdes{			/* reserved area special files */
		daddr_t	blkstart;	/* start logical block # */
		ushort	nblocks;	/* length in logical blocks
					   (zero implies not present) */
	} resmap[8];
/*	resmap consists of the following entries:
 *		loader area
 *		bad block table
 *		dump area
 *		down load image file
 *		Bootable program, size determined by a.out format. nblocks=1.
 */
	char	fpulled;		/* dismounted last time? */
	long	time;			/* time last came on line */
	short	rwcwpccyl;		/* value to program for RWC/WPC,
					   this is rqd cylinder/4 */
	ushort	enetaddr[3];		/* ethernet station address */
	char	minires[68];		/* for future mini frame enhancements */
	char	sysres[292];		/* custom system area */
	struct	mntnam mntname[MAXSLICE];  /* names for auto mounting; null
					      string means no auto mount */
	char	userres[256];		/* user area */
};

#define VHBMAGIC	0x55515651	/* magic number in disk vhb */

/*	indexes into resmap	*/
#define	INDLOADER	0
#define INDBBTBL	1
#define INDDUMP		2
#define INDDOWNLOAD	3
#define INDBOOT		4

/*	values for hwtype	*/
#define	HD	0		/* Winchester */
#define SY	1		/* Syquest */
#define FD	2		/* floppy */

/*	drive numbers		*/
#define GDDRV0	0		/* WD1010 drive 0 - Winchester.	type=HD */
#define GDDRV1	1		/* WD1010 drive 1 - Winchester.	type=HD
						OR  Syquest.	type=SY */
#define GDDRV2	2		/* WD2797 drive 0 - Floppy.	type=FD */

/*	values of flag bits in v_flags	*/
#define F_OPENED	0x0001	/* set when the first open is performed for
					any slice on this disk, cleared when the
					drive goes off line - indicates an
					attempt has been made to read the vhb */
#define F_CT_FMT	0x0002	/* a valid vhb has been read for this disk,
					this implies logical block=1024 bytes
					and bad block handling */
#define F_READY		0x0004	/* ready from controller */
#define F_PULLED	0x0008	/* disk was removed without permission last
					time, produces warning on open */
#define PHYS_ADDR	0x0010	/* used for formatting/alien disks.  (iv)
				   v_flags is set by ioctl for reading non
				   standard floppies.  cleared by gdreadvhb.
				   slice 0 is the only valid one */
				/* in this mode the offset number is the
				   physical sector number <<10, whether sector
				   size is 1024, 512, 256 or 128. count is
				   still the number of bytes. */
#define F_MAYREMOVE	0x0020	/* the drive may go off line */
#define WR_PROT		0x0040	/* set after each transfer. 1=write protected
					disk. 0=not protected */
#define WINCH		0x0100	/* drive is a Winchester */
#define EXCH		0x0200	/* drive is exchangeable */


/*	bad block table	*/
/*
 *	On the disk the bad block table consists of an array of cells, one per
 *	used alternate physical sector.
 *	cyl	is the cylinder containing the bad block badblk.
 *	badblk	is the physical sector address (within the cylinder cyl)
 *		of a bad block.
 *	altblk	is the location of the alternate physical sector. It is
 *		specified as the track number since the alternate sector is
 *		always the last sector of a track.
 *	nxtind	is a chain of bad blocks on the same cylinder. The number is
 *		the index into this array of bad block cells. A value of zero
 *		means the end of the chain for this cylinder. The zero'th
 *		entry is not used, other than to hold the count of used cells).
 *
 *	
 *	In memory a similar array will be held in the appropriate gdbtab
 *	together with an array containing an entry for each cylinder which
 *	holds the index into the above array of cells for the head for that
 *	cylinder.
 *	This means that a zero entry indicates no bad blocks on that cylinder.
 *
 *	This mechanism implies a maximum of 255 bad blocks per disk which is
 *	adequate for disks upto the 250 Mbyte range.
 *	The bad block table is held as a chained set of logical blocks on
 *	track zero. Each block can hold 256 entries.
 *	The first bad block cell in each logical block of the bad block table
 *	contains a chksum (in cyl and badblk) for the 1024 byte block, it is
 *	a 32 bit sum which sums to -1. altblk contains the logical block
 *	number of the next block in the bad block table, zero=end.
 *	On a disk with an odd number of sectors per track, the last sector
 *	is removed from the logical mapping and is used as an alternate area.
 *
 *	Bad block handling is disabled on floppies.
 */
#define HDMAXBADBLK	256	/* only support maximum of 256 bad blocks */
#define HDMAXCYL	1024	/* support a maximum of 1024 cylinders */
#define SYMAXBADBLK	40	/* only support maximum of 40 bad blocks */
#define SYMAXCYL	1024	/* support a maximum of 1024 cylinders */
#define FPMAXBADBLK	0	/* no bad block support on floppies */
#define FPMAXCYL	0	/* no bad block support on floppies */

/*	this structure contains the relevant information about the transfer
 *	currently in progress.
 */
struct driver {
/* *******	d_flags + ctl are accessed by assembly code in trap.s ******* */
/* *******	do not change their sizes, locations or contents without **** */
/* *******	checking their use in trap.s.				***** */
	ushort	d_flags;	/* driver flags */
	char	ctl;		/* controller number */
	char	retries;	/* number of retries remaining for this
				   operation before we give up */
	int	fd_timer;	/* fd motor on timer */
	ushort	timer;		/* timer for operation completion */
	struct	xfrinfo x;	/* details of the current required transfer */
	struct	xfrinfo rpt;	/* details of the current real transfer */
	/*	information for repeating a transfer
			(needed because of bad blocks) */
	ushort	rptcyl;
	ushort	rpttrk;
	ushort	rptsec;
	ushort	rpttcnt;
	dev_t	disk;		/* current device for transfer */
	int	xfrcnt;		/* count of characters transferred so far */
	union {			/* holds virtual address in Kernel address */
		caddr_t b_addr;	/* space that is mapped to correspond with */
		struct {	/* the address in bp->a_un */
			ushort high;
			ushort low;
		} addr;
	} c_un;
	struct proc *notify;	/* proc pointer to inform when drive
						comes online */
	ushort	rpts;		/* total transfers for complete request */
};

/*	values in d_flags	*/
#define F_ACTIVE	(ushort)0x0001	/* driver operation in progress */
#define F_DMAON		(ushort)0x0002	/* DMA operation in progress */
#define F_SEEKING	(ushort)0x0004	/* seek operation in progress */
#define FDMTRON		(ushort)0x0008	/* floppy motor is on + up to speed */
#define FDMTRSTRT	(ushort)0x0010	/* the floppy motor has been started but
					is not up to speed yet */
#define FDCHECKED	(ushort)0x0020	/* set when floppy has been verified as
					still being the same one that was on
					line before the motor was turned off */
#define MAYGETFDINT	(ushort)0x0040	/* on resetting the floppy the 2797 may
					   or may not choose to give an
					   interrupt, so be prepared to
					   discard it */
#define FDSPECIALRD	(ushort)0x0080	/* a read of the vhb from dismount
						caused a special read to be be
						performed in the disk driver
						while checking if the floppy had
						been changed */
#define FDNEWQ		(ushort)0x0100	/* new disk maybe so use recal to
					   establish head position */
#define FD_TIMEOUT	(ushort)0x0200	/* a timeout occurred on a floppy
					   transfer, floppy not in or in
					   backwards - so terminate with error*/

/*	values in ctl (supplied from assembly interrupt code)	*/
#define WD2797	1
#define WD1010	0
#define BIU	2

extern struct driver gdreal;

extern struct gdsw gdsw[];
extern struct iotime gdstat[];
extern struct iobuf gdtab, gdutab[];

extern char gdourunflg;		/* flag indicating disk over/under run */

#define	GDPRI	(PZERO + 3)

/*
 *	Internal commands
 */
#define CMD_READ	((char)0)
#define CMD_WRITE	((char)1)
#define CMD_FORMAT	((char)2)

/*
 *	Command information for WD1010.
 */
#define	HDMASK		0x0007	/* 3 bits for head size */
#define W_RESTORE	0x0010	/* restore command */
#define W_SEEK		0x0070	/* seek command */
#define W_READ		0x0020	/* read sector command */
#define W_WRITE		0x0030	/* write sector command */
#define W_SCANID	0x0040	/* scan id command */
#define W_WR_FORMAT	0x0050	/* write format command */
#define W_RATEMSK	0x000F	/* LS 4 bits of restore/seek command = rate */
#define W_MULT		0x0004	/* multi sector transfer flag for read/write */
#define W_INTEOC	0x0008	/* interrupt at end of command (read only) */

/*
 *	Status information for WD1010.
 */
#define W_ERR		0x0001	/* logical or of bits in the error register */
#define W_CIP		0x0002	/* 1= command in progress */
#define W_DRQ		0x0008	/* 1= data request outstanding */
#define W_SEKCMP	0x0010	/* 1= seek complete */
#define W_WRFLT		0x0020	/* 1= write fault */
#define W_RDY		0x0040	/* 1= ready,frozen on error until status read */
#define W_BUSY		0x0080	/* 1= WD1010 is accessing the disk */

/*
 *	Error status information for the WD1010.
 */
#define W_BBD		0x0080	/* bad block detected (not used) */
#define W_CRC		0x0040	/* 1= CRC error */
#define W_ID		0x0010	/* 1= id not found */
#define W_ABC		0x0004	/* 1= aborted command */
#define W_TK		0x0002	/* 1= restore command did not find track zero */

/*
 *	Command information for the WD2797.
 */
#define F_RESTORE	0x0000	/* restore command */
#define F_SEEK		0x0010	/* seek command */
#define F_STEP		0x0020	/* step command */
#define F_STEPIN	0x0040	/* step-in command */
#define F_STEPOUT	0x0060	/* step-out command */
#define F_READ		0x0080	/* read sector command */
#define F_WRITE		0x00a0	/* write sector command */
#define F_READADR	0x00c0	/* read address command */
#define F_READTRK	0x00e0	/* read track command */
#define F_WRITETRK	0x00f0	/* write track command */
#define F_FORCEINT	0x00d0	/* force interrupt command */

#define LOADHEAD	0x0008	/* 1= load head at beginning (restore,seek,step,
				   step-in, step-out) */
#define VERIFYTRK	0x0004	/* 1= verify on destination track (restore,seek,
				   step, step-in, step-out) */
#define STEPMSK		0x0003	/* stepping motor rate (restore,seek,
				   step, step-in, step-out) */
#define F_UPDTRKRG	0x0010	/* 1= update track register (step, step-in,
				   step-out) */
#define F_MULT		0x0010	/* 1= multiple record flag(read/write sector) */
#define F_LENGTH	0x0008	/* 1= lsb sector length in sector id field means
				   00=128 01=256 10=512 11=1024
				   (read/write sector) */
#define F_15MSDLY	0x0004	/* 1= 15MS delay(30 MS for 1MHZ) (read/write
				   sector, read/write track and read address) */
/* #define F_UPDATESSO	0x0002	/* 1= update SSO to 1 (read/write
				   sector, read/write track and read address) */
#define F_D_A_MRK	0x0001	/* data address mark (write sector) */
#define F_INT0		0x0001	/* force interrupt on not ready to ready
				   transition. (force interrupt) */
#define F_INT1		0x0002	/* force interrupt on ready to not ready
				   transition. (force interrupt) */
#define F_INT2		0x0004	/* force interrupt on index pulse.
				   (force interrupt) */
#define F_INT3		0x0008	/* force interrupt immediately (requires reset).
				   (force interrupt) */
#define F_INT_NO	0x0000	/* terminate with no interrupt.(force interrupt)

/*
 *	Status information for the WD2797.
 */
#define F_BUSY		0x0001	/* 1= command under execution */
#define F_DRQ		0x0002	/* 1= data request line */
#define F_LOSTDATA	0x0004	/* 1= CPU didn't respond to DRQ */
#define F_CRCERR	0x0008	/* 1= error in one or more id fields or an error
				   in the data field */
#define F_RECNF		0x0010	/* 1= requested side,track, sector not found */
#define F_SEEKERR	0x0010	/* 1= seek error */
#define F_RECTYP	0x0020	/* 1= deleted data mark else data mark, on read.
				   forced to zero on write. */
#define F_WRPROT	0x0040	/* 1= indicates a protected disk on write,
				   not used on read */
#define F_NOTRDY	0x0080	/* 1= drive not ready */
#define F_TRK0		0x0004	/* 1= heads on track zero */

/*
 *	down load file index.
 */
#define DLDSZ	256
struct dldent {
	short d_strt;		/* block displacement from down load index */
	short d_sz;		/* # of blocks for this entry */
};

struct dldind {
	struct dldent dldent[DLDSZ];
};
#endif gdisk_h
