xref: /csrg-svn/sys/vax/stand/rl.c (revision 11111)
1*11111Ssam /*	rl.c	4.2	83/02/16	*/
210775Ssam 
310775Ssam /*
410775Ssam  * Standalone RL02 disk driver
510775Ssam  */
610775Ssam #include "../machine/pte.h"
710775Ssam 
810775Ssam #include "../h/param.h"
910775Ssam #include "../h/inode.h"
1010775Ssam #include "../h/fs.h"
1110775Ssam 
1210775Ssam #include "../vaxuba/rlreg.h"
1310775Ssam #include "../vaxuba/ubareg.h"
1410775Ssam 
1510775Ssam #include "saio.h"
1610775Ssam #include "savax.h"
1710775Ssam 
1810775Ssam u_short	rlstd[] = { 0774400 };
1910775Ssam short	rl_off[] = { 0, 361, 0, -1, -1, -1, -1, -1 };
2010775Ssam 
2110775Ssam /* struct to keep state info about the controller */
2210775Ssam struct	rl_stat {
2310775Ssam 	short	rl_dn;		/* drive number */
2410775Ssam 	short	rl_cylnhd;	/* cylinder and head */
2510775Ssam 	u_short	rl_bleft;	/* bytes left to transfer */
2610775Ssam 	u_short	rl_bpart;	/* bytes transferred */
2710775Ssam } rl_stat[] = { -1, 0, 0, 0};
2810775Ssam 
2910775Ssam rlopen(io)
3010775Ssam 	register struct iob *io;
3110775Ssam {
3210775Ssam 	register struct rldevice *rladdr =
3310775Ssam 		(struct rldevice *)ubamem(io->i_unit, rlstd[0]);
3410775Ssam 	register struct rl_stat *st = &rl_stat[0];
3510775Ssam 	register int ctr = 0;
3610775Ssam 
3710775Ssam 	if (rl_off[io->i_boff] == -1 ||
3810775Ssam 	    io->i_boff < 0 || io->i_boff > 7)
3910775Ssam 		_stop("rl bad unit");
4010775Ssam 
4110775Ssam 	/*
4210775Ssam 	 * DEC reports that:
4310775Ssam 	 * For some unknown reason the RL02 (seems to be only drive 1)
4410775Ssam 	 * does not return a valid drive status the first time that a
4510775Ssam 	 * GET STATUS request is issued for the drive, in fact it can
4610775Ssam 	 * take up to three or more GET STATUS requests to obtain the
4710775Ssam 	 * correct status.
4810775Ssam 	 * In order to overcome this, the driver has been modified to
4910775Ssam 	 * issue a GET STATUS request and validate the drive status
5010775Ssam 	 * returned.  If a valid status is not returned after eight
5110775Ssam 	 * attempts, then an error message is printed.
5210775Ssam 	 */
5310775Ssam 	do {
5410775Ssam 		rladdr->rlda.getstat = RL_RESET;
5510775Ssam 		rladdr->rlcs = (io->i_unit <<8) | RL_GETSTAT; /* Get status*/
5610775Ssam 		rlwait(rladdr);
5710775Ssam 	} while( (rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8 );
5810775Ssam 
5910775Ssam 	if ((rladdr->rlcs & RL_DE) || (ctr >= 8))
6010775Ssam 		_stop("rl unit does not respond");
6110775Ssam 
6210775Ssam 	if ((rladdr->rlmp.getstat & RLMP_DT) == 0 )	/* NO RL01'S */
6310775Ssam 		_stop("rl01 unit not supported");
6410775Ssam 
6510775Ssam 	/* Determine disk posistion */
6610775Ssam 	rladdr->rlcs = (io->i_unit << 8) | RL_RHDR;
6710775Ssam 	rlwait(rladdr);
6810775Ssam 
6910775Ssam 	/* save disk drive posistion */
7010775Ssam 	st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6;
7110775Ssam 	st->rl_dn = io->i_unit;
7210775Ssam 
7310775Ssam 	/* byte offset for cylinder desired */
7410775Ssam 	io->i_boff = rl_off[io->i_boff] * NRLBPSC * NRLTRKS * NRLSECT;
7510775Ssam }
7610775Ssam 
7710775Ssam rlstrategy(io, func)
7810775Ssam 	register struct iob *io;
7910775Ssam {
8010775Ssam 	register struct rldevice *rladdr =
8110775Ssam 		(struct rldevice *)ubamem(io->i_unit, rlstd[0]);
8210775Ssam 	register struct rl_stat *st = &rl_stat[0];
8310775Ssam 	int com;
8410775Ssam 	daddr_t bn;
8510775Ssam 	short cn, sn, head;
8610775Ssam 	int diff, ubinfo, ubaddr, errcnt = 0;
8710775Ssam 
8810775Ssam retry:
8910775Ssam 	ubinfo = ubasetup(io, 1);
9010775Ssam 	bn = io->i_bn;		/* block number */
9110775Ssam 	cn = bn / 40;		/* 40 512 byte blocks per cylinder */
9210775Ssam 	sn = (bn % 20) << 1;
9310775Ssam 	head = (bn / 20) & 1;
9410775Ssam 	st->rl_bleft = io->i_cc;	/* total number of bytes to trans */
9510775Ssam 	ubaddr = ubinfo;
9610775Ssam 
9710775Ssam stupid_rl:
9810775Ssam 	/* find out how many cylinders to seek */
9910775Ssam 	diff = (st->rl_cylnhd >> 1) - cn;
10010775Ssam 	if ( diff == 0 && (st->rl_cylnhd & 1) == head )
10110775Ssam 		goto noseek;
10210775Ssam 
10310775Ssam 	/* first time or we switched drives */
10410775Ssam 	st->rl_dn = io->i_unit;	/* drive number */
10510775Ssam 
10610775Ssam 	if ( diff < 0 )
10710775Ssam 		rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4;
10810775Ssam 	else
10910775Ssam 		rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4;
11010775Ssam 	rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK;
11110775Ssam 
11210775Ssam 	/* reset position of drive */
11310775Ssam 	st->rl_cylnhd = (cn << 1) | head;
11410775Ssam 
11510775Ssam noseek:
11610775Ssam 	/* wait for controller and drive */
11710775Ssam 	while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY)
11810775Ssam 		continue;
11910775Ssam 
12010775Ssam 	/* calculate the max number of bytes we can trans */
12110775Ssam 	st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC);
12210775Ssam 	if ( st->rl_bleft < st->rl_bpart )
12310775Ssam 		st->rl_bpart = st->rl_bleft;
12410775Ssam 
12510775Ssam 	rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn;
12610775Ssam 	rladdr->rlmp.rw = -(st->rl_bpart >> 1);
12710775Ssam 	rladdr->rlba = ubaddr;
12810775Ssam 
12910775Ssam 	com = (st->rl_dn << 8) | ((ubaddr>>12)&RL_BAE);
13010775Ssam 
13110775Ssam 	if (func == READ)
13210775Ssam 		com |= RL_READ;
13310775Ssam 	else
13410775Ssam 		com |= RL_WRITE;
13510775Ssam 	rladdr->rlcs = com;
13610775Ssam 
13710775Ssam 	/* wait for controller and drive */
13810775Ssam 	while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY)
13910775Ssam 		continue;
14010775Ssam 
14110775Ssam 	if (rladdr->rlcs & RL_ERR) {
14210775Ssam 		int status;
14310775Ssam 
14410775Ssam 		if ( rladdr->rlcs & RL_DE ) {
14510775Ssam 			rladdr->rlda.getstat = RL_GSTAT;
14610775Ssam 			rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT;
14710775Ssam 			rlwait(rladdr);
14810775Ssam 			status = rladdr->rlmp.getstat;
14910775Ssam 			rladdr->rlda.getstat = RL_RESET;
15010775Ssam 			rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT;
15110775Ssam 			rlwait(rladdr);
15210775Ssam 		}
15310775Ssam 		printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n",
15410775Ssam 		    cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS,
15510775Ssam 		    status, RLER_BITS);
15610775Ssam 
15710775Ssam 		/* Determine disk posistion */
15810775Ssam 		rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR;
15910775Ssam 		rlwait(rladdr);
16010775Ssam 
16110775Ssam 		/* save disk drive posistion */
16210775Ssam 		st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6;
16310775Ssam 
16410775Ssam 		if (errcnt == 10) {
16510775Ssam 			printf("rl: unrecovered error\n");
16610775Ssam 			return (-1);
16710775Ssam 		}
16810775Ssam 		errcnt++;
16910775Ssam 		goto retry;
17010775Ssam 	}
17110775Ssam 
17210775Ssam 	/* do we have to finish off the rest of the transfer? */
17310775Ssam 	if ( (st->rl_bleft -= st->rl_bpart) > 0 ) {
17410775Ssam 		/* increment head and/or cylinder */
17510775Ssam 		if ( ++head > 1 ) {
17610775Ssam 			cn++;		/* want next cyl, head 0 sector 0 */
17710775Ssam 			head = 0;
17810775Ssam 		}
17910775Ssam 
18010775Ssam 		/* we always want sector to be zero */
18110775Ssam 		sn = 0;
18210775Ssam 
18310775Ssam 		/*
18410775Ssam 		 * standalone code for ubafree does what regular
18510775Ssam 		 *   ubapurge does and we want to purge last transfer
18610775Ssam 		 */
18710775Ssam 		ubafree(io, ubinfo);
18810775Ssam 
18910775Ssam 		ubaddr = ubinfo + io->i_cc - st->rl_bleft;
19010775Ssam 
19110775Ssam 		goto stupid_rl;
19210775Ssam 	}
19310775Ssam 
19410775Ssam 	ubafree(io, ubinfo);
19510775Ssam 
19610775Ssam 	if (errcnt)
19710775Ssam 		printf("rl: recovered by retry\n");
19810775Ssam 	return (io->i_cc);
19910775Ssam }
20010775Ssam 
20110775Ssam rlwait(rladdr)
20210775Ssam 	register struct rldevice *rladdr;
20310775Ssam {
20410775Ssam 
20510775Ssam 	while ((rladdr->rlcs & RL_CRDY) == 0)
20610775Ssam 		continue;
20710775Ssam }
208*11111Ssam 
209*11111Ssam rlioctl(io, cmd, arg)
210*11111Ssam 	struct iob *io;
211*11111Ssam 	int cmd;
212*11111Ssam 	caddr_t arg;
213*11111Ssam {
214*11111Ssam 
215*11111Ssam 	return (ECMD);
216*11111Ssam }
217