static char     SCCS_ID [] = "@(#)msm.c	1.3";
/*
 * MSM disk driver - 67MB and 256MB
 */

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

#define	ALTBSY	0x20
#define	UNS	0x10
#define UNREADY	0x08
#define	SINC	0x02
#define	OFFL	0x01

#define	DISABLE	0x80
#define ENABLE	0x40
#define	DISARM	0xc0
#define SETHEAD	0x20
#define	SETCYL	0x10
#define	SEEK	0x02
#define RELEASE	0xb0

#define CNTL_UNRCV      0xc1
#define CYL_OV          0x10
#define IDLE		0x02

#define CREAD            0x01
#define CWRITE           0x02
#define CRESET           0x08

#define	STOP	0x48
#define	GO	0x50
#define	READ_GO	0x70
#define SELCHBSY	0x08

#ifdef NORMAL
char    msmaddr[4]      = { 0xfc, 0xfd, 0xfe, 0xff };
char    msmcntl         = 0xfb;
char    msmselch        = 0xf0;
#else  NORMAL
char    msmaddr[4]      = { 0xec, 0xed, 0xee, 0xef };
char    msmcntl         = 0xeb;
char    msmselch        = 0xf1;
#endif NORMAL

static int      curcntl;        /* controller address for msmidle */

#define NSECTORS 2              /* number of physical sectors per 512 bytes */
#define SECSHIFT 1              /* shift for NSECTORS */
#define NBPT    32              /* 512-byte blocks per track */

#define D67_NBPC        (32*5)  /* 512-byte blocks per cylinder - 67MB */
#define D256_NBPC       (32*19) /* 512-byte blocks per cylinder - 256MB */
#define C13R_NBPC       (32*1 ) /* 512-byte blocks per cylinder - 13MBR */
#define C13F_NBPC       (32*1 ) /* 512-byte blocks per cylinder - 13MBF */
#define C40F_NBPC       (32*3 ) /* 512-byte blocks per cylinder - 40MBF */
#define C67F_NBPC       (32*5 ) /* 512-byte blocks per cylinder - 67MBF */

d67strategy(io, func)
struct iob *io;
{
	return msmstrategy (io, func, D67_NBPC,0);
}

d256strategy(io, func)
struct iob *io;
{
	return msmstrategy (io, func, D256_NBPC,0);
}

c13rstrategy(io, func)
struct iob *io;
{
	return msmstrategy (io, func, C13R_NBPC,0);
}

c13fstrategy(io, func)
struct iob *io;
{
	return msmstrategy (io, func, C13F_NBPC,0x10);
}

c40fstrategy(io, func)
struct iob *io;
{
	return msmstrategy (io, func, C40F_NBPC,0x10);
}

c67fstrategy(io, func)
struct iob *io;
{
	return msmstrategy (io, func, C67F_NBPC,0x10);
}

static
msmstrategy(io, func, nbpc,headoffset)
register struct iob *io;
int     headoffset;
{
	register int drive, cntl, selch, stat;
	register int tn;        /* track */
	register int cn;        /* cylinder */
	register int sn;        /* sector */

	if ((drive = io->i_deva) == 0) drive = msmaddr[io->i_unit];
	if ((cntl = io->i_cntl) == 0) cntl = msmcntl;
	if ((selch = io->i_selch) == 0) selch = msmselch;
	curcntl = cntl;
	cn = io->i_bn / nbpc;
	{
		register off_t bn;        /* block number */
		bn = io->i_bn % nbpc;
		tn = bn / NBPT;
		sn = (bn % NBPT) << SECSHIFT;
	}
	msmidle();
	while (ss(drive) & ALTBSY) ;
	wh(drive, cn);
	msmidle();
	oc(drive, SETCYL | DISARM) ;
	msmidle();
	oc(drive, SEEK);
	msmidle();
	while ((stat=ss(drive)) & UNREADY) ;
	if (stat & (UNS|SINC|OFFL|ALTBSY)) {
		printf("MSM seek error: cyl=%d track=%d sect=%d er=%x ad=%x\n",
		    cn, tn, sn, stat, drive);
		return(-1);
	}
	oc(selch, STOP);
	wdh(selch, io->i_ma);
	wdh(selch, &io->i_ma[io->i_cc - 1]);
	wh(drive, tn | headoffset );
	oc(drive, SETHEAD);
	msmidle();
	wd(cntl, sn);
	wh(cntl, ((tn | headoffset) <<10) | cn);
	wh(drive, tn | headoffset );
	oc(drive, SETHEAD);
	msmidle();
	if (func == READ) {
		oc(cntl, CREAD);
		oc(selch, READ_GO);
	} else {
		oc(cntl, CWRITE);
		oc(selch, GO);
	}
	while (ss(selch) & SELCHBSY) ;
	oc(selch, STOP);
	msmidle();
	if ((stat=ss(cntl)) & (CNTL_UNRCV|CYL_OV)) {
		printf("MSM %s error: cyl=%d track=%d sect=%d er=%x ad=%x\n",
		    func == READ ? "read" : "write",
		    cn, tn, sn, stat, cntl);
		return(-1);
	}
	return(io->i_cc);
}
msmidle()
{
	while (! (ss(curcntl) & IDLE) )
		continue;
}
