xref: /csrg-svn/sys/vax/stand/up.c (revision 10638)
1*10638Shelge /*	up.c	4.5	83/01/31	*/
29974Ssam 
310023Ssam /*
410023Ssam  * UNIBUS peripheral standalone driver
510023Ssam  * with ECC correction and bad block forwarding.
610023Ssam  * Also supports header operation and write
710023Ssam  * check for data and/or header.
810023Ssam  */
910352Shelge 
109974Ssam #include "../h/param.h"
119974Ssam #include "../h/inode.h"
129974Ssam #include "../h/fs.h"
139974Ssam #include "../h/dkbad.h"
149974Ssam #include "../h/vmmac.h"
159974Ssam 
169974Ssam #include "../vax/pte.h"
179974Ssam #include "../vaxuba/upreg.h"
189974Ssam #include "../vaxuba/ubareg.h"
199974Ssam 
2010023Ssam #include "saio.h"
219974Ssam #include "savax.h"
229974Ssam 
2310352Shelge #define MAXBADDESC	126	/* max number of bad sectors recorded */
2410352Shelge #define SECTSIZ		512	/* sector size in bytes */
2510352Shelge #define HDRSIZ		4	/* number of bytes in sector header */
2610352Shelge #define MAXECC		5	/* max number of bad bits accepted in
2710352Shelge 				 * a soft ecc error when F_ECCLM is set */
2810352Shelge #define	NUPTYPES	3
2910352Shelge 
3010023Ssam u_short	ubastd[] = { 0776700 };
319974Ssam 
329974Ssam char	up_gottype[MAXNUBA*8] = { 0 };
339974Ssam char	up_type[MAXNUBA*8] = { 0 };
349974Ssam short	up_off[] = { 0, 27, 68, -1, -1, -1, -1, 82 };
359974Ssam short	fj_off[] = { 0, 50, 0, -1, -1, -1, -1, 155 };
369974Ssam /* this is called upam instead of am because hp.c has a similar array */
379974Ssam short	upam_off[] = { 0, 32, 0, 668, 723, 778, 668, 98 };
3810023Ssam 
3910352Shelge struct st upst[NUPTYPES] = {
4010023Ssam 	32,	19,	32*19,	823,	up_off,		/* 9300/equiv */
4110023Ssam 	32,	10,	32*10,	823,	fj_off,		/* Fuji 160 */
4210023Ssam 	32,	16,	32*16,	1024,	upam_off,	/* Capricorn */
439974Ssam };
4410023Ssam 
459974Ssam u_char	up_offset[16] = {
469974Ssam 	UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
479974Ssam 	UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
489974Ssam 	UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
499974Ssam 	0, 0, 0, 0
509974Ssam };
519974Ssam 
5210023Ssam struct  dkbad upbad[MAXNUBA*8];		/* bad sector table */
5310352Shelge int 	sectsiz;			/* real sector size */
5410023Ssam 
559974Ssam upopen(io)
569974Ssam 	register struct iob *io;
579974Ssam {
5810352Shelge 	register unit = io->i_unit;
5910023Ssam 	register struct updevice *upaddr;
6010352Shelge 	register struct st *st = &upst[up_type[unit]];
619974Ssam 
6210023Ssam 	if (io->i_boff < 0 || io->i_boff > 7 || st->off[io->i_boff] == -1)
6310023Ssam 		_stop("up bad unit");
6410352Shelge 	upaddr = (struct updevice *)ubamem(unit, ubastd[0]);
659974Ssam 	while ((upaddr->upcs1 & UP_DVA) == 0) /* infinite wait */
669974Ssam 		;
6710352Shelge 	if (up_gottype[unit] == 0) {
6810023Ssam 		register int i;
6910023Ssam 		struct iob tio;
7010023Ssam 
719974Ssam 		upaddr->uphr = UPHR_MAXTRAK;
7210023Ssam 		for (st = upst; st < &upst[NUPTYPES]; st++)
7310023Ssam 			if (upaddr->uphr == st->ntrak - 1) {
7410352Shelge 				up_type[unit] = st - upst;
7510023Ssam 				break;
7610023Ssam 			}
7710023Ssam 		if (st == &upst[NUPTYPES]) {
7810352Shelge 			printf("up%d: uphr=%x\n", unit, upaddr->uphr);
7910023Ssam 			_stop("unknown drive type");
8010023Ssam 		}
819974Ssam 		upaddr->upcs2 = UPCS2_CLR;
829974Ssam #ifdef DEBUG
8310352Shelge 		printf("Unittype=%d\n",up_type[unit]);
849974Ssam #endif
859974Ssam 
8610023Ssam 		/*
8710023Ssam 		 * Read in the bad sector table:
8810023Ssam 		 *	copy the contents of the io structure
8910023Ssam 		 *	to tio for use during the bb pointer
9010023Ssam 		 *	read operation.
9110023Ssam 		 */
9210023Ssam 		tio = *io;
9310023Ssam 		tio.i_bn = st->nspc * st->ncyl - st->nsect;
949974Ssam 		tio.i_ma = (char *)&upbad[tio.i_unit];
95*10638Shelge 		tio.i_cc = sizeof (struct dkbad);
9610023Ssam 		tio.i_flgs |= F_RDDATA;
9710023Ssam 		for (i = 0; i < 5; i++) {
98*10638Shelge 			if (upstrategy(&tio, READ) == sizeof (struct dkbad))
9910023Ssam 				break;
1009974Ssam 			tio.i_bn += 2;
1019974Ssam 		}
1029974Ssam 		if (i == 5) {
10310023Ssam 			printf("Unable to read bad sector table\n");
10410352Shelge 			for (i = 0; i < MAXBADDESC; i++) {
10510352Shelge 				upbad[unit].bt_bad[i].bt_cyl = -1;
10610352Shelge 				upbad[unit].bt_bad[i].bt_trksec = -1;
1079974Ssam 			}
1089974Ssam 		}
10910352Shelge 		up_gottype[unit] = 1;
1109974Ssam 	}
1119974Ssam 	io->i_boff = st->off[io->i_boff] * st->nspc;
11210023Ssam 	io->i_flgs &= ~F_TYPEMASK;
1139974Ssam }
1149974Ssam 
1159974Ssam upstrategy(io, func)
1169974Ssam 	register struct iob *io;
1179974Ssam {
11810352Shelge 	int cn, tn, sn;
11910352Shelge 	register unit = io->i_unit;
1209974Ssam 	daddr_t bn;
1219974Ssam 	int recal, info, waitdry;
1229974Ssam 	register struct updevice *upaddr =
12310352Shelge 	    (struct updevice *)ubamem(unit, ubastd[0]);
12410352Shelge 	register struct st *st = &upst[up_type[unit]];
1259974Ssam 
12610352Shelge 	sectsiz = SECTSIZ;
12710352Shelge 	if ((io->i_flgs & (F_HDR|F_CHECK)) != 0)
12810352Shelge 		sectsiz += HDRSIZ;
1299974Ssam 	io->i_errcnt = 0;
130*10638Shelge 	recal = 0;
1319974Ssam 	upaddr->upcs2 = unit;
1329974Ssam 	if ((upaddr->upds & UPDS_VV) == 0) {
1339974Ssam 		upaddr->upcs1 = UP_DCLR|UP_GO;
1349974Ssam 		upaddr->upcs1 = UP_PRESET|UP_GO;
1359974Ssam 		upaddr->upof = UPOF_FMT22;
1369974Ssam 	}
1379974Ssam 	if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY)
1389974Ssam 		_stop("up not ready");
1399974Ssam 	info = ubasetup(io, 1);
1409974Ssam 	upaddr->upwc = -io->i_cc / sizeof (short);
1419974Ssam 	upaddr->upba = info;
142*10638Shelge restart:
14310352Shelge 	bn = io->i_bn + (io->i_cc + upaddr->upwc*sizeof(short))/sectsiz;
14410023Ssam 	while((upaddr->upds & UPDS_DRY) == 0)
14510023Ssam 		;
14610352Shelge 	if (upstart(io, bn) != 0) {
14710352Shelge 		ubafree(io, info);
1489974Ssam 		return (-1);
14910352Shelge 	}
1509974Ssam 	do {
1519974Ssam 		DELAY(25);
1529974Ssam 	} while ((upaddr->upcs1 & UP_RDY) == 0);
1539974Ssam 
15410352Shelge 	if (((upaddr->upds&UPDS_ERR) | (upaddr->upcs1&UP_TRE)) == 0 ) {
15510352Shelge 		ubafree(io, info);
1569974Ssam 		return(io->i_cc);
15710352Shelge 	}
1589974Ssam 
1599974Ssam #ifdef LOGALLERRS
1609974Ssam 	printf("uper: (c,t,s)=(%d,%d,%d) cs2=%b er1=%b er2=%b wc=%x\n",
1619974Ssam 			upaddr->updc, upaddr->upda>>8, (upaddr->upda&0x1f-1),
1629974Ssam 		    	upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
1639974Ssam 			UPER1_BITS, upaddr->uper2, UPER2_BITS,-upaddr->upwc);
1649974Ssam #endif
1659974Ssam 	waitdry = 0;
16610352Shelge 	while ((upaddr->upds & UPDS_DRY) == 0 && ++waitdry < sectsiz)
16710023Ssam 		DELAY(5);
1689974Ssam 	if (++io->i_errcnt > 27) {
1699974Ssam 		/*
1709974Ssam 		 * After 28 retries (16 without offset, and
1719974Ssam 		 * 12 with offset positioning) give up.
1729974Ssam 		 */
17310023Ssam 		io->i_error = EHER;
17410023Ssam 		if (upaddr->upcs2 & UPCS2_WCE)
17510023Ssam 			io->i_error = EWCK;
17610352Shelge hard:
17710352Shelge 		bn = io->i_bn + (io->i_cc + upaddr->upwc*sizeof(short))/sectsiz;
1789974Ssam 		cn = bn/st->nspc;
1799974Ssam 		sn = bn%st->nspc;
1809974Ssam 		tn = sn/st->nsect;
1819974Ssam 		sn = sn%st->nsect;
1829974Ssam 		printf("up error: (cyl,trk,sec)=(%d,%d,%d) cs2=%b er1=%b er2=%b\n",
1839974Ssam 		    	cn, tn, sn,
1849974Ssam 		    	upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
1859974Ssam 			UPER1_BITS, upaddr->uper2, UPER2_BITS);
1869974Ssam 		upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
18710352Shelge 		io->i_errblk = bn;
1889974Ssam 		return (io->i_cc + upaddr->upwc*sizeof(short));
1899974Ssam 	} else
1909974Ssam 		if (upaddr->uper1&UPER1_WLE) {
19110023Ssam 			/*
19210023Ssam 			 * Give up on write locked devices
19310023Ssam 			 * immediately.
19410023Ssam 			 */
19510023Ssam 			printf("up%d: write locked\n", unit);
19610023Ssam 			return(-1);
1979974Ssam 		}
1989974Ssam #ifndef NOBADSECT
1999974Ssam 	else if (upaddr->uper2 & UPER2_BSE) {
20010352Shelge 		if (io->i_flgs & F_NBSF) {
20110352Shelge 			io->i_error = EBSE;
20210352Shelge 			goto hard;
20310352Shelge 		}
20410352Shelge 		if (upecc( io, BSE) == 0)
2059974Ssam 			goto success;
2069974Ssam 		else {
20710023Ssam 			io->i_error = EBSE;
2089974Ssam 			goto hard;
2099974Ssam 		}
2109974Ssam 	}
2119974Ssam #endif
2129974Ssam 	else {
2139974Ssam 		/*
2149974Ssam 		 * Retriable error.
2159974Ssam 		 * If a soft ecc, correct it
2169974Ssam 		 * Otherwise fall through and retry the transfer
2179974Ssam 		 */
21810352Shelge 		if ((upaddr->uper1 & UPER1_DCK) != 0) {
21910352Shelge 			/*
22010352Shelge 			 * If a write check command is active, all
22110352Shelge 			 * ecc errors give UPER1_ECH.
22210352Shelge 			 */
22310352Shelge 			if (((upaddr->uper1 & UPER1_ECH) == 0 )||
22410352Shelge 			    ((upaddr->upcs2 & UPCS2_WCE) != 0 )) {
22510352Shelge 				if (upecc(io, ECC) == 0)
22610352Shelge 					goto success;
22710352Shelge 				else {
22810352Shelge 					io->i_error = EECC;
22910352Shelge 					goto hard;
23010352Shelge 				}
23110352Shelge 			}
23210352Shelge 		}
2339974Ssam 	}
2349974Ssam 	/*
2359974Ssam 	 * Clear drive error and, every eight attempts,
2369974Ssam 	 * (starting with the fourth)
2379974Ssam 	 * recalibrate to clear the slate.
2389974Ssam 	 */
2399974Ssam 	upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
240*10638Shelge 	if ((io->i_errcnt&07) == 4 ) {
2419974Ssam 		upaddr->upcs1 = UP_RECAL|UP_GO;
242*10638Shelge 		recal = 1;
243*10638Shelge 		goto restart;
2449974Ssam 	}
2459974Ssam 	/*
2469974Ssam 	 * Advance recalibration finite state machine
2479974Ssam 	 * if recalibrate in progress, through
2489974Ssam 	 *	RECAL
2499974Ssam 	 *	SEEK
2509974Ssam 	 *	OFFSET (optional)
2519974Ssam 	 *	RETRY
2529974Ssam 	 */
2539974Ssam 	switch (recal) {
2549974Ssam 
2559974Ssam 	case 1:
2569974Ssam 		upaddr->updc = cn;
2579974Ssam 		upaddr->upcs1 = UP_SEEK|UP_GO;
258*10638Shelge 		recal++;
259*10638Shelge 		goto restart;
26010023Ssam 
2619974Ssam 	case 2:
2629974Ssam 		if (io->i_errcnt < 16 || (func & READ) == 0)
2639974Ssam 			goto donerecal;
2649974Ssam 		upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22;
2659974Ssam 		upaddr->upcs1 = UP_OFFSET|UP_GO;
2669974Ssam 		recal++;
267*10638Shelge 		goto restart;
26810023Ssam 
2699974Ssam 	donerecal:
2709974Ssam 	case 3:
2719974Ssam 		recal = 0;
2729974Ssam 		break;
2739974Ssam 	}
2749974Ssam 	/*
275*10638Shelge 	 * If we were offset positioning,
276*10638Shelge 	 * return to centerline.
2779974Ssam 	 */
278*10638Shelge 	if (io->i_errcnt >= 16) {
279*10638Shelge 		upaddr->upof = UPOF_FMT22;
280*10638Shelge 		upaddr->upcs1 = UP_RTC|UP_GO;
281*10638Shelge 		while ((upaddr->upds&UPDS_DRY) == 0)
282*10638Shelge 			DELAY(25);
2839974Ssam 	}
284*10638Shelge 	goto restart;
2859974Ssam success:
28610023Ssam 	if (upaddr->upwc != 0)
287*10638Shelge 		goto restart;
2889974Ssam 	/*
2899974Ssam 	 * Release unibus
2909974Ssam 	 */
2919974Ssam 	ubafree(io, info);
2929974Ssam 	return (io->i_cc);
2939974Ssam }
2949974Ssam 
2959974Ssam /*
2969974Ssam  * Correct an ECC error, and restart the i/o to complete
2979974Ssam  * the transfer if necessary.  This is quite complicated because
2989974Ssam  * the transfer may be going to an odd memory address base and/or
2999974Ssam  * across a page boundary.
3009974Ssam  */
30110023Ssam upecc(io, flag)
3029974Ssam 	register struct iob *io;
3039974Ssam 	int flag;
3049974Ssam {
3059974Ssam 	register struct updevice *up =
3069974Ssam 		(struct updevice *)ubamem(io->i_unit, ubastd[0]);
30710352Shelge 	register struct st *st;
3089974Ssam 	register int i;
3099974Ssam 	caddr_t addr;
31010410Shelge 	int bn, twc, npf, mask, cn, tn, sn;
31110352Shelge 	daddr_t bbn;
3129974Ssam 
3139974Ssam 	/*
3149974Ssam 	 * Npf is the number of sectors transferred before the sector
3159974Ssam 	 * containing the ECC error, bn is the current block number
3169974Ssam 	 */
31710352Shelge 	twc = up->upwc;
31810352Shelge 	npf = ((twc * sizeof(short)) + io->i_cc)/sectsiz;
3199974Ssam #ifdef UPECCDEBUG
3209974Ssam 	printf("npf %d mask 0x%x pos %d wc 0x%x\n",npf,mask,up->upec1,-up->upwc);
3219974Ssam #endif
32210352Shelge 	bn = io->i_bn + npf ;
3239974Ssam 	st = &upst[up_type[io->i_unit]];
32410410Shelge 	cn = bn/st->nspc;
32510410Shelge 	sn = bn%st->nspc;
32610410Shelge 	tn = sn/st->nsect;
32710410Shelge 	sn = sn%st->nsect;
3289974Ssam 	/*
3299974Ssam 	 * action taken depends on the flag
3309974Ssam 	 */
3319974Ssam 	if (flag == ECC) {
33210352Shelge 		int bit, byte, ecccnt;
33310352Shelge 		ecccnt = 0;
3349974Ssam 		mask = up->upec2;
335*10638Shelge 		printf("up%d: soft ecc sn%d\n", io->i_unit, bn);
3369974Ssam 		/*
3379974Ssam 		 * Compute the
3389974Ssam 		 * byte and bit position of the error.  The variable i
3399974Ssam 		 * is the byte offset in the transfer.
3409974Ssam 		 */
3419974Ssam 		i = up->upec1 - 1;		/* -1 makes 0 origin */
3429974Ssam 		bit = i&07;
3439974Ssam 		i = (i&~07)>>3;
3449974Ssam 		byte = i;
3459974Ssam 		up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
3469974Ssam 		/*
3479974Ssam 		 * Correct while possible bits remain of mask.  Since mask
3489974Ssam 		 * contains 11 bits, we continue while the bit offset is > -11.
3499974Ssam 		 * Also watch out for end of this block and the end of the whole
3509974Ssam 		 * transfer.
3519974Ssam 		 */
35210352Shelge 		while (i < sectsiz && (npf*sectsiz)+i < io->i_cc && bit > -11) {
3539974Ssam 			/*
35410023Ssam 			 * addr = vax base addr + (number of sectors transferred
3559974Ssam 			 *	  before the error sector times the sector size)
3569974Ssam 			 *	  + byte number
3579974Ssam 			 */
35810352Shelge 			addr = io->i_ma + (npf*sectsiz) + byte;
3599974Ssam #ifdef UPECCDEBUG
36010352Shelge 			printf("addr %x old: %x ",addr, (*addr&0xff));
3619974Ssam #endif
36210352Shelge 			if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0)
36310352Shelge 				*addr ^= (mask << bit);
3649974Ssam #ifdef UPECCDEBUG
36510352Shelge 			printf("new: %x\n", (*addr&0xff));
3669974Ssam #endif
3679974Ssam 			byte++;
3689974Ssam 			i++;
3699974Ssam 			bit -= 8;
37010352Shelge 			if ((ecccnt++ >= MAXECC) && ((io->i_flgs&F_ECCLM) != 0))
37110352Shelge 				return(1);
3729974Ssam 		}
37310352Shelge 		return(0);
3749974Ssam #ifndef NOBADSECT
3759974Ssam 	} else if (flag == BSE) {
3769974Ssam 		/*
37710352Shelge 		 * if not in bad sector table, return 1 (= hard error)
3789974Ssam 		 */
37910352Shelge 		up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
38010410Shelge 		if ((bbn = isbad(&upbad[io->i_unit], cn, tn, sn)) < 0)
38110352Shelge 			return(1);
3829974Ssam 		bbn = st->ncyl * st->nspc -st->nsect - 1 - bbn;
38310352Shelge 		twc = up->upwc + sectsiz;
38410352Shelge 		up->upwc = -(sectsiz / sizeof (short));
3859974Ssam #ifdef UPECCDEBUG
3869974Ssam 		printf("revector to block %d\n", bbn);
3879974Ssam #endif
3889974Ssam 		/*
3899974Ssam 	 	* Clear the drive & read the replacement sector.
3909974Ssam 	 	* If this is in the middle of a transfer, then set up the
3919974Ssam 	 	* controller registers in a normal fashion.
3929974Ssam 	 	* The ub-address need not be changed.
3939974Ssam 	 	*/
39410023Ssam 		while (up->upcs1 & UP_RDY == 0)
3959974Ssam 			;
39610023Ssam 		if (upstart(io, bbn) != 0)
39710352Shelge 			return (1);		/* error */
39810352Shelge 		io->i_errcnt = 0;		/* success */
3999974Ssam 		do {
4009974Ssam 			DELAY(25);
4019974Ssam 		} while ( up->upcs1 & UP_RDY == 0) ;
4029974Ssam 		if (up->upds & UPDS_ERR || up->upcs1 & UP_TRE) {
40310352Shelge 			up->upwc = twc -sectsiz;
40410352Shelge 			return (1);
4059974Ssam 		}
4069974Ssam 	}
407*10638Shelge 	if (twc)
4089974Ssam 		up->upwc = twc;
40910352Shelge 	return (0);
4109974Ssam }
4119974Ssam 
4129974Ssam upstart(io, bn)
41310023Ssam 	register struct iob *io;
41410023Ssam 	daddr_t bn;
4159974Ssam {
4169974Ssam 	register struct updevice *upaddr =
41710023Ssam 		(struct updevice *)ubamem(io->i_unit, ubastd[0]);
41810352Shelge 	register struct st *st = &upst[up_type[io->i_unit]];
4199974Ssam 	int sn, tn;
4209974Ssam 
4219974Ssam 	sn = bn%st->nspc;
4229974Ssam 	tn = sn/st->nsect;
4239974Ssam 	sn %= st->nsect;
4249974Ssam 	upaddr->updc = bn/st->nspc;
4259974Ssam 	upaddr->upda = (tn << 8) + sn;
42610352Shelge 	switch (io->i_flgs & F_TYPEMASK) {
42710023Ssam 
42810023Ssam 	case F_RDDATA:
42910023Ssam 		upaddr->upcs1 = UP_RCOM|UP_GO;
4309974Ssam 		break;
43110023Ssam 
43210023Ssam 	case F_WRDATA:
43310023Ssam 		upaddr->upcs1 = UP_WCOM|UP_GO;
4349974Ssam 		break;
43510023Ssam 
43610023Ssam 	case F_HDR|F_RDDATA:
43710023Ssam 		upaddr->upcs1 = UP_RHDR|UP_GO;
43810023Ssam 		break;
43910023Ssam 
44010023Ssam 	case F_HDR|F_WRDATA:
44110023Ssam 		upaddr->upcs1 = UP_WHDR|UP_GO;
44210023Ssam 		break;
44310023Ssam 
44410023Ssam 	case F_CHECK|F_WRDATA:
44510023Ssam 	case F_CHECK|F_RDDATA:
4469974Ssam 		upaddr->upcs1 = UP_WCDATA|UP_GO;
4479974Ssam 		break;
44810023Ssam 
44910023Ssam 	case F_HCHECK|F_WRDATA:
45010023Ssam 	case F_HCHECK|F_RDDATA:
4519974Ssam 		upaddr->upcs1 = UP_WCHDR|UP_GO;
4529974Ssam 		break;
45310023Ssam 
4549974Ssam 	default:
45510023Ssam 		io->i_error = ECMD;
45610023Ssam 		io->i_flgs &= ~F_TYPEMASK;
45710023Ssam 		return (1);
4589974Ssam 	}
45910023Ssam 	return (0);
4609974Ssam }
4619974Ssam 
46210023Ssam /*ARGSUSED*/
46310023Ssam upioctl(io, cmd, arg)
46410023Ssam 	struct iob *io;
46510023Ssam 	int cmd;
46610023Ssam 	caddr_t arg;
46710023Ssam {
46810023Ssam 
46910352Shelge 	struct st *st = &upst[up_type[io->i_unit]], *tmp;
47010352Shelge 
47110352Shelge 	switch(cmd) {
47210352Shelge 
47310352Shelge 	case SAIODEVDATA:
47410352Shelge 		tmp = (struct st *)arg;
47510352Shelge 		*tmp = *st;
47610352Shelge 		return(0);
47710352Shelge 
47810352Shelge 	default:
47910352Shelge 		return (ECMD);
48010352Shelge 	}
48110023Ssam }
48210352Shelge 
483