4.3BSD-Reno/src/sys/tahoestand/vdformat/io.c

Compare this file to the similar file:
Show the results in this format:

#ifndef lint
static char sccsid[] = "@(#)io.c	1.7 (Berkeley/CCI) 6/7/88";
#endif

#include	"vdfmt.h"
#include	"cmd.h"


/*
**
*/

static cmd_text_element	nul_table[] = {
	{ 0,	"",	"" }
};

int wait_for_char;
int vdtimeout;
char	*clean_up = "Cleaning up...  Please wait.\n";


/*
**
*/

poll(wait)
int	wait;
{
	register struct vddevice *addr = C_INFO->addr;
	int	tokens[10];

	if (kill_processes == false)
		wait_for_char = 0;
	vdtimeout = wait*1000;
	for (;;) {
		uncache(&(dcb.operrsta));
		if (dcb.operrsta & (DCBS_DONE | DCBS_ABORT))
			break;
		if (kill_processes == false && input()) {
			get_text_cmd(nul_table, tokens);
			if (kill_processes == true) {
				indent();
				print(clean_up);
				exdent(1);
			}
		}
		if (vdtimeout-- <= 0) {
			if(C_INFO->type == VDTYPE_VDDC)
				printf("\nVDDC");
			else
				printf("\nSMD-E");
			printf(": Controller timeout");
abort:
			VDABORT(addr, C_INFO->type);
			DELAY(30000);
			break;
		}
		DELAY(1000);
	}
	if ((vdtimeout > 0)) {
		if (C_INFO->type == VDTYPE_SMDE) {
			for (;;) {
				uncache(&(addr->vdcsr));
				if ((addr->vdcsr & CS_GO) == 0)
					break;
				DELAY(1000);
				if (vdtimeout-- <= 0) {
					printf("\nSMD-E timed out clearing GO");
					goto abort;
				}
			}
			DELAY(300);
		}
		DELAY(500);
	}
	DELAY(200);
	if((dcb.opcode == VDOP_RD) || (dcb.opcode == VDOP_RDRAW))
		mtpr(PADC, 0);
	uncache(&(dcb.operrsta));
	uncache(&(dcb.err_code));
	wait_for_char = 1;
}


/*
**	Access_with_no_trailer is used to perform controller functions which
** require no data movement.
*/

access_with_no_trailer(function, wait_time)
int	function, wait_time;
{
	dcb.opcode = function;		/* command */
	dcb.intflg = DCBINT_NONE;
	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
	dcb.operrsta  = 0;
	dcb.devselect = (function == VDOP_START) ? 0 :
	    ((char)cur.drive | lab->d_devflags);
	dcb.trailcnt = (char)0;
	mdcb.mdcb_head = &dcb;
	mdcb.mdcb_status = 0;
	VDGO(C_INFO->addr, (u_long)&mdcb, C_INFO->type);	
	poll(wait_time);
	if(vdtimeout <= 0) {
		printf(" during startup operation.\n");
		_longjmp(abort_environ, 1);
	}
	return dcb.operrsta;
}

vread(sn, buf, seccnt)
int sn, seccnt;
char *buf;
{
	int ret;

	ret = vrdwr(sn, buf, seccnt, VDOP_RD);
	if (ret == 0)
		vd_error("read");
	return (ret);
}

vwrite(sn, buf, seccnt)
int sn, seccnt;
char *buf;
{
	int ret;

	ret = vrdwr(sn, buf, seccnt, VDOP_WD);
	if (ret == 0)
		vd_error("write");
	return (ret);
};

vrdwr(sn, buf, seccnt, op)
int sn, seccnt, op;
char *buf;
{
	dskadr	dskaddr;

	dskaddr.cylinder = sn / lab->d_secpercyl;
	sn %= lab->d_secpercyl;
	dskaddr.track = sn / lab->d_nsectors;
	dskaddr.sector = sn % lab->d_nsectors;
	if (access_dsk(buf, &dskaddr, op, seccnt, 1) & DCBS_HARD)
		return (0);
	return (seccnt);
}

