1 /* up.c 4.8 83/02/18 */ 2 3 /* 4 * UNIBUS peripheral standalone driver 5 * with ECC correction and bad block forwarding. 6 * Also supports header operation and write 7 * check for data and/or header. 8 */ 9 10 #include "../h/param.h" 11 #include "../h/inode.h" 12 #include "../h/fs.h" 13 #include "../h/dkbad.h" 14 #include "../h/vmmac.h" 15 16 #include "../vax/pte.h" 17 #include "../vaxuba/upreg.h" 18 #include "../vaxuba/ubareg.h" 19 20 #include "saio.h" 21 #include "savax.h" 22 23 #define MAXBADDESC 126 /* max number of bad sectors recorded */ 24 #define SECTSIZ 512 /* sector size in bytes */ 25 #define HDRSIZ 4 /* number of bytes in sector header */ 26 #define MAXECC 5 /* max # bad bits allowed on ecc w/ F_ECCLM */ 27 28 u_short ubastd[] = { 0776700 }; 29 30 char up_gottype[MAXNUBA*8] = { 0 }; 31 char up_type[MAXNUBA*8] = { 0 }; 32 extern struct st upst[]; 33 34 u_char up_offset[16] = { 35 UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 36 UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 37 UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 38 0, 0, 0, 0 39 }; 40 41 struct dkbad upbad[MAXNUBA*8]; /* bad sector table */ 42 int sectsiz; /* real sector size */ 43 44 upopen(io) 45 register struct iob *io; 46 { 47 register unit = io->i_unit; 48 register struct updevice *upaddr; 49 register struct st *st; 50 51 if (io->i_boff < 0 || io->i_boff > 7) 52 _stop("up bad unit"); 53 upaddr = (struct updevice *)ubamem(unit, ubastd[0]); 54 while ((upaddr->upcs1 & UP_DVA) == 0) 55 ; 56 if (up_gottype[unit] == 0) { 57 register int i; 58 struct iob tio; 59 60 up_type[unit] = upmaptype(unit, upaddr); 61 if (up_type[unit] < 0) 62 _stop("unknown drive type"); 63 st = &upst[up_type[unit]]; 64 if (st->off[io->i_boff] == -1) 65 _stop("up bad unit"); 66 /* 67 * Read in the bad sector table: 68 * copy the contents of the io structure 69 * to tio for use during the bb pointer 70 * read operation. 71 */ 72 tio = *io; 73 tio.i_bn = st->nspc * st->ncyl - st->nsect; 74 tio.i_ma = (char *)&upbad[tio.i_unit]; 75 tio.i_cc = sizeof (struct dkbad); 76 tio.i_flgs |= F_RDDATA; 77 for (i = 0; i < 5; i++) { 78 if (upstrategy(&tio, READ) == sizeof (struct dkbad)) 79 break; 80 tio.i_bn += 2; 81 } 82 if (i == 5) { 83 printf("Unable to read bad sector table\n"); 84 for (i = 0; i < MAXBADDESC; i++) { 85 upbad[unit].bt_bad[i].bt_cyl = -1; 86 upbad[unit].bt_bad[i].bt_trksec = -1; 87 } 88 } 89 up_gottype[unit] = 1; 90 } 91 io->i_boff = st->off[io->i_boff] * st->nspc; 92 io->i_flgs &= ~F_TYPEMASK; 93 } 94 95 upstrategy(io, func) 96 register struct iob *io; 97 { 98 int cn, tn, sn; 99 register unit = io->i_unit; 100 daddr_t bn; 101 int recal, info, waitdry; 102 register struct updevice *upaddr = 103 (struct updevice *)ubamem(unit, ubastd[0]); 104 register struct st *st = &upst[up_type[unit]]; 105 106 sectsiz = SECTSIZ; 107 if (io->i_flgs & (F_HDR|F_HCHECK)) 108 sectsiz += HDRSIZ; 109 upaddr->upcs2 = unit; 110 if ((upaddr->upds & UPDS_VV) == 0) { 111 upaddr->upcs1 = UP_DCLR|UP_GO; 112 upaddr->upcs1 = UP_PRESET|UP_GO; 113 upaddr->upof = UPOF_FMT22; 114 } 115 if ((upaddr->upds & UPDS_DREADY) == 0) 116 _stop("up not ready"); 117 info = ubasetup(io, 1); 118 upaddr->upwc = -io->i_cc / sizeof (short); 119 upaddr->upba = info; 120 recal = 0; 121 io->i_errcnt = 0; 122 123 restart: 124 bn = io->i_bn + (io->i_cc + upaddr->upwc * sizeof(short)) / sectsiz; 125 while((upaddr->upds & UPDS_DRY) == 0) 126 ; 127 if (upstart(io, bn) != 0) { 128 ubafree(io, info); 129 return (-1); 130 } 131 do { 132 DELAY(25); 133 } while ((upaddr->upcs1 & UP_RDY) == 0); 134 /* 135 * If transfer has completed, free UNIBUS 136 * resources and return transfer size. 137 */ 138 if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0) { 139 ubafree(io, info); 140 return (io->i_cc); 141 } 142 #ifdef LOGALLERRS 143 printf("uper: (c,t,s)=(%d,%d,%d) cs2=%b er1=%b er2=%b wc=%x\n", 144 upaddr->updc, upaddr->upda>>8, (upaddr->upda&0x1f-1), 145 upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 146 UPER1_BITS, upaddr->uper2, UPER2_BITS,-upaddr->upwc); 147 #endif 148 waitdry = 0; 149 while ((upaddr->upds & UPDS_DRY) == 0 && ++waitdry < sectsiz) 150 DELAY(5); 151 if (upaddr->uper1&UPER1_WLE) { 152 /* 153 * Give up on write locked devices immediately. 154 */ 155 printf("up%d: write locked\n", unit); 156 return (-1); 157 } 158 if (++io->i_errcnt > 27) { 159 /* 160 * After 28 retries (16 without offset, and 161 * 12 with offset positioning) give up. 162 */ 163 io->i_error = EHER; 164 if (upaddr->upcs2 & UPCS2_WCE) 165 io->i_error = EWCK; 166 hard: 167 bn = io->i_bn + 168 (io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz; 169 cn = bn/st->nspc; 170 sn = bn%st->nspc; 171 tn = sn/st->nsect; 172 sn = sn%st->nsect; 173 printf( 174 "up error: (cyl,trk,sec)=(%d,%d,%d) cs2=%b er1=%b er2=%b\n", 175 cn, tn, sn, 176 upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 177 UPER1_BITS, upaddr->uper2, UPER2_BITS); 178 upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; 179 io->i_errblk = bn; 180 return (io->i_cc + upaddr->upwc * sizeof(short)); 181 } 182 if (upaddr->uper2 & UPER2_BSE) { 183 if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0) 184 goto success; 185 io->i_error = EBSE; 186 goto hard; 187 } 188 /* 189 * Retriable error. 190 * If a soft ecc, correct it 191 * Otherwise fall through and retry the transfer 192 */ 193 if (upaddr->uper1 & UPER1_DCK) { 194 /* 195 * If a write check command is active, all 196 * ecc errors give UPER1_ECH. 197 */ 198 if ((upaddr->uper1 & UPER1_ECH) == 0 || 199 (upaddr->upcs2 & UPCS2_WCE)) { 200 if (upecc(io, ECC) == 0) 201 goto success; 202 io->i_error = EECC; 203 goto hard; 204 } 205 } 206 /* 207 * Clear drive error and, every eight attempts, 208 * (starting with the fourth) 209 * recalibrate to clear the slate. 210 */ 211 upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; 212 if ((io->i_errcnt&07) == 4 ) { 213 upaddr->upcs1 = UP_RECAL|UP_GO; 214 recal = 1; 215 goto restart; 216 } 217 /* 218 * Advance recalibration finite state machine 219 * if recalibrate in progress, through 220 * RECAL 221 * SEEK 222 * OFFSET (optional) 223 * RETRY 224 */ 225 switch (recal) { 226 227 case 1: 228 upaddr->updc = cn; 229 upaddr->upcs1 = UP_SEEK|UP_GO; 230 recal = 2; 231 goto restart; 232 233 case 2: 234 if (io->i_errcnt < 16 || (func & READ) == 0) 235 goto donerecal; 236 upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22; 237 upaddr->upcs1 = UP_OFFSET|UP_GO; 238 recal = 3; 239 goto restart; 240 241 donerecal: 242 case 3: 243 recal = 0; 244 break; 245 } 246 /* 247 * If we were offset positioning, 248 * return to centerline. 249 */ 250 if (io->i_errcnt >= 16) { 251 upaddr->upof = UPOF_FMT22; 252 upaddr->upcs1 = UP_RTC|UP_GO; 253 while ((upaddr->upds&UPDS_DRY) == 0) 254 DELAY(25); 255 } 256 goto restart; 257 258 success: 259 if (upaddr->upwc != 0) 260 goto restart; 261 /* 262 * Release unibus 263 */ 264 ubafree(io, info); 265 return (io->i_cc); 266 } 267 268 /* 269 * Correct an ECC error, and restart the 270 * i/o to complete the transfer (if necessary). 271 * This is quite complicated because the transfer 272 * may be going to an odd memory address base and/or 273 * across a page boundary. 274 */ 275 upecc(io, flag) 276 register struct iob *io; 277 int flag; 278 { 279 register struct updevice *up = 280 (struct updevice *)ubamem(io->i_unit, ubastd[0]); 281 register struct st *st; 282 register int i; 283 caddr_t addr; 284 int bn, twc, npf, mask, cn, tn, sn; 285 daddr_t bbn; 286 287 /* 288 * Npf is the number of sectors transferred 289 * before the sector containing the ECC error; 290 * bn is the current block number. 291 */ 292 twc = up->upwc; 293 npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz; 294 #ifdef UPECCDEBUG 295 printf("npf %d mask 0x%x pos %d wc 0x%x\n", 296 npf, up->ec2, up->upec1, -twc); 297 #endif 298 bn = io->i_bn + npf ; 299 st = &upst[up_type[io->i_unit]]; 300 cn = bn/st->nspc; 301 sn = bn%st->nspc; 302 tn = sn/st->nsect; 303 sn = sn%st->nsect; 304 305 /* 306 * ECC correction. 307 */ 308 if (flag == ECC) { 309 int bit, byte, ecccnt; 310 311 ecccnt = 0; 312 mask = up->upec2; 313 printf("up%d: soft ecc sn%d\n", io->i_unit, bn); 314 /* 315 * Compute the byte and bit position 316 * of the error. i is the byte offset 317 * in the transfer at which the correction 318 * is first applied. 319 */ 320 i = up->upec1 - 1; /* -1 makes 0 origin */ 321 bit = i&07; 322 i = (i&~07)>>3; 323 byte = i; 324 up->upcs1 = UP_TRE|UP_DCLR|UP_GO; 325 /* 326 * Correct while possible bits remain of mask. 327 * Since mask contains 11 bits, we continue while 328 * the bit offset is > -11. Also watch out for 329 * end of this block and the end of the transfer. 330 */ 331 while (i < sectsiz && (npf*sectsiz)+i < io->i_cc && bit > -11) { 332 /* 333 * addr = 334 * vax base addr + 335 * (# sectors transferred before the error) * 336 * (sector size) + 337 * byte number 338 */ 339 addr = io->i_ma + (npf * sectsiz) + byte; 340 #ifdef UPECCDEBUG 341 printf("addr %x old: %x ",addr, (*addr&0xff)); 342 #endif 343 if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) 344 *addr ^= (mask << bit); 345 #ifdef UPECCDEBUG 346 printf("new: %x\n", (*addr&0xff)); 347 #endif 348 byte++, i++; 349 bit -= 8; 350 if ((io->i_flgs&F_ECCLM) && ++ecccnt > MAXECC) 351 return (1); 352 } 353 return (0); 354 } 355 356 /* 357 * Bad sector forwarding. 358 */ 359 if (flag == BSE) { 360 /* 361 * If not in bad sector table, 362 * indicate a hard error to caller. 363 */ 364 up->upcs1 = UP_TRE|UP_DCLR|UP_GO; 365 if ((bbn = isbad(&upbad[io->i_unit], cn, tn, sn)) < 0) 366 return (1); 367 bbn = st->ncyl * st->nspc -st->nsect - 1 - bbn; 368 twc = up->upwc + sectsiz; 369 up->upwc = - (sectsiz / sizeof (short)); 370 #ifdef UPECCDEBUG 371 printf("revector to block %d\n", bbn); 372 #endif 373 /* 374 * Clear the drive & read the replacement 375 * sector. If this is in the middle of a 376 * transfer, then set up the controller 377 * registers in a normal fashion. 378 * The UNIBUS address need not be changed. 379 */ 380 while (up->upcs1 & UP_RDY == 0) 381 ; 382 if (upstart(io, bbn) != 0) 383 return (1); /* error */ 384 io->i_errcnt = 0; /* success */ 385 do { 386 DELAY(25); 387 } while ( up->upcs1 & UP_RDY == 0) ; 388 if (up->upds & UPDS_ERR || up->upcs1 & UP_TRE) { 389 up->upwc = twc -sectsiz; 390 return (1); 391 } 392 } 393 if (twc) 394 up->upwc = twc; 395 return (0); 396 } 397 398 upstart(io, bn) 399 register struct iob *io; 400 daddr_t bn; 401 { 402 register struct updevice *upaddr = 403 (struct updevice *)ubamem(io->i_unit, ubastd[0]); 404 register struct st *st = &upst[up_type[io->i_unit]]; 405 int sn, tn; 406 407 sn = bn%st->nspc; 408 tn = sn/st->nsect; 409 sn %= st->nsect; 410 upaddr->updc = bn/st->nspc; 411 upaddr->upda = (tn << 8) + sn; 412 switch (io->i_flgs & F_TYPEMASK) { 413 414 case F_RDDATA: 415 upaddr->upcs1 = UP_RCOM|UP_GO; 416 break; 417 418 case F_WRDATA: 419 upaddr->upcs1 = UP_WCOM|UP_GO; 420 break; 421 422 case F_HDR|F_RDDATA: 423 upaddr->upcs1 = UP_RHDR|UP_GO; 424 break; 425 426 case F_HDR|F_WRDATA: 427 upaddr->upcs1 = UP_WHDR|UP_GO; 428 break; 429 430 case F_CHECK|F_WRDATA: 431 case F_CHECK|F_RDDATA: 432 upaddr->upcs1 = UP_WCDATA|UP_GO; 433 break; 434 435 case F_HCHECK|F_WRDATA: 436 case F_HCHECK|F_RDDATA: 437 upaddr->upcs1 = UP_WCHDR|UP_GO; 438 break; 439 440 default: 441 io->i_error = ECMD; 442 io->i_flgs &= ~F_TYPEMASK; 443 return (1); 444 } 445 return (0); 446 } 447 448 /*ARGSUSED*/ 449 upioctl(io, cmd, arg) 450 struct iob *io; 451 int cmd; 452 caddr_t arg; 453 { 454 struct st *st = &upst[up_type[io->i_unit]], *tmp; 455 456 switch(cmd) { 457 458 case SAIODEVDATA: 459 tmp = (struct st *)arg; 460 *tmp = *st; 461 return (0); 462 } 463 return (ECMD); 464 } 465