/*
 * RP04/RP06 disk driver
 */

#include <sys/param.h>
#include <sys/inode.h>
#include "../saio.h"

struct	device
{
	union {
		int	w;
		char	c[2];
	} xpcs1;		/* Control and Status register 1 */
	int	xpwc;		/* Word count register */
	caddr_t	xpba;		/* UNIBUS address register */
	int	xpda;		/* Desired address register */
	union {
		int	w;
		char	c[2];
	} xpcs2;		/* Control and Status register 2*/
	int	xpds;		/* Drive Status */
	int	xper1;		/* Error register 1 */
	int	xpas;		/* Attention Summary */
	int	xpla;		/* Look ahead */
	int	xpdb;		/* Data buffer */
	int	xpmr;		/* Maintenance register */
	int	xpdt;		/* Drive type */
	int	xpsn;		/* Serial number */
	int	xpof;		/* Offset register */
	int	xpdc;		/* Desired Cylinder address register*/
	int	xpcc;		/* Current Cylinder */
	int	xper2;		/* Error register 2 */
	int	xper3;		/* Error register 3 */
	int	xpec1;		/* Burst error bit position */
	int	xpec2;		/* Burst error bit pattern */
	int	xpbae;		/* 11/70 bus extension */
	int	xpcs3;
};

#define	XPADDR	((struct device *)0176700)

/*
 * Defines for Disk Type Independence
 */
#define	RP	022		/* RP04/5/6 */
#define	RM2	025		/* RM02/3 */
#define	RM3	024		/* RM02/3 */
#define	RM5	027		/* RM05 */
#define RM5X	076		/* Emulex + Ampex 9300CD */
#define	DVHP	077		/* Diva */

#define	HP_SECT	22
#define	HP_TRAC	19
#define	RM_SECT	32
#define	RM_TRAC	5
#define	DV_TRAC	19
#define	DV_SECT	33

#define	P400	020
#define	M400	0220
#define	P800	040
#define	M800	0240
#define	P1200	060
#define	M1200	0260

#define	GO	01
#define	PRESET	020
#define	RTC	016
#define	OFFSET	014
#define	SEARCH	030
#define	RECAL	06
#define DCLR	010
#define	WCOM	060
#define	RCOM	070

#define	IE	0100
#define	PIP	020000
#define	DRY	0200
#define	ERR	040000
#define	TRE	040000
#define	DCK	0100000
#define	WLE	04000
#define	ECH	0100
#define VV	0100
#define FMT22	010000

extern	char haveCSW;		/* bool, set if switch register exists */
int	xptype = 0;		/* drive type; declared so we can patch */

xpstrategy(io, func)
register struct iob *io;
{
	register unit;
	register i;
	register nm_sect_per_cyl,nsect;
	daddr_t bn;
	int sn, cn, tn;

	if (((unit = io->i_unit) & 04) == 0)
		bn = io->i_bn;
	else {
		unit &= 03;
		bn = io->i_bn;
		bn -= io->i_boff;
		i = unit + 1;
		unit = bn%i;
		bn /= i;
		bn += io->i_boff;
	}

	XPADDR->xpcs2.w = unit;

	if((XPADDR->xpds & VV) == 0) {
		XPADDR->xpcs1.c[0] = PRESET|GO;
		XPADDR->xpof = FMT22;
	}
	/*
 	 *	This next weirdness handled the look up into the Drive Type
 	 *	register to tell what type of disk we have here.
	 *	Look in switch register first (if there is one).
 	 *
 	 *	Note: No need to look up after the first time.
 	 */
	
	if (xptype == 0) {
		if (haveCSW && (*CSW == RM2 || *CSW == RM3 || *CSW == RM5
		    || *CSW == RM5X || *CSW == RP || *CSW == DVHP))
			xptype = *CSW;
		else
			xptype = (XPADDR->xpdt & 077);
	}

	switch(xptype)
	{

	case RM2:
	case RM3:
		nm_sect_per_cyl = RM_SECT * RM_TRAC;
		nsect = RM_SECT;
		break;

	case RM5:
	case RM5X:
		nm_sect_per_cyl = RM_SECT * HP_TRAC;
		nsect = RM_SECT;
		break;

	case RP:
		nm_sect_per_cyl = HP_SECT * HP_TRAC;
		nsect = HP_SECT;
		break;

	case DVHP:
		nm_sect_per_cyl = DV_SECT * DV_TRAC;
		nsect = DV_SECT;
		break;

	default:
		printf("xp: unknown device type 0%o\n", xptype);
		return(-1);	
	}
	cn = bn/(nm_sect_per_cyl);
	sn = bn%(nm_sect_per_cyl);
	tn = sn/nsect;
	sn = sn%nsect;

	XPADDR->xpdc = cn;
	XPADDR->xpda = (tn << 8) + sn;
	XPADDR->xpba = io->i_ma;
	XPADDR->xpwc = -(io->i_cc>>1);
	unit = (segflag << 8) | GO;
	if (func == READ)
		unit |= RCOM;
	else if (func == WRITE)
		unit |= WCOM;
	XPADDR->xpcs1.w = unit;
	while ((XPADDR->xpcs1.w&DRY) == 0)
			;
	if (XPADDR->xpcs1.w & TRE) {
		printf("disk error: cyl=%d track=%d sect=%d cs2=%o, er1=%o\n",
		    cn, tn, sn, XPADDR->xpcs2, XPADDR->xper1);
		return(-1);
	}
	return(io->i_cc);
}
