xref: /csrg-svn/sys/vax/stand/up.c (revision 33533)
123248Smckusick /*
232196Skarels  * 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*33533Sbostic  *	@(#)up.c	7.4 (Berkeley) 02/22/88
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  */
1532196Skarels #include "param.h"
1632196Skarels #include "inode.h"
1732196Skarels #include "fs.h"
1832196Skarels #include "dkbad.h"
1932196Skarels #include "vmmac.h"
209974Ssam 
2133408Skarels #include "../vax/pte.h"
229974Ssam 
2333408Skarels #include "../vaxuba/upreg.h"
2433408Skarels #include "../vaxuba/ubareg.h"
2533408Skarels 
2610023Ssam #include "saio.h"
279974Ssam #include "savax.h"
289974Ssam 
2925443Skarels #define RETRIES		27
3025443Skarels 
3110352Shelge #define MAXBADDESC	126	/* max number of bad sectors recorded */
3210352Shelge #define SECTSIZ		512	/* sector size in bytes */
3310352Shelge #define HDRSIZ		4	/* number of bytes in sector header */
3411365Ssam 
35*33533Sbostic #define	MAXPART		8
36*33533Sbostic #define	MAXCTLR		1	/* all addresses must be specified */
37*33533Sbostic u_short	ubastd[MAXCTLR] = { 0776700 };
389974Ssam 
3911143Ssam extern	struct st upst[];
4010023Ssam 
4132196Skarels #ifndef SMALL
42*33533Sbostic struct  dkbad upbad[MAXNUBA][MAXCTLR][8];	/* bad sector table */
4332196Skarels #endif
4411365Ssam int 	sectsiz;			/* real sector size */
4511365Ssam 
4625443Skarels struct	up_softc {
4725443Skarels 	char	gottype;
4825443Skarels 	char	type;
4925443Skarels 	char	debug;
5025443Skarels #	define	UPF_BSEDEBUG	01	/* debugging bad sector forwarding */
5125443Skarels #	define	UPF_ECCDEBUG	02	/* debugging ecc correction */
5225443Skarels 	int	retries;
5325443Skarels 	int	ecclim;
54*33533Sbostic } up_softc[MAXNUBA][MAXCTLR][8];
5525443Skarels 
569974Ssam u_char	up_offset[16] = {
579974Ssam 	UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
589974Ssam 	UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
599974Ssam 	UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
609974Ssam 	0, 0, 0, 0
619974Ssam };
629974Ssam 
639974Ssam upopen(io)
649974Ssam 	register struct iob *io;
659974Ssam {
6610352Shelge 	register unit = io->i_unit;
6710023Ssam 	register struct updevice *upaddr;
68*33533Sbostic 	register struct up_softc *sc;
6911118Ssam 	register struct st *st;
709974Ssam 
71*33533Sbostic 	if ((u_int)io->i_ctlr >= MAXCTLR)
72*33533Sbostic 		return (ECTLR);
73*33533Sbostic 	if ((u_int)io->i_part >= MAXPART)
74*33533Sbostic 		return (EPART);
75*33533Sbostic 	upaddr = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]);
7615067Skarels 	upaddr->upcs2 = unit % 8;
77*33533Sbostic 	while ((upaddr->upcs1 & UP_DVA) == 0);
78*33533Sbostic 	sc = &up_softc[io->i_adapt][io->i_ctlr][unit];
7925443Skarels 	if (sc->gottype == 0) {
8010023Ssam 		register int i;
8110023Ssam 		struct iob tio;
8210023Ssam 
8325443Skarels 		sc->retries = RETRIES;
8425443Skarels 		sc->ecclim = 11;
8525443Skarels 		sc->debug = 0;
8625443Skarels 		sc->type = upmaptype(unit, upaddr);
87*33533Sbostic 		if (sc->type < 0) {
88*33533Sbostic 			printf("unknown drive type\n");
89*33533Sbostic 			return (ENXIO);
90*33533Sbostic 		}
9125443Skarels 		st = &upst[sc->type];
92*33533Sbostic 		if (st->off[io->i_part] == -1)
93*33533Sbostic 			return (EPART);
9432196Skarels #ifndef SMALL
9510023Ssam 		/*
9611365Ssam 		 * Read in the bad sector table.
9710023Ssam 		 */
9810023Ssam 		tio = *io;
9910023Ssam 		tio.i_bn = st->nspc * st->ncyl - st->nsect;
100*33533Sbostic 		tio.i_ma = (char *)&upbad[tio.i_adapt][tio.i_ctlr][tio.i_unit];
10110638Shelge 		tio.i_cc = sizeof (struct dkbad);
10210023Ssam 		tio.i_flgs |= F_RDDATA;
10310023Ssam 		for (i = 0; i < 5; i++) {
10410638Shelge 			if (upstrategy(&tio, READ) == sizeof (struct dkbad))
10510023Ssam 				break;
1069974Ssam 			tio.i_bn += 2;
1079974Ssam 		}
1089974Ssam 		if (i == 5) {
10910023Ssam 			printf("Unable to read bad sector table\n");
11010352Shelge 			for (i = 0; i < MAXBADDESC; i++) {
111*33533Sbostic 				upbad[tio.i_adapt][tio.i_ctlr][unit].bt_bad[i].bt_cyl = -1;
112*33533Sbostic 				upbad[tio.i_adapt][tio.i_ctlr][unit].bt_bad[i].bt_trksec = -1;
1139974Ssam 			}
1149974Ssam 		}
11532196Skarels #endif
11625443Skarels 		sc->gottype = 1;
1179974Ssam 	}
11825443Skarels 	st = &upst[sc->type];
119*33533Sbostic 	io->i_boff = st->off[io->i_part] * st->nspc;
12010023Ssam 	io->i_flgs &= ~F_TYPEMASK;
12133408Skarels 	return (0);
1229974Ssam }
1239974Ssam 
1249974Ssam upstrategy(io, func)
1259974Ssam 	register struct iob *io;
1269974Ssam {
12711317Ssam 	int cn, tn, sn, o;
12810352Shelge 	register unit = io->i_unit;
12933408Skarels 	register daddr_t bn;
1309974Ssam 	int recal, info, waitdry;
131*33533Sbostic 	register struct updevice *upaddr;
132*33533Sbostic 	struct up_softc *sc;
133*33533Sbostic 	register struct st *st;
13433408Skarels 	int error, rv = io->i_cc;
13533408Skarels #ifndef SMALL
13633408Skarels 	int doprintf = 0;
13733408Skarels #endif
1389974Ssam 
139*33533Sbostic 	upaddr = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]);
140*33533Sbostic 	sc = &up_softc[io->i_adapt][io->i_ctlr][unit];
141*33533Sbostic 	st = &upst[sc->type];
14210352Shelge 	sectsiz = SECTSIZ;
14311085Ssam 	if (io->i_flgs & (F_HDR|F_HCHECK))
14410352Shelge 		sectsiz += HDRSIZ;
14511365Ssam 	upaddr->upcs2 = unit % 8;
1469974Ssam 	if ((upaddr->upds & UPDS_VV) == 0) {
1479974Ssam 		upaddr->upcs1 = UP_DCLR|UP_GO;
1489974Ssam 		upaddr->upcs1 = UP_PRESET|UP_GO;
1499974Ssam 		upaddr->upof = UPOF_FMT22;
1509974Ssam 	}
15125443Skarels 	if ((upaddr->upds & UPDS_DREADY) == 0) {
15225443Skarels 		printf("up%d not ready", unit);
15325443Skarels 		return (-1);
15425443Skarels 	}
1559974Ssam 	info = ubasetup(io, 1);
1569974Ssam 	upaddr->upwc = -io->i_cc / sizeof (short);
15711085Ssam 	recal = 0;
15811085Ssam 	io->i_errcnt = 0;
15911085Ssam 
16010638Shelge restart:
16125443Skarels 	error = 0;
16211317Ssam 	o = io->i_cc + (upaddr->upwc * sizeof (short));
16311317Ssam 	upaddr->upba = info + o;
16411317Ssam 	bn = io->i_bn + o / sectsiz;
16533408Skarels #ifndef SMALL
16625443Skarels 	if (doprintf && sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG))
16711386Ssam 		printf("wc=%d o=%d i_bn=%d bn=%d\n",
16811365Ssam 			upaddr->upwc, o, io->i_bn, bn);
16933408Skarels #endif
17010023Ssam 	while((upaddr->upds & UPDS_DRY) == 0)
17110023Ssam 		;
17210352Shelge 	if (upstart(io, bn) != 0) {
17325443Skarels 		rv = -1;
17425443Skarels 		goto done;
17510352Shelge 	}
1769974Ssam 	do {
1779974Ssam 		DELAY(25);
1789974Ssam 	} while ((upaddr->upcs1 & UP_RDY) == 0);
17911085Ssam 	/*
18011085Ssam 	 * If transfer has completed, free UNIBUS
18111085Ssam 	 * resources and return transfer size.
18211085Ssam 	 */
18315067Skarels 	if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0)
18415067Skarels 		goto done;
18525443Skarels 	bn = io->i_bn +
18625443Skarels 		(io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz;
18725443Skarels 	if (upaddr->uper1 & (UPER1_DCK|UPER1_ECH))
18825443Skarels 		bn--;
18925443Skarels 	cn = bn/st->nspc;
19025443Skarels 	sn = bn%st->nspc;
19125443Skarels 	tn = sn/st->nsect;
19225443Skarels 	sn = sn%st->nsect;
19332196Skarels #ifndef SMALL
19425443Skarels 	if (sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) {
19525443Skarels 		printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
19625443Skarels 		   bn, cn, tn, sn);
19711386Ssam 		printf("cs2=%b er1=%b er2=%b wc=%d\n",
19811365Ssam 	    	  upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
19911386Ssam 		  UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc);
20011365Ssam 	}
20132196Skarels #endif
2029974Ssam 	waitdry = 0;
20311386Ssam 	while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz)
20410023Ssam 		DELAY(5);
20532196Skarels #ifndef SMALL
20611085Ssam 	if (upaddr->uper1&UPER1_WLE) {
20711085Ssam 		/*
20811085Ssam 		 * Give up on write locked devices immediately.
20911085Ssam 		 */
21011085Ssam 		printf("up%d: write locked\n", unit);
21125443Skarels 		rv = -1;
21225443Skarels 		goto done;
21311085Ssam 	}
21425443Skarels 	if (upaddr->uper2 & UPER2_BSE) {
21525443Skarels 		if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0)
21625443Skarels 			goto success;
21725443Skarels 		error = EBSE;
21825443Skarels 		goto hard;
21925443Skarels 	}
22025443Skarels 	/*
22125443Skarels 	 * ECC error. If a soft error, correct it;
22225443Skarels 	 * if correction is too large, no more retries.
22325443Skarels 	 */
22425443Skarels 	if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH|UPER1_HCRC)) == UPER1_DCK) {
22525443Skarels 		if (upecc(io, ECC) == 0)
22625443Skarels 			goto success;
22725443Skarels 		error = EECC;
22825443Skarels 		goto hard;
22925443Skarels 	}
23025443Skarels 	/*
23125443Skarels 	 * If the error is a header CRC,
23225443Skarels 	 * check if a replacement sector exists in
23325443Skarels 	 * the bad sector table.
23425443Skarels 	 */
23525443Skarels 	if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 &&
23625443Skarels 	     upecc(io, BSE) == 0)
23725443Skarels 		goto success;
23832196Skarels #endif
23925443Skarels 	if (++io->i_errcnt > sc->retries) {
2409974Ssam 		/*
2419974Ssam 		 * After 28 retries (16 without offset, and
2429974Ssam 		 * 12 with offset positioning) give up.
2439974Ssam 		 */
24410352Shelge hard:
24525443Skarels 		if (error == 0) {
24625443Skarels 			error = EHER;
24725443Skarels 			if (upaddr->upcs2 & UPCS2_WCE)
24825443Skarels 				error = EWCK;
24925443Skarels 		}
25025443Skarels 		printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
25125443Skarels 		   bn, cn, tn, sn);
25225443Skarels 		printf("cs2=%b er1=%b er2=%b\n",
25311085Ssam 		   upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
25411085Ssam 		   UPER1_BITS, upaddr->uper2, UPER2_BITS);
2559974Ssam 		upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
25610352Shelge 		io->i_errblk = bn;
25715067Skarels 		if (io->i_errcnt >= 16) {
25815067Skarels 			upaddr->upof = UPOF_FMT22;
25915067Skarels 			upaddr->upcs1 = UP_RTC|UP_GO;
26015067Skarels 			while ((upaddr->upds&UPDS_DRY) == 0)
26115067Skarels 				DELAY(25);
26215067Skarels 		}
26325443Skarels 		rv = -1;
26425443Skarels 		goto done;
26511085Ssam 	}
26611085Ssam 	/*
2679974Ssam 	 * Clear drive error and, every eight attempts,
2689974Ssam 	 * (starting with the fourth)
2699974Ssam 	 * recalibrate to clear the slate.
2709974Ssam 	 */
2719974Ssam 	upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
27210638Shelge 	if ((io->i_errcnt&07) == 4 ) {
2739974Ssam 		upaddr->upcs1 = UP_RECAL|UP_GO;
27415067Skarels 		while ((upaddr->upds&UPDS_DRY) == 0)
27515067Skarels 			DELAY(25);
2769974Ssam 		upaddr->updc = cn;
2779974Ssam 		upaddr->upcs1 = UP_SEEK|UP_GO;
27815067Skarels 		while ((upaddr->upds&UPDS_DRY) == 0)
27915067Skarels 			DELAY(25);
28015067Skarels 	}
28115067Skarels 	if (io->i_errcnt >= 16 && (func & READ)) {
2829974Ssam 		upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22;
2839974Ssam 		upaddr->upcs1 = UP_OFFSET|UP_GO;
28410638Shelge 		while ((upaddr->upds&UPDS_DRY) == 0)
28510638Shelge 			DELAY(25);
2869974Ssam 	}
28710638Shelge 	goto restart;
28811085Ssam 
2899974Ssam success:
29011386Ssam #define	rounddown(x, y)	(((x) / (y)) * (y))
29111386Ssam 	upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short));
29211386Ssam 	if (upaddr->upwc) {
29333408Skarels #ifndef SMALL
29411317Ssam 		doprintf++;
29533408Skarels #endif
29610638Shelge 		goto restart;
29711317Ssam 	}
29815067Skarels done:
2999974Ssam 	/*
30011365Ssam 	 * Release UNIBUS
3019974Ssam 	 */
3029974Ssam 	ubafree(io, info);
30315067Skarels 	/*
30415067Skarels 	 * If we were offset positioning,
30515067Skarels 	 * return to centerline.
30615067Skarels 	 */
30715067Skarels 	if (io->i_errcnt >= 16) {
30815067Skarels 		upaddr->upof = UPOF_FMT22;
30915067Skarels 		upaddr->upcs1 = UP_RTC|UP_GO;
31015067Skarels 		while ((upaddr->upds&UPDS_DRY) == 0)
31115067Skarels 			DELAY(25);
31215067Skarels 	}
31325443Skarels 	return (rv);
3149974Ssam }
3159974Ssam 
31632196Skarels #ifndef SMALL
3179974Ssam /*
31811143Ssam  * Correct an ECC error, and restart the
31911143Ssam  * i/o to complete the transfer (if necessary).
32011143Ssam  * This is quite complicated because the transfer
32111143Ssam  * may be going to an odd memory address base and/or
3229974Ssam  * across a page boundary.
3239974Ssam  */
32410023Ssam upecc(io, flag)
3259974Ssam 	register struct iob *io;
3269974Ssam 	int flag;
3279974Ssam {
328*33533Sbostic 	register i, unit;
329*33533Sbostic 	register struct up_softc *sc;
330*33533Sbostic 	register struct updevice *up;
33110352Shelge 	register struct st *st;
3329974Ssam 	caddr_t addr;
33310410Shelge 	int bn, twc, npf, mask, cn, tn, sn;
33410352Shelge 	daddr_t bbn;
3359974Ssam 
3369974Ssam 	/*
33711143Ssam 	 * Npf is the number of sectors transferred
33811143Ssam 	 * before the sector containing the ECC error;
33911143Ssam 	 * bn is the current block number.
3409974Ssam 	 */
341*33533Sbostic 	unit = io->i_unit;
342*33533Sbostic 	sc = &up_softc[io->i_adapt][io->i_ctlr][unit];
343*33533Sbostic 	up = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]);
34410352Shelge 	twc = up->upwc;
34511143Ssam 	npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz;
34615067Skarels 	if (flag == ECC)
34715067Skarels 		npf--;
34825443Skarels 	if (sc->debug & UPF_ECCDEBUG)
34911386Ssam 		printf("npf=%d mask=0x%x ec1=%d wc=%d\n",
35011386Ssam 			npf, up->upec2, up->upec1, twc);
35111317Ssam 	bn = io->i_bn + npf;
35225443Skarels 	st = &upst[sc->type];
35310410Shelge 	cn = bn/st->nspc;
35410410Shelge 	sn = bn%st->nspc;
35510410Shelge 	tn = sn/st->nsect;
35610410Shelge 	sn = sn%st->nsect;
35711143Ssam 
3589974Ssam 	/*
35911143Ssam 	 * ECC correction.
3609974Ssam 	 */
3619974Ssam 	if (flag == ECC) {
36225443Skarels 		int bit, o;
36311085Ssam 
3649974Ssam 		mask = up->upec2;
36511365Ssam 		printf("up%d: soft ecc sn%d\n", unit, bn);
36625443Skarels 		for (i = mask, bit = 0; i; i >>= 1)
36725443Skarels 			if (i & 1)
36825443Skarels 				bit++;
36925443Skarels 		if (bit > sc->ecclim) {
37025443Skarels 			printf("%d-bit error\n", bit);
37125443Skarels 			return (1);
37225443Skarels 		}
3739974Ssam 		/*
37411317Ssam 		 * Compute the byte and bit position of
37511317Ssam 		 * the error.  o is the byte offset in
37611317Ssam 		 * the transfer at which the correction
37711317Ssam 		 * applied.
3789974Ssam 		 */
3799974Ssam 		i = up->upec1 - 1;		/* -1 makes 0 origin */
38011386Ssam 		bit = i & 07;
38111386Ssam 		o = (i & ~07) >> 3;
3829974Ssam 		up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
3839974Ssam 		/*
38411143Ssam 		 * Correct while possible bits remain of mask.
38511143Ssam 		 * Since mask contains 11 bits, we continue while
38611143Ssam 		 * the bit offset is > -11.  Also watch out for
38711143Ssam 		 * end of this block and the end of the transfer.
3889974Ssam 		 */
38911317Ssam 		while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) {
3909974Ssam 			/*
39111143Ssam 			 * addr =
39211317Ssam 			 *  (base address of transfer) +
39311143Ssam 			 *  (# sectors transferred before the error) *
39411143Ssam 			 *    (sector size) +
39511317Ssam 			 *  (byte offset to incorrect data)
3969974Ssam 			 */
39711317Ssam 			addr = io->i_ma + (npf * sectsiz) + o;
39811317Ssam 			/*
39911317Ssam 			 * No data transfer occurs with a write check,
40011317Ssam 			 * so don't correct the resident copy of data.
40111317Ssam 			 */
40211365Ssam 			if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
40325443Skarels 				if (sc->debug & UPF_ECCDEBUG)
40411365Ssam 					printf("addr=0x%x old=0x%x ", addr,
40511365Ssam 						(*addr&0xff));
40610352Shelge 				*addr ^= (mask << bit);
40725443Skarels 				if (sc->debug & UPF_ECCDEBUG)
40811365Ssam 					printf("new=0x%x\n", (*addr&0xff));
40911365Ssam 			}
41011317Ssam 			o++, bit -= 8;
4119974Ssam 		}
41211085Ssam 		return (0);
41311085Ssam 	}
41411143Ssam 
41511143Ssam 	/*
41611143Ssam 	 * Bad sector forwarding.
41711143Ssam 	 */
41811085Ssam 	if (flag == BSE) {
4199974Ssam 		/*
42011143Ssam 		 * If not in bad sector table,
42111143Ssam 		 * indicate a hard error to caller.
4229974Ssam 		 */
42310352Shelge 		up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
424*33533Sbostic 		if ((bbn = isbad(&upbad[io->i_adapt][io->i_ctlr][unit], cn, tn, sn)) < 0)
42511085Ssam 			return (1);
42611386Ssam 		bbn = (st->ncyl * st->nspc) - st->nsect - 1 - bbn;
42710352Shelge 		twc = up->upwc + sectsiz;
42811085Ssam 		up->upwc = - (sectsiz / sizeof (short));
42925443Skarels 		if (sc->debug & UPF_BSEDEBUG)
43011365Ssam 			printf("revector sn %d to %d\n", sn, bbn);
4319974Ssam 		/*
43211143Ssam 	 	 * Clear the drive & read the replacement
43311143Ssam 		 * sector.  If this is in the middle of a
43411143Ssam 		 * transfer, then set up the controller
43511143Ssam 		 * registers in a normal fashion.
43611143Ssam 	 	 * The UNIBUS address need not be changed.
43711143Ssam 	 	 */
43811386Ssam 		while ((up->upcs1 & UP_RDY) == 0)
4399974Ssam 			;
44011386Ssam 		if (upstart(io, bbn))
44110352Shelge 			return (1);		/* error */
44210352Shelge 		io->i_errcnt = 0;		/* success */
4439974Ssam 		do {
4449974Ssam 			DELAY(25);
44511386Ssam 		} while ((up->upcs1 & UP_RDY) == 0) ;
44611386Ssam 		if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) {
44711386Ssam 			up->upwc = twc - sectsiz;
44810352Shelge 			return (1);
4499974Ssam 		}
4509974Ssam 	}
45110638Shelge 	if (twc)
4529974Ssam 		up->upwc = twc;
45310352Shelge 	return (0);
4549974Ssam }
455*33533Sbostic #endif /* !SMALL */
4569974Ssam 
4579974Ssam upstart(io, bn)
45810023Ssam 	register struct iob *io;
45910023Ssam 	daddr_t bn;
4609974Ssam {
461*33533Sbostic 	register struct updevice *upaddr;
462*33533Sbostic 	register struct up_softc *sc;
463*33533Sbostic 	register struct st *st;
4649974Ssam 	int sn, tn;
4659974Ssam 
466*33533Sbostic 	upaddr = (struct updevice *)ubamem(io->i_adapt, ubastd[io->i_ctlr]);
467*33533Sbostic 	sc = &up_softc[io->i_adapt][io->i_ctlr][io->i_unit];
468*33533Sbostic 	st = &upst[sc->type];
4699974Ssam 	sn = bn%st->nspc;
4709974Ssam 	tn = sn/st->nsect;
4719974Ssam 	sn %= st->nsect;
4729974Ssam 	upaddr->updc = bn/st->nspc;
4739974Ssam 	upaddr->upda = (tn << 8) + sn;
47410352Shelge 	switch (io->i_flgs & F_TYPEMASK) {
47510023Ssam 
47610023Ssam 	case F_RDDATA:
47710023Ssam 		upaddr->upcs1 = UP_RCOM|UP_GO;
4789974Ssam 		break;
47910023Ssam 
48010023Ssam 	case F_WRDATA:
48110023Ssam 		upaddr->upcs1 = UP_WCOM|UP_GO;
4829974Ssam 		break;
48310023Ssam 
48432196Skarels #ifndef SMALL
485*33533Sbostic 	case F_HDR|F_RDDATA:
48610023Ssam 		upaddr->upcs1 = UP_RHDR|UP_GO;
48710023Ssam 		break;
48810023Ssam 
48910023Ssam 	case F_HDR|F_WRDATA:
49010023Ssam 		upaddr->upcs1 = UP_WHDR|UP_GO;
49110023Ssam 		break;
49210023Ssam 
49310023Ssam 	case F_CHECK|F_WRDATA:
49410023Ssam 	case F_CHECK|F_RDDATA:
4959974Ssam 		upaddr->upcs1 = UP_WCDATA|UP_GO;
4969974Ssam 		break;
49710023Ssam 
49810023Ssam 	case F_HCHECK|F_WRDATA:
49910023Ssam 	case F_HCHECK|F_RDDATA:
5009974Ssam 		upaddr->upcs1 = UP_WCHDR|UP_GO;
5019974Ssam 		break;
50232196Skarels #endif
50310023Ssam 
5049974Ssam 	default:
50510023Ssam 		io->i_error = ECMD;
50610023Ssam 		io->i_flgs &= ~F_TYPEMASK;
50710023Ssam 		return (1);
5089974Ssam 	}
50910023Ssam 	return (0);
5109974Ssam }
5119974Ssam 
512*33533Sbostic #ifndef SMALL
51310023Ssam /*ARGSUSED*/
51410023Ssam upioctl(io, cmd, arg)
51510023Ssam 	struct iob *io;
51610023Ssam 	int cmd;
51710023Ssam 	caddr_t arg;
51810023Ssam {
51925443Skarels 	int unit = io->i_unit;
520*33533Sbostic 	register struct up_softc *sc;
521*33533Sbostic 	struct st *st;
52210352Shelge 
523*33533Sbostic 	sc = &up_softc[io->i_adapt][io->i_ctlr][unit];
524*33533Sbostic 	st = &upst[sc->type];
52510352Shelge 	switch(cmd) {
52610352Shelge 
52711365Ssam 	case SAIODEBUG:
52825443Skarels 		sc->debug = (int)arg;
52925443Skarels 		break;
53011365Ssam 
53110352Shelge 	case SAIODEVDATA:
53225443Skarels 		*(struct st *)arg = *st;
53325443Skarels 		break;
53425443Skarels 
53525443Skarels 	case SAIOGBADINFO:
536*33533Sbostic 		*(struct dkbad *)arg = upbad[io->i_adapt][io->i_ctlr][unit];
53725443Skarels 		break;
53825443Skarels 
53925443Skarels 	case SAIOECCLIM:
54025443Skarels 		sc->ecclim = (int)arg;
54125443Skarels 		break;
54225443Skarels 
54325443Skarels 	case SAIORETRIES:
54425443Skarels 		sc->retries = (int)arg;
54525443Skarels 		break;
54625443Skarels 
54725443Skarels 	default:
54825443Skarels 		return (ECMD);
54910352Shelge 	}
55025443Skarels 	return (0);
55110023Ssam }
552*33533Sbostic #endif /* !SMALL */
553