/*
**	access_dsk is used by other routines to do reads and writes to the disk.
** The status of the read / write is returned to the caller for processing.
*/

access_dsk(buf, dskaddr, func, count, wait)
char	*buf;
dskadr	*dskaddr;
int	func, count, wait;
{
	cur.daddr.cylinder = dskaddr->cylinder;
	cur.daddr.track = dskaddr->track;
	wait_for_char = 0;
	dcb.opcode = func;		/* format sector command */
	dcb.intflg = DCBINT_NONE;
	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
	dcb.operrsta  = 0;
	dcb.devselect = (char)cur.drive | lab->d_devflags;
	if(func == VDOP_SEEK) {
		dcb.trailcnt = (char)(sizeof(struct trseek) / sizeof(long));
		dcb.trail.sktrail.skaddr.cylinder = dskaddr->cylinder;
		dcb.trail.sktrail.skaddr.track = dskaddr->track;
		dcb.trail.sktrail.skaddr.sector = dskaddr->sector;
	} else {
		dcb.trailcnt = (char)(sizeof(struct trrw) / sizeof(long));
		dcb.trail.rwtrail.memadr = (u_long)buf; 
		dcb.trail.rwtrail.wcount=count*(lab->d_secsize/sizeof(short));
		dcb.trail.rwtrail.disk.cylinder = dskaddr->cylinder;
		dcb.trail.rwtrail.disk.track = dskaddr->track;
		dcb.trail.rwtrail.disk.sector = dskaddr->sector;
	}
	mdcb.mdcb_head = &dcb;
	mdcb.mdcb_status = 0;
	VDGO(C_INFO->addr, (u_long)&mdcb, C_INFO->type);
	if(wait) {
		poll(10);
		if(vdtimeout <= 0) {
			printf(" in access_dsk.\n");
			_longjmp(abort_environ, 1);
		}
	}
	wait_for_char = 1;
	return dcb.operrsta;
}


/*
**	Spin_up_drive starts the drives on a controller and waits around for
** the drive to spin up if it is not already spinning.
*/

spin_up_drive()
{
	register struct vddevice *addr = C_INFO->addr;

	VDRESET(addr, C_INFO->type);
	if(C_INFO->type == VDTYPE_SMDE) {
		addr->vdcsr =  0;
		addr->vdtcf_mdcb =  AM_ENPDA;
		addr->vdtcf_dcb =  AM_ENPDA;
		addr->vdtcf_trail =  AM_ENPDA;
		addr->vdtcf_data =  AM_ENPDA;
		addr->vdccf = CCF_SEN | 0x8 | CCF_STS |
		    XMD_32BIT | BSZ_16WRD | CCF_ERR |
		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE;
	}
	access_with_no_trailer(VDOP_INIT, 10);
	access_with_no_trailer(VDOP_DIAG, 20);
	configure_drive(0);
}

/*
**	Configure_drive tells the controller what kind of drive is attached
** on a particular line.
*/

