1 /* hp.c 3.16 10/16/80 */ 2 3 /* 4 * RP06/RM03/RM05 disk driver 5 */ 6 7 #include "../h/param.h" 8 #include "../h/systm.h" 9 #include "../h/dk.h" 10 #include "../h/buf.h" 11 #include "../h/conf.h" 12 #include "../h/dir.h" 13 #include "../h/user.h" 14 #include "../h/map.h" 15 #include "../h/pte.h" 16 #include "../h/mba.h" 17 #include "../h/mtpr.h" 18 #include "../h/vm.h" 19 20 #define DK_N 0 21 #define DK_NMAX 1 22 23 struct device 24 { 25 int hpcs1; /* control and Status register 1 */ 26 int hpds; /* Drive Status */ 27 int hper1; /* Error register 1 */ 28 int hpmr; /* Maintenance */ 29 int hpas; /* Attention Summary */ 30 int hpda; /* Desired address register */ 31 int hpdt; /* Drive type */ 32 int hpla; /* Look ahead */ 33 int hpsn; /* serial number */ 34 int hpof; /* Offset register */ 35 int hpdc; /* Desired Cylinder address register */ 36 int hpcc; /* Current Cylinder */ 37 int hper2; /* Error register 2 */ 38 int hper3; /* Error register 3 */ 39 int hpec1; /* Burst error bit position */ 40 int hpec2; /* Burst error bit pattern */ 41 }; 42 43 #define HPMBA MBA0 44 #define HPMBANUM 0 45 46 #define NHP 2 47 #define RP 022 48 #define RM 024 49 #define RM5 027 50 #define NSECT 22 51 #define NTRAC 19 52 #define NRMSECT 32 53 #define NRMTRAC 5 54 55 #define _hpSDIST 3 56 #define _hpRDIST 6 57 58 int hpSDIST = _hpSDIST; 59 int hpRDIST = _hpRDIST; 60 int hpseek; 61 62 struct size 63 { 64 daddr_t nblocks; 65 int cyloff; 66 } hp_sizes[8] = 67 { 68 15884, 0, /* A=cyl 0 thru 37 */ 69 33440, 38, /* B=cyl 38 thru 117 */ 70 340670, 0, /* C=cyl 0 thru 814 */ 71 0, 0, 72 0, 0, 73 0, 0, 74 291346, 118, /* G=cyl 118 thru 814 */ 75 0, 0, 76 }, rm_sizes[8] = { 77 15884, 0, /* A=cyl 0 thru 99 */ 78 33440, 100, /* B=cyl 100 thru 309 */ 79 131680, 0, /* C=cyl 0 thru 822 */ 80 0, 0, 81 0, 0, 82 0, 0, 83 82080, 310, /* G=cyl 310 thru 822 */ 84 0, 0, 85 }, rm5_sizes[8] = { 86 15884, 0, /* A=cyl 0 thru 26 */ 87 33440, 27, /* B=cyl 27 thru 81 */ 88 500992, 0, /* C=cyl 0 thru 823 */ 89 15884, 562, /* D=cyl 562 thru 588 */ 90 55936, 589, /* E=cyl 589 thru 680 */ 91 86944, 681, /* F=cyl 681 thru 823 */ 92 159296, 562, /* G=cyl 562 thru 823 */ 93 291346, 82, /* H=cyl 82 thru 561 */ 94 }; 95 96 #define P400 020 97 #define M400 0220 98 #define P800 040 99 #define M800 0240 100 #define P1200 060 101 #define M1200 0260 102 int hp_offset[16] = 103 { 104 P400, M400, P400, M400, 105 P800, M800, P800, M800, 106 P1200, M1200, P1200, M1200, 107 0, 0, 0, 0, 108 }; 109 110 struct buf hptab; 111 struct buf rhpbuf; 112 struct buf hputab[NHP]; 113 char hp_type[NHP]; /* drive type */ 114 115 #define GO 01 116 #define PRESET 020 117 #define RTC 016 118 #define OFFSET 014 119 #define SEEK 04 120 #define SEARCH 030 121 #define RECAL 06 122 #define DCLR 010 123 #define WCOM 060 124 #define RCOM 070 125 126 #define IE 0100 127 #define PIP 020000 128 #define DRY 0200 129 #define ERR 040000 130 #define TRE 040000 131 #define DCK 0100000 132 #define WLE 04000 133 #define ECH 0100 134 #define VV 0100 135 #define DPR 0400 136 #define MOL 010000 137 #define FMT22 010000 138 139 #define b_cylin b_resid 140 141 #ifdef INTRLVE 142 daddr_t dkblock(); 143 #endif 144 145 hpstrategy(bp) 146 register struct buf *bp; 147 { 148 register struct buf *dp; 149 register unit, xunit, nspc; 150 long sz, bn; 151 struct size *sizes; 152 153 if ((mbaact&(1<<HPMBANUM)) == 0) 154 mbainit(HPMBANUM); 155 xunit = minor(bp->b_dev) & 077; 156 sz = bp->b_bcount; 157 sz = (sz+511) >> 9; 158 unit = dkunit(bp); 159 if (hp_type[unit] == 0) { 160 struct device *hpaddr; 161 double mspw; 162 163 /* determine device type */ 164 hpaddr = mbadev(HPMBA, unit); 165 166 /* record transfer rate (these are guesstimates secs/word) */ 167 switch (hp_type[unit] = hpaddr->hpdt) { 168 case RM: mspw = .0000019728; break; 169 case RM5: mspw = .0000020345; break; 170 case RP: mspw = .0000029592; break; 171 } 172 if (DK_N + unit <= DK_NMAX) 173 dk_mspw[DK_N+unit] = mspw; 174 } 175 switch (hp_type[unit]) { 176 177 case RM: 178 sizes = rm_sizes; 179 nspc = NRMSECT*NRMTRAC; 180 break; 181 case RM5: 182 sizes = rm5_sizes; 183 nspc = NRMSECT*NTRAC; 184 break; 185 case RP: 186 sizes = hp_sizes; 187 nspc = NSECT*NTRAC; 188 break; 189 default: 190 printf("hp: unknown device type 0%o\n", hp_type[unit]); 191 u.u_error = ENXIO; 192 unit = NHP+1; /* force error */ 193 } 194 if (unit >= NHP || 195 bp->b_blkno < 0 || 196 (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) { 197 bp->b_flags |= B_ERROR; 198 iodone(bp); 199 return; 200 } 201 bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff; 202 dp = &hputab[unit]; 203 (void) spl5(); 204 disksort(dp, bp); 205 if (dp->b_active == 0) { 206 hpustart(unit); 207 if(hptab.b_active == 0) 208 hpstart(); 209 } 210 (void) spl0(); 211 } 212 213 hpustart(unit) 214 register unit; 215 { 216 register struct buf *bp, *dp; 217 register struct device *hpaddr; 218 daddr_t bn; 219 int sn, cn, csn; 220 221 ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; 222 hpaddr = mbadev(HPMBA, 0); 223 hpaddr->hpas = 1<<unit; 224 225 if(unit >= NHP) 226 return; 227 if (unit+DK_N <= DK_NMAX) 228 dk_busy &= ~(1<<(unit+DK_N)); 229 dp = &hputab[unit]; 230 if((bp=dp->b_actf) == NULL) 231 return; 232 hpaddr = mbadev(HPMBA, unit); 233 if((hpaddr->hpds & VV) == 0) { 234 hpaddr->hpcs1 = PRESET|GO; 235 hpaddr->hpof = FMT22; 236 } 237 if(dp->b_active) 238 goto done; 239 dp->b_active++; 240 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) 241 goto done; 242 243 bn = dkblock(bp); 244 cn = bp->b_cylin; 245 switch (hp_type[unit]) { 246 247 case RM: 248 sn = bn%(NRMSECT*NRMTRAC); 249 sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 250 break; 251 case RM5: 252 sn = bn%(NRMSECT*NTRAC); 253 sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 254 break; 255 case RP: 256 sn = bn%(NSECT*NTRAC); 257 sn = (sn+NSECT-hpSDIST)%NSECT; 258 break; 259 default: 260 panic("hpustart"); 261 } 262 263 if(cn - (hpaddr->hpdc & 0xffff)) 264 goto search; 265 else if (hpseek) 266 goto done; 267 csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1; 268 if(csn < 0) 269 csn += NSECT; 270 if(csn > NSECT-hpRDIST) 271 goto done; 272 273 search: 274 hpaddr->hpdc = cn; 275 if (hpseek) 276 hpaddr->hpcs1 = SEEK|GO; 277 else { 278 hpaddr->hpda = sn; 279 hpaddr->hpcs1 = SEARCH|GO; 280 } 281 unit += DK_N; 282 if (unit <= DK_NMAX) { 283 dk_busy |= 1<<unit; 284 dk_seek[unit]++; 285 } 286 return; 287 288 done: 289 dp->b_forw = NULL; 290 if(hptab.b_actf == NULL) 291 hptab.b_actf = dp; 292 else 293 hptab.b_actl->b_forw = dp; 294 hptab.b_actl = dp; 295 } 296 297 hpstart() 298 { 299 register struct buf *bp, *dp; 300 register unit; 301 register struct device *hpaddr; 302 daddr_t bn; 303 int dn, sn, tn, cn, nspc, ns; 304 305 loop: 306 if ((dp = hptab.b_actf) == NULL) 307 return; 308 if ((bp = dp->b_actf) == NULL) { 309 hptab.b_actf = dp->b_forw; 310 goto loop; 311 } 312 hptab.b_active++; 313 unit = minor(bp->b_dev) & 077; 314 dn = dkunit(bp); 315 bn = dkblock(bp); 316 switch (hp_type[dn]) { 317 case RM: 318 nspc = NRMSECT*NRMTRAC; 319 ns = NRMSECT; 320 cn = rm_sizes[unit&07].cyloff; 321 break; 322 case RM5: 323 nspc = NRMSECT*NTRAC; 324 ns = NRMSECT; 325 cn = rm5_sizes[unit&07].cyloff; 326 break; 327 case RP: 328 nspc = NSECT*NTRAC; 329 ns = NSECT; 330 cn = hp_sizes[unit&07].cyloff; 331 break; 332 default: 333 panic("hpstart"); 334 } 335 cn += bn/nspc; 336 sn = bn%nspc; 337 tn = sn/ns; 338 sn = sn%ns; 339 340 hpaddr = mbadev(HPMBA, dn); 341 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) { 342 hptab.b_active = 0; 343 hptab.b_errcnt = 0; 344 dp->b_actf = bp->av_forw; 345 bp->b_flags |= B_ERROR; 346 iodone(bp); 347 goto loop; 348 } 349 if(hptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE) == 0) { 350 hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22; 351 HPMBA->mba_cr &= ~MBAIE; 352 hpaddr->hpcs1 = OFFSET|GO; 353 while(hpaddr->hpds & PIP) 354 ; 355 HPMBA->mba_cr |= MBAIE; 356 } 357 hpaddr->hpdc = cn; 358 hpaddr->hpda = (tn << 8) + sn; 359 mbastart(bp, (int *)hpaddr); 360 361 unit = dn+DK_N; 362 if (unit <= DK_NMAX) { 363 dk_busy |= 1<<unit; 364 dk_xfer[unit]++; 365 dk_wds[unit] += bp->b_bcount>>6; 366 } 367 } 368 369 hpintr(mbastat, as) 370 { 371 register struct buf *bp, *dp; 372 register unit; 373 register struct device *hpaddr; 374 375 if(hptab.b_active) { 376 dp = hptab.b_actf; 377 bp = dp->b_actf; 378 unit = dkunit(bp); 379 if (DK_N+unit <= DK_NMAX) 380 dk_busy &= ~(1<<(DK_N+unit)); 381 hpaddr = mbadev(HPMBA, unit); 382 if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { 383 while((hpaddr->hpds & DRY) == 0) 384 ; 385 if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE) 386 bp->b_flags |= B_ERROR; 387 else 388 hptab.b_active = 0; 389 if(hptab.b_errcnt > 27) 390 deverror(bp, mbastat, hpaddr->hper1); 391 if ((hpaddr->hper1&0xffff) == DCK) { 392 if (hpecc(hpaddr, bp)) 393 return; 394 } 395 hpaddr->hpcs1 = DCLR|GO; 396 if((hptab.b_errcnt&07) == 4) { 397 HPMBA->mba_cr &= ~MBAIE; 398 hpaddr->hpcs1 = RECAL|GO; 399 while(hpaddr->hpds & PIP) 400 ; 401 HPMBA->mba_cr |= MBAIE; 402 } 403 } 404 if(hptab.b_active) { 405 if(hptab.b_errcnt) { 406 HPMBA->mba_cr &= ~MBAIE; 407 hpaddr->hpcs1 = RTC|GO; 408 while(hpaddr->hpds & PIP) 409 ; 410 HPMBA->mba_cr |= MBAIE; 411 } 412 hptab.b_active = 0; 413 hptab.b_errcnt = 0; 414 hptab.b_actf = dp->b_forw; 415 dp->b_active = 0; 416 dp->b_errcnt = 0; 417 dp->b_actf = bp->av_forw; 418 bp->b_resid = -HPMBA->mba_bcr & 0xffff; 419 iodone(bp); 420 if(dp->b_actf) 421 hpustart(unit); 422 } 423 as &= ~(1<<unit); 424 } else { 425 if(as == 0) 426 HPMBA->mba_cr |= MBAIE; 427 } 428 for(unit=0; unit<NHP; unit++) 429 if(as & (1<<unit)) 430 hpustart(unit); 431 hpstart(); 432 } 433 434 hpread(dev) 435 { 436 437 physio(hpstrategy, &rhpbuf, dev, B_READ, minphys); 438 } 439 440 hpwrite(dev) 441 { 442 443 physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys); 444 } 445 446 hpecc(rp, bp) 447 register struct device *rp; 448 register struct buf *bp; 449 { 450 struct mba_regs *mbp = HPMBA; 451 register int i; 452 caddr_t addr; 453 int reg, bit, byte, npf, mask, o; 454 int dn, bn, cn, tn, sn, ns, nt; 455 extern char buffers[NBUF][BSIZE]; 456 struct pte mpte; 457 int bcr; 458 459 /* 460 * Npf is the number of sectors transferred before the sector 461 * containing the ECC error, and reg is the MBA register 462 * mapping (the first part of)the transfer. 463 * O is offset within a memory page of the first byte transferred. 464 */ 465 bcr = mbp->mba_bcr & 0xffff; 466 if (bcr) 467 bcr |= 0xffff0000; /* sxt */ 468 npf = btop(bcr + bp->b_bcount) - 1; 469 reg = npf; 470 o = (int)bp->b_un.b_addr & PGOFSET; 471 printf("%D ", bp->b_blkno + npf); 472 prdev("ECC", bp->b_dev); 473 mask = rp->hpec2&0xffff; 474 if (mask == 0) { 475 rp->hpof = FMT22; 476 return (0); 477 } 478 479 /* 480 * Compute the byte and bit position of the error. 481 * The variable i is the byte offset in the transfer, 482 * the variable byte is the offset from a page boundary 483 * in main memory. 484 */ 485 i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 486 bit = i&07; 487 i = (i&~07)>>3; 488 byte = i + o; 489 /* 490 * Correct while possible bits remain of mask. Since mask 491 * contains 11 bits, we continue while the bit offset is > -11. 492 * Also watch out for end of this block and the end of the whole 493 * transfer. 494 */ 495 while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 496 mpte = mbp->mba_map[reg+btop(byte)]; 497 addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 498 putmemc(addr, getmemc(addr)^(mask<<bit)); 499 byte++; 500 i++; 501 bit -= 8; 502 } 503 hptab.b_active++; /* Either complete or continuing */ 504 if (bcr == 0) 505 return (0); 506 /* 507 * Have to continue the transfer... clear the drive, 508 * and compute the position where the transfer is to continue. 509 * We have completed npf+1 sectores of the transfer already; 510 * restart at offset o of next sector (i.e. in MBA register reg+1). 511 */ 512 rp->hpcs1 = DCLR|GO; 513 dn = dkunit(bp); 514 bn = dkblock(bp); 515 switch (hp_type[dn]) { 516 517 case RM: 518 ns = NRMSECT; nt = NRMTRAC; break; 519 case RM5: 520 ns = NRMSECT; nt = NTRAC; break; 521 case RP: 522 ns = NSECT; nt = NTRAC; break; 523 default: 524 panic("hpecc"); 525 } 526 cn = bp->b_cylin; 527 sn = bn%(ns*nt) + npf + 1; 528 tn = sn/ns; 529 sn %= ns; 530 cn += tn/nt; 531 tn %= nt; 532 rp->hpdc = cn; 533 rp->hpda = (tn<<8) + sn; 534 mbp->mba_sr = -1; 535 mbp->mba_var = (int)ptob(reg+1) + o; 536 rp->hpcs1 = RCOM|GO; 537 return (1); 538 } 539