/*
 * Cartridge disk
 */

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


#define DSKERR		0x63	/* wrt chk|ill addr|seek inc|nrdy */
#define ADDR_INTLK	0x10
#define WRT_PROT	0x80
#define NRSRW		0x08

#define SEEK		0x42

#define CNTLERR		0xf1	/* overrun|addr comp fail|def trk|data err */
#define CYL_OV		0x10
#define IDLE		0x02

#define READCMD		0x01
#define WRITECMD	0x02

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

char	dskaddr[8] = {
	0xc6, 0xc7, 0xd6, 0xd7, 0xe6, 0xe7, 0xf6, 0xf7
};
char    dskcntl   = 0xb6;
char    dskselch  = 0xf0;

dskstrategy(io, func)
register struct iob *io;
{
	register com;
	daddr_t bn;
	int dn, cn, sn;
	register selch, cntl, file;
	register stat;

	bn = io->i_bn;
	dn = io->i_unit;
	cn = bn/24;
	if ((sn = (bn<<1)%48) >= 24)
		sn += 32-24;
	if ((file = io->i_deva) == 0) file = dskaddr[dn];
	if ((cntl = io->i_cntl) == 0) cntl = dskcntl;
	if ((selch = io->i_selch) == 0) selch = dskselch;
	while (ss(selch) & SELCHBSY) ;
	while (! (ss(cntl) & IDLE) ) ;
	while (ss(file) & (ADDR_INTLK | NRSRW)) ;
	wh(file, cn);
	oc(file, SEEK);
	while (! (ss(cntl) & IDLE) ) ;
	while ((stat = ss(file)) & NRSRW) ;
	if (stat & (DSKERR)) {
		printf("disk error: cyl=%d, sector=%d, er=%x, ad=%x\n",
		    cn, sn, stat, file);
		return(-1);
	}
	oc(selch, STOP);
	wdh(selch, io->i_ma);
	wdh(selch, io->i_ma + io->i_cc - 1);
	wh(file, cn);
	wd(cntl, sn);

	if (func == READ) {
		oc(cntl, READCMD);
		oc(selch, READ_GO);
	} else {
		oc(cntl, WRITECMD);
		oc(selch, GO);
	}
	while (ss(selch) & SELCHBSY) ;
	while (! ((stat=ss(cntl)) & IDLE) ) ;
	if (stat & CNTLERR) {
		printf("disk error: cyl=%d, sector=%d, er=%x, ad=%x\n",
		    cn, sn, stat, cntl);
		return(-1);
	}
	return(io->i_cc);
}
