1 /* 2 * Copyright (c) 1982, 1986 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.2 (Berkeley) 01/28/88 7 */ 8 9 /* 10 * Standalone RL02 disk driver 11 */ 12 #include "../machine/pte.h" 13 14 #include "param.h" 15 #include "inode.h" 16 #include "fs.h" 17 18 #include "../vaxuba/rlreg.h" 19 #include "../vaxuba/ubareg.h" 20 21 #include "saio.h" 22 #include "savax.h" 23 24 u_short rlstd[] = { 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[] = { -1, 0, 0, 0}; 34 35 rlopen(io) 36 register struct iob *io; 37 { 38 register struct rldevice *rladdr = 39 (struct rldevice *)ubamem(io->i_unit, rlstd[0]); 40 register struct rl_stat *st = &rl_stat[0]; 41 register int ctr = 0; 42 43 if (badaddr((char *)rladdr, sizeof(short))) { 44 printf("nonexistent device\n"); 45 return (ENXIO); 46 } 47 if ((unsigned)io->i_boff > 7 || rl_off[io->i_boff] == -1) { 48 printf("rl bad unit\n"); 49 return (EUNIT); 50 } 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 (EUNIT); 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_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 86 st->rl_dn = io->i_unit; 87 88 /* byte offset for cylinder desired */ 89 io->i_boff = rl_off[io->i_boff] * NRLBPSC * NRLTRKS * NRLSECT; 90 return (0); 91 } 92 93 rlstrategy(io, func) 94 register struct iob *io; 95 { 96 register struct rldevice *rladdr = 97 (struct rldevice *)ubamem(io->i_unit, rlstd[0]); 98 register struct rl_stat *st = &rl_stat[0]; 99 int com; 100 daddr_t bn; 101 short cn, sn, head; 102 int diff, ubinfo, ubaddr, errcnt = 0; 103 104 retry: 105 ubinfo = ubasetup(io, 1); 106 bn = io->i_bn; /* block number */ 107 cn = bn / 40; /* 40 512 byte blocks per cylinder */ 108 sn = (bn % 20) << 1; 109 head = (bn / 20) & 1; 110 st->rl_bleft = io->i_cc; /* total number of bytes to trans */ 111 ubaddr = ubinfo; 112 113 stupid_rl: 114 /* find out how many cylinders to seek */ 115 diff = (st->rl_cylnhd >> 1) - cn; 116 if ( diff == 0 && (st->rl_cylnhd & 1) == head ) 117 goto noseek; 118 119 /* first time or we switched drives */ 120 st->rl_dn = io->i_unit; /* drive number */ 121 122 if ( diff < 0 ) 123 rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4; 124 else 125 rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4; 126 rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK; 127 128 /* reset position of drive */ 129 st->rl_cylnhd = (cn << 1) | head; 130 131 noseek: 132 /* wait for controller and drive */ 133 while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 134 continue; 135 136 /* calculate the max number of bytes we can trans */ 137 st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC); 138 if ( st->rl_bleft < st->rl_bpart ) 139 st->rl_bpart = st->rl_bleft; 140 141 rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn; 142 rladdr->rlmp.rw = -(st->rl_bpart >> 1); 143 rladdr->rlba = ubaddr; 144 145 com = (st->rl_dn << 8) | ((ubaddr>>12)&RL_BAE); 146 147 if (func == READ) 148 com |= RL_READ; 149 else 150 com |= RL_WRITE; 151 rladdr->rlcs = com; 152 153 /* wait for controller and drive */ 154 while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 155 continue; 156 157 if (rladdr->rlcs & RL_ERR) { 158 int status; 159 160 if ( rladdr->rlcs & RL_DE ) { 161 rladdr->rlda.getstat = RL_GSTAT; 162 rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT; 163 rlwait(rladdr); 164 status = rladdr->rlmp.getstat; 165 rladdr->rlda.getstat = RL_RESET; 166 rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT; 167 rlwait(rladdr); 168 } 169 printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n", 170 cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS, 171 status, RLER_BITS); 172 173 /* Determine disk posistion */ 174 rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR; 175 rlwait(rladdr); 176 177 /* save disk drive posistion */ 178 st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 179 180 if (errcnt == 10) { 181 printf("rl: unrecovered error\n"); 182 return (-1); 183 } 184 errcnt++; 185 goto retry; 186 } 187 188 /* do we have to finish off the rest of the transfer? */ 189 if ( (st->rl_bleft -= st->rl_bpart) > 0 ) { 190 /* increment head and/or cylinder */ 191 if ( ++head > 1 ) { 192 cn++; /* want next cyl, head 0 sector 0 */ 193 head = 0; 194 } 195 196 /* we always want sector to be zero */ 197 sn = 0; 198 199 /* 200 * standalone code for ubafree does what regular 201 * ubapurge does and we want to purge last transfer 202 */ 203 ubafree(io, ubinfo); 204 205 ubaddr = ubinfo + io->i_cc - st->rl_bleft; 206 207 goto stupid_rl; 208 } 209 210 ubafree(io, ubinfo); 211 212 if (errcnt) 213 printf("rl: recovered by retry\n"); 214 return (io->i_cc); 215 } 216 217 rlwait(rladdr) 218 register struct rldevice *rladdr; 219 { 220 221 while ((rladdr->rlcs & RL_CRDY) == 0) 222 continue; 223 } 224 225 rlioctl(io, cmd, arg) 226 struct iob *io; 227 int cmd; 228 caddr_t arg; 229 { 230 231 return (ECMD); 232 } 233