/* * Sunol Systems Disk and Streaming Tape Driver * * (C) 1984 UniSoft Corp. of Berkeley CA * * UniPlus Source Code. This program is proprietary * with Unisoft Corporation and is not to be reproduced * or used in any manner except as authorized in * writing by Unisoft. * * The Sunol disk is a Corvus work-alike, so it uses the routines * in cv.c for reading and writing.  This file contains the * routines only needed by the tape unit. */#include "sys/param.h"#include "sys/types.h"#include "sys/inode.h"#include "sys/ino.h"#include "saio.h"#include "sys/pport.h"#include "sys/d_profile.h"#include "sys/cv.h"#include "sys/sunol.h"char sunolbuf[PBSIZE];int tapevd;		/* tape virtual drive is one beyond disk virtual drives *//* * ssztape - find size of Sunol tape */ssztape(fp)register fp;{	register struct iob *ip = &iob[fp-3];	register punit = ip->i_unit;	register struct sdparam *sp;	register tblks;	if (sop(punit, 2, N_PARAM, TAPEVD) < 0) {		printf("sop failure getting drive parameters for tape\n");		return(-1);	}	if (cvr(punit, sunolbuf, sizeof(struct sdparam)) < 0) {		printf("cvr failure getting drive parameters for tape\n");		return(-1);	}	sp = (struct sdparam *)sunolbuf;	tblks = ((sp->nblk_msb<<16)&0xFF0000)		+ ((sp->nblk_nsb<<8)&0xFF00) + (sp->nblk_lsb&0xFF);	return(tblks);}/* * sszdisk - find number of blocks on Sunol disk from *	block offset specified in open to physical end */sszdisk(fp)int fp;{	register struct iob *ip = &iob[fp-3];	register punit = ip->i_unit;	register vd;	register currblks;	register dblks;	register struct sdparam *sp;	dblks = currblks = 0;	for (vd = 1; vd <= 8; vd++) {		if (sop(punit, 2, N_PARAM, vd) < 0)			break;		if (cvr(punit, sunolbuf, sizeof(struct sdparam)) < 0) {			printf("cvr failure getting drive parameters for vd %d\n", vd);			return(-1);		}		sp = (struct sdparam *)sunolbuf;		dblks += currblks;		currblks = ((sp->nblk_msb<<16)&0xFF0000)			+ ((sp->nblk_nsb<<8)&0xFF00) + (sp->nblk_lsb&0xFF);	}	if ((tapevd = vd-2) < 0)		return(-1);	return(dblks - ip->i_boff);}/* * stotape - copy nblks from sunol device starting at block dbn */stotape(dfp, dbn, nblks)int dfp;	/* disk file desc. */int dbn;	/* logical disk bn within disk device */int nblks;	/* blocks to copy - at most the number of blocks on a tape */{	register struct iob *ip = &iob[dfp-3];	register tstart;	/* starting sector on tape */	register dstart;	/* starting sector on disk */	register dpbn;		/* disk physical bn */	register count;	tstart = 0;	dpbn = ip->i_boff + dbn;	while (nblks > 0) {		dstart = dpbn & 0xFFFF;		count = 0x10000 - dstart;		if (nblks < count)	/* to end of disk v.d. or end of request */			count = nblks;		/*if (scopy(dfp, cvbtovd(dpbn), dstart, TAPEVD, tstart, count) < 0)*/		if (scopy(dfp, cvbtovd(dpbn), dstart, 2, tstart, count) < 0)			return(-1);		tstart += count;		dpbn += count;		nblks -= count;	}}/* * sfrtape - copy nblks to sunol device starting at block dbn */sfrtape(dfp, dbn, nblks)int dfp;	/* disk file desc. */int dbn;	/* logical disk bn within disk device */int nblks;	/* blocks to copy - at most the number of blocks on a tape */{	register struct iob *ip = &iob[dfp-3];	register tstart;	/* starting sector on tape */	register dstart;	/* starting sector on disk */	register dpbn;		/* disk physical bn */	register count;	tstart = 0;	dpbn = ip->i_boff + dbn;	while (nblks > 0) {		dstart = dpbn & 0xFFFF;		count = 0x10000 - dstart;		if (nblks < count)	/* to end of disk v.d. or end of request */			count = nblks;		if (scopy(dfp, TAPEVD, tstart, cvbtovd(dpbn), dstart, count) < 0)			return(-1);		tstart += count;		dpbn += count;		nblks -= count;	}}struct copyparam scopyparam;		/* parameter block for copy command */scopy(dfp, srcvd, srcstart, destvd, deststart, count)register dfp, count;{	int punit = iob[dfp-3].i_unit;	register struct device_d *addr = pro_da[punit];	register char *ira = &(addr->d_ira);	register struct copyparam *pp = &scopyparam;	register char *cp;	register i;	register char status;	int zero = 0;	i = pp->command = N_COPY;	i += (pp->srcvd = srcvd);	i += (pp->lsrcstart = srcstart & 0xFF);	i += (pp->msrcstart = srcstart >> 8 & 0xFF);	pp->fill1 = 0;	i += (pp->destvd = destvd);	i += (pp->ldeststart = deststart & 0xFF);	i += (pp->mdeststart = deststart >> 8 & 0xFF);	pp->fill2 = 0;	i += (pp->lcount = count & 0xFF);	i += (pp->mcount = count >> 8 & 0xFF);	i = ((i&0xFF) ^ 0xFF) + 1;	pp->chksum = i;#ifdef notdefcp = (char *)pp;for (i = sizeof(struct copyparam); i > 0; i--)printf("0x%x ", (*cp++)&0xFF);printf("\n");#endif notdef	addr->d_ddra = 0xff;	/* port A to output */	addr->d_irb &= ~0x08;	/* bidirectional driver to output */	cp = (char *)pp;	for (i = sizeof(struct copyparam); i > 0; i--) {		while (((status = addr->d_irb) & ST_BUSY) == 0);		if ((status & ST_HTOC) == 0)			break;		*ira = *cp++;	}	for (;;) {		if (cvwait(addr) < 0) {			printf("leaving scopy before fill, %d bytes left\n", i);			return(-1);		}		if ((addr->d_irb & ST_HTOC) == 0)			break;		*ira = zero;	}	if (i > 0) {		printf("scopy: %d bytes short\n", i);		return(-1);	}	addr->d_ddra = 0x00;	/* data direction port A bits to input */	addr->d_irb |= 0x08;	/* bidirectional driver to input */	for (i=1000; i>0; i--);	/* pause so controller goes busy */	while (((status = addr->d_irb) & ST_BUSY) == 0);	/* cvwait without timeout */	if (status & ST_HTOC) {	/* controller expects something */		printf("scopy: no status available after command done\n");		return(-1);	}	if ((status = *ira) == 0) {printf("scopy: good status after copy\n");		return(0);	}printf("scopy: bad status 0x%x (0x%x)\n", status&0xFF, status&0x1F);	/* non-zero status is followed by 10 bytes */	if (cvr(punit, &(pp->srcvd), (sizeof(struct copyparam)-2)) < 0) {		printf("can't read status block after copy\n");		{		/* sunolbuf still has parameters from call to ssztape */		register struct sdparam *sp = (struct sdparam *)sunolbuf;		printf("%s: revision 0x%x, ROM version 0x%x\n",			sp->fwmsg, sp->revision, sp->romv);		}		return(-1);	}	/* for backups (destvd 9), up to 14 blocks may be missed by		the copy command and must be handled in start/stop mode */	count = pp->lcount + (pp->mcount<<8);	srcstart = pp->lsrcstart + (pp->msrcstart<<8) + cvvdtob(srcvd);	deststart = pp->ldeststart + (pp->mdeststart<<8) + cvvdtob(destvd);printf("scopy: %d blocks, src 0x%x, dest 0x%x\n", count, srcstart, deststart);	while (count > 0) {		lseek(dfp, (off_t)(srcstart*PBSIZE), 0);		if ((read(dfp,sunolbuf,PBSIZE)) != PBSIZE) {			printf("read error bn=%d\n", srcstart);			return(-1);		}		lseek(dfp, (off_t)(deststart*PBSIZE), 0);		if (write(dfp,sunolbuf,PBSIZE) != PBSIZE) {			printf("write error bn=%d\n", deststart);			return(-1);		}		count--;		srcstart++;		deststart++;	}	return(0);}/* * sop - issue command to sunol *//* VARARGS3 */sop(unit, na, a){	register int *ap;	register struct device_d *addr = pro_da[unit];	addr->d_ddra = 0xff;	/* port A to output */	addr->d_irb &= ~0x08;	/* bidirectional driver to output */	ap = &a;	for (; na > 0; na--, ap++) {		if (cvwait(addr) < 0)			return(-1);		addr->d_ira = *ap;	}	return(srstat(addr));		/* read status */}#ifdef notdef	if (sop512(punit, 2, N_DIAGN, 1) < 0) { /* ??? may not be needed */		printf("sop512 failure setting diag mode\n");		return(-1);	}/* * sop512 - issue command to sunol followed by 512 bytes of filler *//* VARARGS3 */sop512(unit, na, a){	register int *ap;	register struct device_d *addr = pro_da[unit];	register zero = 0;	register i;	addr->d_ddra = 0xff;	/* port A to output */	addr->d_irb &= ~0x08;	/* bidirectional driver to output */	ap = &a;	for (; na > 0; na--, ap++) {		if (cvwait(addr) < 0) {			printf(" timeout in sop512 ");			return(-1);		}		addr->d_ira = *ap;	}	for (i = 0; i < 512; i++) {		if (cvwait(addr) < 0) {			printf(" timeout in sop512 ");			return(-1);		}		addr->d_ira = zero;	}	return(srstat(addr));		/* read status */}#endif notdefsrstat(addr)register struct device_d *addr;{	register char status;	addr->d_ddra = 0x00;	/* data direction port A bits to input */	addr->d_irb |= 0x08;	/* bidirectional driver to input */	if (cvwait(addr) < 0)		return(-1);/*	cvqwait(addr);		/* quick wait (macro without timeout) */	if (status = addr->d_ira) {	/*printf("bad status 0x%x (0x%x)\n", status&0xFF, status&0x1F);*/		return(-1);	}	return 0;}