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