xref: /csrg-svn/sys/vax/stand/up.c (revision 25443)
123248Smckusick /*
223248Smckusick  * Copyright (c) 1982 Regents of the University of California.
323248Smckusick  * All rights reserved.  The Berkeley software License Agreement
423248Smckusick  * specifies the terms and conditions for redistribution.
523248Smckusick  *
6*25443Skarels  *	@(#)up.c	6.5 (Berkeley) 11/08/85
723248Smckusick  */
89974Ssam 
910023Ssam /*
1010023Ssam  * UNIBUS peripheral standalone driver
1110023Ssam  * with ECC correction and bad block forwarding.
1210023Ssam  * Also supports header operation and write
1310023Ssam  * check for data and/or header.
1410023Ssam  */
159974Ssam #include "../h/param.h"
169974Ssam #include "../h/inode.h"
179974Ssam #include "../h/fs.h"
189974Ssam #include "../h/dkbad.h"
199974Ssam #include "../h/vmmac.h"
209974Ssam 
219974Ssam #include "../vax/pte.h"
229974Ssam #include "../vaxuba/upreg.h"
239974Ssam #include "../vaxuba/ubareg.h"
249974Ssam 
2510023Ssam #include "saio.h"
269974Ssam #include "savax.h"
279974Ssam 
28*25443Skarels #define RETRIES		27
29*25443Skarels 
3010352Shelge #define MAXBADDESC	126	/* max number of bad sectors recorded */
3110352Shelge #define SECTSIZ		512	/* sector size in bytes */
3210352Shelge #define HDRSIZ		4	/* number of bytes in sector header */
3311365Ssam 
3410023Ssam u_short	ubastd[] = { 0776700 };
359974Ssam 
3611143Ssam extern	struct st upst[];
3710023Ssam 
3811365Ssam struct  dkbad upbad[MAXNUBA*8];		/* bad sector table */
3911365Ssam int 	sectsiz;			/* real sector size */
4011365Ssam 
41*25443Skarels struct	up_softc {
42*25443Skarels 	char	gottype;
43*25443Skarels 	char	type;
44*25443Skarels 	char	debug;
45*25443Skarels #	define	UPF_BSEDEBUG	01	/* debugging bad sector forwarding */
46*25443Skarels #	define	UPF_ECCDEBUG	02	/* debugging ecc correction */
47*25443Skarels 	int	retries;
48*25443Skarels 	int	ecclim;
49*25443Skarels } up_softc[MAXNUBA * 8];
50*25443Skarels 
519974Ssam u_char	up_offset[16] = {
529974Ssam 	UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
539974Ssam 	UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
549974Ssam 	UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
559974Ssam 	0, 0, 0, 0
569974Ssam };
579974Ssam 
589974Ssam upopen(io)
599974Ssam 	register struct iob *io;
609974Ssam {
6110352Shelge 	register unit = io->i_unit;
6210023Ssam 	register struct updevice *upaddr;
63*25443Skarels 	register struct up_softc *sc = &up_softc[unit];
6411118Ssam 	register struct st *st;
659974Ssam 
6611143Ssam 	if (io->i_boff < 0 || io->i_boff > 7)
6710023Ssam 		_stop("up bad unit");
6810352Shelge 	upaddr = (struct updevice *)ubamem(unit, ubastd[0]);
6915067Skarels 	upaddr->upcs2 = unit % 8;
7011085Ssam 	while ((upaddr->upcs1 & UP_DVA) == 0)
719974Ssam 		;
72*25443Skarels 	if (sc->gottype == 0) {
7310023Ssam 		register int i;
7410023Ssam 		struct iob tio;
7510023Ssam 
76*25443Skarels 		sc->retries = RETRIES;
77*25443Skarels 		sc->ecclim = 11;
78*25443Skarels 		sc->debug = 0;
79*25443Skarels 		sc->type = upmaptype(unit, upaddr);
80*25443Skarels 		if (sc->type < 0)
8110023Ssam 			_stop("unknown drive type");
82*25443Skarels 		st = &upst[sc->type];
8311143Ssam 		if (st->off[io->i_boff] == -1)
8411143Ssam 			_stop("up bad unit");
8510023Ssam 		/*
8611365Ssam 		 * Read in the bad sector table.
8710023Ssam 		 */
8810023Ssam 		tio = *io;
8910023Ssam 		tio.i_bn = st->nspc * st->ncyl - st->nsect;
909974Ssam 		tio.i_ma = (char *)&upbad[tio.i_unit];
9110638Shelge 		tio.i_cc = sizeof (struct dkbad);
9210023Ssam 		tio.i_flgs |= F_RDDATA;
9310023Ssam 		for (i = 0; i < 5; i++) {
9410638Shelge 			if (upstrategy(&tio, READ) == sizeof (struct dkbad))
9510023Ssam 				break;
969974Ssam 			tio.i_bn += 2;
979974Ssam 		}
989974Ssam 		if (i == 5) {
9910023Ssam 			printf("Unable to read bad sector table\n");
10010352Shelge 			for (i = 0; i < MAXBADDESC; i++) {
10110352Shelge 				upbad[unit].bt_bad[i].bt_cyl = -1;
10210352Shelge 				upbad[unit].bt_bad[i].bt_trksec = -1;
1039974Ssam 			}
1049974Ssam 		}
105*25443Skarels 		sc->gottype = 1;
1069974Ssam 	}
107*25443Skarels 	st = &upst[sc->type];
1089974Ssam 	io->i_boff = st->off[io->i_boff] * st->nspc;
10910023Ssam 	io->i_flgs &= ~F_TYPEMASK;
1109974Ssam }
1119974Ssam 
1129974Ssam upstrategy(io, func)
1139974Ssam 	register struct iob *io;
1149974Ssam {
11511317Ssam 	int cn, tn, sn, o;
11610352Shelge 	register unit = io->i_unit;
1179974Ssam 	daddr_t bn;
1189974Ssam 	int recal, info, waitdry;
1199974Ssam 	register struct updevice *upaddr =
12010352Shelge 	    (struct updevice *)ubamem(unit, ubastd[0]);
121*25443Skarels 	struct up_softc *sc = &up_softc[unit];
122*25443Skarels 	register struct st *st = &upst[sc->type];
123*25443Skarels 	int doprintf = 0, error, rv = io->i_cc;
1249974Ssam 
12510352Shelge 	sectsiz = SECTSIZ;
12611085Ssam 	if (io->i_flgs & (F_HDR|F_HCHECK))
12710352Shelge 		sectsiz += HDRSIZ;
12811365Ssam 	upaddr->upcs2 = unit % 8;
1299974Ssam 	if ((upaddr->upds & UPDS_VV) == 0) {
1309974Ssam 		upaddr->upcs1 = UP_DCLR|UP_GO;
1319974Ssam 		upaddr->upcs1 = UP_PRESET|UP_GO;
1329974Ssam 		upaddr->upof = UPOF_FMT22;
1339974Ssam 	}
134*25443Skarels 	if ((upaddr->upds & UPDS_DREADY) == 0) {
135*25443Skarels 		printf("up%d not ready", unit);
136*25443Skarels 		return (-1);
137*25443Skarels 	}
1389974Ssam 	info = ubasetup(io, 1);
1399974Ssam 	upaddr->upwc = -io->i_cc / sizeof (short);
14011085Ssam 	recal = 0;
14111085Ssam 	io->i_errcnt = 0;
14211085Ssam 
14310638Shelge restart:
144*25443Skarels 	error = 0;
14511317Ssam 	o = io->i_cc + (upaddr->upwc * sizeof (short));
14611317Ssam 	upaddr->upba = info + o;
14711317Ssam 	bn = io->i_bn + o / sectsiz;
148*25443Skarels 	if (doprintf && sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG))
14911386Ssam 		printf("wc=%d o=%d i_bn=%d bn=%d\n",
15011365Ssam 			upaddr->upwc, o, io->i_bn, bn);
15110023Ssam 	while((upaddr->upds & UPDS_DRY) == 0)
15210023Ssam 		;
15310352Shelge 	if (upstart(io, bn) != 0) {
154*25443Skarels 		rv = -1;
155*25443Skarels 		goto done;
15610352Shelge 	}
1579974Ssam 	do {
1589974Ssam 		DELAY(25);
1599974Ssam 	} while ((upaddr->upcs1 & UP_RDY) == 0);
16011085Ssam 	/*
16111085Ssam 	 * If transfer has completed, free UNIBUS
16211085Ssam 	 * resources and return transfer size.
16311085Ssam 	 */
16415067Skarels 	if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0)
16515067Skarels 		goto done;
166*25443Skarels 	bn = io->i_bn +
167*25443Skarels 		(io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz;
168*25443Skarels 	if (upaddr->uper1 & (UPER1_DCK|UPER1_ECH))
169*25443Skarels 		bn--;
170*25443Skarels 	cn = bn/st->nspc;
171*25443Skarels 	sn = bn%st->nspc;
172*25443Skarels 	tn = sn/st->nsect;
173*25443Skarels 	sn = sn%st->nsect;
174*25443Skarels 	if (sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) {
175*25443Skarels 		printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
176*25443Skarels 		   bn, cn, tn, sn);
17711386Ssam 		printf("cs2=%b er1=%b er2=%b wc=%d\n",
17811365Ssam 	    	  upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
17911386Ssam 		  UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc);
18011365Ssam 	}
1819974Ssam 	waitdry = 0;
18211386Ssam 	while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz)
18310023Ssam 		DELAY(5);
18411085Ssam 	if (upaddr->uper1&UPER1_WLE) {
18511085Ssam 		/*
18611085Ssam 		 * Give up on write locked devices immediately.
18711085Ssam 		 */
18811085Ssam 		printf("up%d: write locked\n", unit);
189*25443Skarels 		rv = -1;
190*25443Skarels 		goto done;
19111085Ssam 	}
192*25443Skarels 	if (upaddr->uper2 & UPER2_BSE) {
193*25443Skarels 		if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0)
194*25443Skarels 			goto success;
195*25443Skarels 		error = EBSE;
196*25443Skarels 		goto hard;
197*25443Skarels 	}
198*25443Skarels 	/*
199*25443Skarels 	 * ECC error. If a soft error, correct it;
200*25443Skarels 	 * if correction is too large, no more retries.
201*25443Skarels 	 */
202*25443Skarels 	if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH|UPER1_HCRC)) == UPER1_DCK) {
203*25443Skarels 		if (upecc(io, ECC) == 0)
204*25443Skarels 			goto success;
205*25443Skarels 		error = EECC;
206*25443Skarels 		goto hard;
207*25443Skarels 	}
208*25443Skarels 	/*
209*25443Skarels 	 * If the error is a header CRC,
210*25443Skarels 	 * check if a replacement sector exists in
211*25443Skarels 	 * the bad sector table.
212*25443Skarels 	 */
213*25443Skarels 	if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 &&
214*25443Skarels 	     upecc(io, BSE) == 0)
215*25443Skarels 		goto success;
216*25443Skarels 	if (++io->i_errcnt > sc->retries) {
2179974Ssam 		/*
2189974Ssam 		 * After 28 retries (16 without offset, and
2199974Ssam 		 * 12 with offset positioning) give up.
2209974Ssam 		 */
22110352Shelge hard:
222*25443Skarels 		if (error == 0) {
223*25443Skarels 			error = EHER;
224*25443Skarels 			if (upaddr->upcs2 & UPCS2_WCE)
225*25443Skarels 				error = EWCK;
226*25443Skarels 		}
227*25443Skarels 		printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
228*25443Skarels 		   bn, cn, tn, sn);
229*25443Skarels 		printf("cs2=%b er1=%b er2=%b\n",
23011085Ssam 		   upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
23111085Ssam 		   UPER1_BITS, upaddr->uper2, UPER2_BITS);
2329974Ssam 		upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
23310352Shelge 		io->i_errblk = bn;
23415067Skarels 		if (io->i_errcnt >= 16) {
23515067Skarels 			upaddr->upof = UPOF_FMT22;
23615067Skarels 			upaddr->upcs1 = UP_RTC|UP_GO;
23715067Skarels 			while ((upaddr->upds&UPDS_DRY) == 0)
23815067Skarels 				DELAY(25);
23915067Skarels 		}
240*25443Skarels 		rv = -1;
241*25443Skarels 		goto done;
24211085Ssam 	}
24311085Ssam 	/*
2449974Ssam 	 * Clear drive error and, every eight attempts,
2459974Ssam 	 * (starting with the fourth)
2469974Ssam 	 * recalibrate to clear the slate.
2479974Ssam 	 */
2489974Ssam 	upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
24910638Shelge 	if ((io->i_errcnt&07) == 4 ) {
2509974Ssam 		upaddr->upcs1 = UP_RECAL|UP_GO;
25115067Skarels 		while ((upaddr->upds&UPDS_DRY) == 0)
25215067Skarels 			DELAY(25);
2539974Ssam 		upaddr->updc = cn;
2549974Ssam 		upaddr->upcs1 = UP_SEEK|UP_GO;
25515067Skarels 		while ((upaddr->upds&UPDS_DRY) == 0)
25615067Skarels 			DELAY(25);
25715067Skarels 	}
25815067Skarels 	if (io->i_errcnt >= 16 && (func & READ)) {
2599974Ssam 		upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22;
2609974Ssam 		upaddr->upcs1 = UP_OFFSET|UP_GO;
26110638Shelge 		while ((upaddr->upds&UPDS_DRY) == 0)
26210638Shelge 			DELAY(25);
2639974Ssam 	}
26410638Shelge 	goto restart;
26511085Ssam 
2669974Ssam success:
26711386Ssam #define	rounddown(x, y)	(((x) / (y)) * (y))
26811386Ssam 	upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short));
26911386Ssam 	if (upaddr->upwc) {
27011317Ssam 		doprintf++;
27110638Shelge 		goto restart;
27211317Ssam 	}
27315067Skarels done:
2749974Ssam 	/*
27511365Ssam 	 * Release UNIBUS
2769974Ssam 	 */
2779974Ssam 	ubafree(io, info);
27815067Skarels 	/*
27915067Skarels 	 * If we were offset positioning,
28015067Skarels 	 * return to centerline.
28115067Skarels 	 */
28215067Skarels 	if (io->i_errcnt >= 16) {
28315067Skarels 		upaddr->upof = UPOF_FMT22;
28415067Skarels 		upaddr->upcs1 = UP_RTC|UP_GO;
28515067Skarels 		while ((upaddr->upds&UPDS_DRY) == 0)
28615067Skarels 			DELAY(25);
28715067Skarels 	}
288*25443Skarels 	return (rv);
2899974Ssam }
2909974Ssam 
2919974Ssam /*
29211143Ssam  * Correct an ECC error, and restart the
29311143Ssam  * i/o to complete the transfer (if necessary).
29411143Ssam  * This is quite complicated because the transfer
29511143Ssam  * may be going to an odd memory address base and/or
2969974Ssam  * across a page boundary.
2979974Ssam  */
29810023Ssam upecc(io, flag)
2999974Ssam 	register struct iob *io;
3009974Ssam 	int flag;
3019974Ssam {
30211365Ssam 	register i, unit = io->i_unit;
303*25443Skarels 	register struct up_softc *sc = &up_softc[unit];
3049974Ssam 	register struct updevice *up =
30511365Ssam 		(struct updevice *)ubamem(unit, ubastd[0]);
30610352Shelge 	register struct st *st;
3079974Ssam 	caddr_t addr;
30810410Shelge 	int bn, twc, npf, mask, cn, tn, sn;
30910352Shelge 	daddr_t bbn;
3109974Ssam 
3119974Ssam 	/*
31211143Ssam 	 * Npf is the number of sectors transferred
31311143Ssam 	 * before the sector containing the ECC error;
31411143Ssam 	 * bn is the current block number.
3159974Ssam 	 */
31610352Shelge 	twc = up->upwc;
31711143Ssam 	npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz;
31815067Skarels 	if (flag == ECC)
31915067Skarels 		npf--;
320*25443Skarels 	if (sc->debug & UPF_ECCDEBUG)
32111386Ssam 		printf("npf=%d mask=0x%x ec1=%d wc=%d\n",
32211386Ssam 			npf, up->upec2, up->upec1, twc);
32311317Ssam 	bn = io->i_bn + npf;
324*25443Skarels 	st = &upst[sc->type];
32510410Shelge 	cn = bn/st->nspc;
32610410Shelge 	sn = bn%st->nspc;
32710410Shelge 	tn = sn/st->nsect;
32810410Shelge 	sn = sn%st->nsect;
32911143Ssam 
3309974Ssam 	/*
33111143Ssam 	 * ECC correction.
3329974Ssam 	 */
3339974Ssam 	if (flag == ECC) {
334*25443Skarels 		int bit, o;
33511085Ssam 
3369974Ssam 		mask = up->upec2;
33711365Ssam 		printf("up%d: soft ecc sn%d\n", unit, bn);
338*25443Skarels 		for (i = mask, bit = 0; i; i >>= 1)
339*25443Skarels 			if (i & 1)
340*25443Skarels 				bit++;
341*25443Skarels 		if (bit > sc->ecclim) {
342*25443Skarels 			printf("%d-bit error\n", bit);
343*25443Skarels 			return (1);
344*25443Skarels 		}
3459974Ssam 		/*
34611317Ssam 		 * Compute the byte and bit position of
34711317Ssam 		 * the error.  o is the byte offset in
34811317Ssam 		 * the transfer at which the correction
34911317Ssam 		 * applied.
3509974Ssam 		 */
3519974Ssam 		i = up->upec1 - 1;		/* -1 makes 0 origin */
35211386Ssam 		bit = i & 07;
35311386Ssam 		o = (i & ~07) >> 3;
3549974Ssam 		up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
3559974Ssam 		/*
35611143Ssam 		 * Correct while possible bits remain of mask.
35711143Ssam 		 * Since mask contains 11 bits, we continue while
35811143Ssam 		 * the bit offset is > -11.  Also watch out for
35911143Ssam 		 * end of this block and the end of the transfer.
3609974Ssam 		 */
36111317Ssam 		while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) {
3629974Ssam 			/*
36311143Ssam 			 * addr =
36411317Ssam 			 *  (base address of transfer) +
36511143Ssam 			 *  (# sectors transferred before the error) *
36611143Ssam 			 *    (sector size) +
36711317Ssam 			 *  (byte offset to incorrect data)
3689974Ssam 			 */
36911317Ssam 			addr = io->i_ma + (npf * sectsiz) + o;
37011317Ssam 			/*
37111317Ssam 			 * No data transfer occurs with a write check,
37211317Ssam 			 * so don't correct the resident copy of data.
37311317Ssam 			 */
37411365Ssam 			if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
375*25443Skarels 				if (sc->debug & UPF_ECCDEBUG)
37611365Ssam 					printf("addr=0x%x old=0x%x ", addr,
37711365Ssam 						(*addr&0xff));
37810352Shelge 				*addr ^= (mask << bit);
379*25443Skarels 				if (sc->debug & UPF_ECCDEBUG)
38011365Ssam 					printf("new=0x%x\n", (*addr&0xff));
38111365Ssam 			}
38211317Ssam 			o++, bit -= 8;
3839974Ssam 		}
38411085Ssam 		return (0);
38511085Ssam 	}
38611143Ssam 
38711143Ssam 	/*
38811143Ssam 	 * Bad sector forwarding.
38911143Ssam 	 */
39011085Ssam 	if (flag == BSE) {
3919974Ssam 		/*
39211143Ssam 		 * If not in bad sector table,
39311143Ssam 		 * indicate a hard error to caller.
3949974Ssam 		 */
39510352Shelge 		up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
39611365Ssam 		if ((bbn = isbad(&upbad[unit], cn, tn, sn)) < 0)
39711085Ssam 			return (1);
39811386Ssam 		bbn = (st->ncyl * st->nspc) - st->nsect - 1 - bbn;
39910352Shelge 		twc = up->upwc + sectsiz;
40011085Ssam 		up->upwc = - (sectsiz / sizeof (short));
401*25443Skarels 		if (sc->debug & UPF_BSEDEBUG)
40211365Ssam 			printf("revector sn %d to %d\n", sn, bbn);
4039974Ssam 		/*
40411143Ssam 	 	 * Clear the drive & read the replacement
40511143Ssam 		 * sector.  If this is in the middle of a
40611143Ssam 		 * transfer, then set up the controller
40711143Ssam 		 * registers in a normal fashion.
40811143Ssam 	 	 * The UNIBUS address need not be changed.
40911143Ssam 	 	 */
41011386Ssam 		while ((up->upcs1 & UP_RDY) == 0)
4119974Ssam 			;
41211386Ssam 		if (upstart(io, bbn))
41310352Shelge 			return (1);		/* error */
41410352Shelge 		io->i_errcnt = 0;		/* success */
4159974Ssam 		do {
4169974Ssam 			DELAY(25);
41711386Ssam 		} while ((up->upcs1 & UP_RDY) == 0) ;
41811386Ssam 		if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) {
41911386Ssam 			up->upwc = twc - sectsiz;
42010352Shelge 			return (1);
4219974Ssam 		}
4229974Ssam 	}
42310638Shelge 	if (twc)
4249974Ssam 		up->upwc = twc;
42510352Shelge 	return (0);
4269974Ssam }
4279974Ssam 
4289974Ssam upstart(io, bn)
42910023Ssam 	register struct iob *io;
43010023Ssam 	daddr_t bn;
4319974Ssam {
4329974Ssam 	register struct updevice *upaddr =
43310023Ssam 		(struct updevice *)ubamem(io->i_unit, ubastd[0]);
434*25443Skarels 	register struct up_softc *sc = &up_softc[io->i_unit];
435*25443Skarels 	register struct st *st = &upst[sc->type];
4369974Ssam 	int sn, tn;
4379974Ssam 
4389974Ssam 	sn = bn%st->nspc;
4399974Ssam 	tn = sn/st->nsect;
4409974Ssam 	sn %= st->nsect;
4419974Ssam 	upaddr->updc = bn/st->nspc;
4429974Ssam 	upaddr->upda = (tn << 8) + sn;
44310352Shelge 	switch (io->i_flgs & F_TYPEMASK) {
44410023Ssam 
44510023Ssam 	case F_RDDATA:
44610023Ssam 		upaddr->upcs1 = UP_RCOM|UP_GO;
4479974Ssam 		break;
44810023Ssam 
44910023Ssam 	case F_WRDATA:
45010023Ssam 		upaddr->upcs1 = UP_WCOM|UP_GO;
4519974Ssam 		break;
45210023Ssam 
45310023Ssam 	case F_HDR|F_RDDATA:
45410023Ssam 		upaddr->upcs1 = UP_RHDR|UP_GO;
45510023Ssam 		break;
45610023Ssam 
45710023Ssam 	case F_HDR|F_WRDATA:
45810023Ssam 		upaddr->upcs1 = UP_WHDR|UP_GO;
45910023Ssam 		break;
46010023Ssam 
46110023Ssam 	case F_CHECK|F_WRDATA:
46210023Ssam 	case F_CHECK|F_RDDATA:
4639974Ssam 		upaddr->upcs1 = UP_WCDATA|UP_GO;
4649974Ssam 		break;
46510023Ssam 
46610023Ssam 	case F_HCHECK|F_WRDATA:
46710023Ssam 	case F_HCHECK|F_RDDATA:
4689974Ssam 		upaddr->upcs1 = UP_WCHDR|UP_GO;
4699974Ssam 		break;
47010023Ssam 
4719974Ssam 	default:
47210023Ssam 		io->i_error = ECMD;
47310023Ssam 		io->i_flgs &= ~F_TYPEMASK;
47410023Ssam 		return (1);
4759974Ssam 	}
47610023Ssam 	return (0);
4779974Ssam }
4789974Ssam 
47910023Ssam /*ARGSUSED*/
48010023Ssam upioctl(io, cmd, arg)
48110023Ssam 	struct iob *io;
48210023Ssam 	int cmd;
48310023Ssam 	caddr_t arg;
48410023Ssam {
485*25443Skarels 	int unit = io->i_unit;
486*25443Skarels 	register struct up_softc *sc = &up_softc[unit];
487*25443Skarels 	struct st *st = &upst[sc->type];
48810352Shelge 
48910352Shelge 	switch(cmd) {
49010352Shelge 
49111365Ssam 	case SAIODEBUG:
492*25443Skarels 		sc->debug = (int)arg;
493*25443Skarels 		break;
49411365Ssam 
49510352Shelge 	case SAIODEVDATA:
496*25443Skarels 		*(struct st *)arg = *st;
497*25443Skarels 		break;
498*25443Skarels 
499*25443Skarels 	case SAIOGBADINFO:
500*25443Skarels 		*(struct dkbad *)arg = upbad[unit];
501*25443Skarels 		break;
502*25443Skarels 
503*25443Skarels 	case SAIOECCLIM:
504*25443Skarels 		sc->ecclim = (int)arg;
505*25443Skarels 		break;
506*25443Skarels 
507*25443Skarels 	case SAIORETRIES:
508*25443Skarels 		sc->retries = (int)arg;
509*25443Skarels 		break;
510*25443Skarels 
511*25443Skarels 	default:
512*25443Skarels 		return (ECMD);
51310352Shelge 	}
514*25443Skarels 	return (0);
51510023Ssam }
516