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