1 /* 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)rl.c 7.9 (Berkeley) 05/04/91 7 */ 8 9 /* 10 * Standalone RL02 disk driver 11 */ 12 13 #include "sys/param.h" 14 15 #include "../include/pte.h" 16 #include "../uba/rlreg.h" 17 #include "../uba/ubareg.h" 18 19 #include "stand/saio.h" 20 #include "savax.h" 21 22 #define MAXPART 8 23 #define MAXCTLR 1 /* all addresses must be specified */ 24 u_short rlstd[MAXCTLR] = { 0774400 }; 25 short rl_off[] = { 0, 361, 0, -1, -1, -1, -1, -1 }; 26 27 /* struct to keep state info about the controller */ 28 struct rl_stat { 29 short rl_dn; /* drive number */ 30 short rl_cylnhd; /* cylinder and head */ 31 u_short rl_bleft; /* bytes left to transfer */ 32 u_short rl_bpart; /* bytes transferred */ 33 } rl_stat[MAXCTLR] = { -1, 0, 0, 0 }; 34 35 rlopen(io) 36 register struct iob *io; 37 { 38 register struct rldevice *rladdr; 39 register struct rl_stat *st; 40 register int ctr = 0; 41 42 if ((u_int)io->i_adapt >= nuba) 43 return (EADAPT); 44 if ((u_int)io->i_ctlr >= MAXCTLR) 45 return (ECTLR); 46 rladdr = (struct rldevice *)ubamem(io->i_adapt, rlstd[io->i_ctlr]); 47 if (badaddr((char *)rladdr, sizeof(short))) 48 return (ENXIO); 49 if ((u_int)io->i_part >= MAXPART || rl_off[io->i_part] == -1) 50 return (EPART); 51 52 /* 53 * DEC reports that: 54 * For some unknown reason the RL02 (seems to be only drive 1) 55 * does not return a valid drive status the first time that a 56 * GET STATUS request is issued for the drive, in fact it can 57 * take up to three or more GET STATUS requests to obtain the 58 * correct status. 59 * In order to overcome this, the driver has been modified to 60 * issue a GET STATUS request and validate the drive status 61 * returned. If a valid status is not returned after eight 62 * attempts, then an error message is printed. 63 */ 64 do { 65 rladdr->rlda.getstat = RL_RESET; 66 rladdr->rlcs = (io->i_unit <<8) | RL_GETSTAT; /* Get status*/ 67 rlwait(rladdr); 68 } while ((rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8); 69 70 if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) { 71 printf("rl: unit does not respond\n"); 72 return (EUNIT); 73 } 74 75 if ((rladdr->rlmp.getstat & RLMP_DT) == 0) { /* NO RL01'S */ 76 printf("rl01 unit not supported\n"); 77 return (ENXIO); 78 } 79 80 /* Determine disk posistion */ 81 rladdr->rlcs = (io->i_unit << 8) | RL_RHDR; 82 rlwait(rladdr); 83 84 /* save disk drive posistion */ 85 st = &rl_stat[io->i_ctlr]; 86 st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 87 st->rl_dn = io->i_unit; 88 89 /* byte offset for cylinder desired */ 90 io->i_boff = rl_off[io->i_part] * NRLBPSC * NRLTRKS * NRLSECT; 91 return (0); 92 } 93 94 rlstrategy(io, func) 95 register struct iob *io; 96 { 97 register struct rldevice *rladdr; 98 register struct rl_stat *st; 99 int com; 100 daddr_t bn; 101 short cn, sn, head; 102 int diff, ubinfo, ubaaddr, errcnt = 0; 103 104 rladdr = (struct rldevice *)ubamem(io->i_adapt, rlstd[io->i_ctlr]); 105 st = &rl_stat[io->i_ctlr]; 106 retry: 107 ubinfo = ubasetup(io, 1); 108 bn = io->i_bn; /* block number */ 109 cn = bn / 40; /* 40 512 byte blocks per cylinder */ 110 sn = (bn % 20) << 1; 111 head = (bn / 20) & 1; 112 st->rl_bleft = io->i_cc; /* total number of bytes to trans */ 113 ubaaddr = ubinfo; 114 115 stupid_rl: 116 /* find out how many cylinders to seek */ 117 diff = (st->rl_cylnhd >> 1) - cn; 118 if (diff == 0 && (st->rl_cylnhd & 1) == head) 119 goto noseek; 120 121 /* first time or we switched drives */ 122 st->rl_dn = io->i_unit; /* drive number */ 123 124 if (diff < 0) 125 rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4; 126 else 127 rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4; 128 rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK; 129 130 /* reset position of drive */ 131 st->rl_cylnhd = (cn << 1) | head; 132 133 noseek: 134 /* wait for controller and drive */ 135 while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 136 continue; 137 138 /* calculate the max number of bytes we can trans */ 139 st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC); 140 if (st->rl_bleft < st->rl_bpart) 141 st->rl_bpart = st->rl_bleft; 142 143 rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn; 144 rladdr->rlmp.rw = -(st->rl_bpart >> 1); 145 rladdr->rlba = ubaaddr; 146 147 com = (st->rl_dn << 8) | ((ubaaddr>>12)&RL_BAE); 148 149 if (func == F_READ) 150 com |= RL_READ; 151 else 152 com |= RL_WRITE; 153 rladdr->rlcs = com; 154 155 /* wait for controller and drive */ 156 while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 157 continue; 158 159 if (rladdr->rlcs & RL_ERR) { 160 int status; 161 162 if (rladdr->rlcs & RL_DE) { 163 rladdr->rlda.getstat = RL_GSTAT; 164 rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT; 165 rlwait(rladdr); 166 status = rladdr->rlmp.getstat; 167 rladdr->rlda.getstat = RL_RESET; 168 rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT; 169 rlwait(rladdr); 170 } 171 printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n", 172 cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS, 173 status, RLER_BITS); 174 175 /* Determine disk posistion */ 176 rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR; 177 rlwait(rladdr); 178 179 /* save disk drive posistion */ 180 st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 181 182 if (errcnt++ == 10) { 183 printf("rl: unrecovered error\n"); 184 return (-1); 185 } 186 goto retry; 187 } 188 189 /* do we have to finish off the rest of the transfer? */ 190 if ((st->rl_bleft -= st->rl_bpart) > 0) { 191 /* increment head and/or cylinder */ 192 if (++head > 1) { 193 cn++; /* want next cyl, head 0 sector 0 */ 194 head = 0; 195 } 196 197 /* we always want sector to be zero */ 198 sn = 0; 199 200 /* 201 * standalone code for ubafree does what regular 202 * ubapurge does and we want to purge last transfer 203 */ 204 ubafree(io, ubinfo); 205 206 ubaaddr = ubinfo + io->i_cc - st->rl_bleft; 207 208 goto stupid_rl; 209 } 210 211 ubafree(io, ubinfo); 212 213 if (errcnt) 214 printf("rl: recovered by retry\n"); 215 return (io->i_cc); 216 } 217 218 static 219 rlwait(rladdr) 220 register struct rldevice *rladdr; 221 { 222 while ((rladdr->rlcs & RL_CRDY) == 0); 223 } 224