configure_drive(pass)
int	pass;
{
	register struct vddevice *addr = C_INFO->addr;
	register i;

top:
	dcb.opcode = VDOP_CONFIG;		/* command */
	dcb.intflg = DCBINT_NONE;
	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
	dcb.operrsta = 0;
	dcb.devselect = cur.drive | lab->d_devflags;
	dcb.trail.rstrail.ncyl = lab->d_ncylinders;
	dcb.trail.rstrail.nsurfaces = lab->d_ntracks;
	if(C_INFO->type == VDTYPE_VDDC)
		dcb.trailcnt = (char)2;
	else {
		dcb.trailcnt = sizeof (struct treset)/sizeof (long);
		dcb.trail.rstrail.nsectors = lab->d_nsectors;
		dcb.trail.rstrail.slip_sec = lab->d_sparespertrack;
		dcb.trail.rstrail.recovery = VDRF_NONE;
		addr->vdcylskew = lab->d_cylskew;
		addr->vdtrackskew = lab->d_trackskew;
		addr->vdsecsize = lab->d_secsize/sizeof(short);
	}
	mdcb.mdcb_head = &dcb;
	mdcb.mdcb_status = 0;
	VDGO(addr, (u_long)&mdcb, C_INFO->type);
	poll(5);
	if(vdtimeout <= 0) {
		printf(" during drive configuration.\n");
		goto bad;
	}
	if(dcb.operrsta & VDERR_HARD) {
		if (C_INFO->type == VDTYPE_SMDE) {
			if (lab->d_devflags == 0) {
				lab->d_devflags = VD_ESDI;
				goto top;
			}
#ifdef notdef
printf("vdstatus %x\n", addr->vdstatus[cur.drive]);
			if ((addr->vdstatus[cur.drive] & STA_US) == 0) {
				printf("Drive not present\n\n");
				goto bad;
			}
#endif
		}
		if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) {
			printf("drive config error\n");
			goto bad;
		}
		if(pass) {
			printf("\nDrive failed to start!\n\n");
			goto bad;
		}
		printf("\ndrive not ready, attempting to spin up...");
		access_with_no_trailer(VDOP_START, 62);
		for (i = 0; i < 620; i++) {
			if (C_INFO->type == VDTYPE_SMDE &&
			    addr->vdstatus[cur.drive] & STA_UR)
				break;
			DELAY(100000);
		}
		printf(" retrying drive configuration\n");
		pass++;
		lab->d_devflags = 0;
		goto top;
	}
	D_INFO->alive = u_true;
	return;
bad:
	D_INFO->alive = u_false;
	_longjmp(abort_environ, -1);
}


/*
** 	data_ok checks an error status word for bit patterns
**  associated with error conditions from the VDDC controller.  If a hardware
**  error is present then the problem is reported on the console.
**  If a data error is present the a zero is returned.
**  If everything is OK then a 1 is returned.
*/

data_ok()
{
	register int	status = dcb.operrsta;

	if(status & HARD_ERROR){
		vd_error("data transfer");
		printf("  op = 0x%x\n", dcb.opcode);
		reset_controller();
		dcb.operrsta &= HEADER_ERROR;
	}
	return (int)(!(status & (DATA_ERROR | HEADER_ERROR)));
}

vd_error(s)
	char *s;
{
	register int	status = dcb.operrsta;

	print("%s error at sector %d (cyl %d trk %d sect %d),\n",
	    s, to_sector(cur.daddr), dcb.err_cyl & 0xfff, dcb.err_trk,
	    dcb.err_sec);
	print("  status=%b", dcb.operrsta, VDERRBITS);
	if (C_INFO->type == VDTYPE_SMDE)
		printf(", ecode=0x%x", dcb.err_code);
	printf(".\n");
}


/*
**
*/

reset_controller()
{
	printf("Resetting controller.  Please wait...\n");
	spin_up_drive();
	printf("Controller was reset successfully.\n");
}

/*
**
*/

static	int	indent_count;


/*
**
*/

indent()
{
	indent_count += 2;
}


/*
**
*/

exdent(count)
int	count;
{
	if(count == -1)
		indent_count = 0;
	else
		indent_count -= count * 2;
	if(indent_count < 0)
			indent_count = 0;
}


/*
**
*/
/*VARARGS1*/
print(par0, par1, par2, par3, par4, par5, par6)
char	*par0, *par1, *par2, *par3, *par4, *par5, *par6;
{
	register int	count = indent_count;

	while(count--)
		printf(" ");
	printf(par0, par1, par2, par3, par4, par5, par6);
	DELAY((strlen(par0) + 20) * 9000);
}