1 /* hp.c 3.14 09/27/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 162 /* determine device type */ 163 hpaddr = mbadev(HPMBA, unit); 164 hp_type[unit] = hpaddr->hpdt; 165 } 166 switch (hp_type[unit]) { 167 168 case RM: 169 sizes = rm_sizes; 170 nspc = NRMSECT*NRMTRAC; 171 break; 172 case RM5: 173 sizes = rm5_sizes; 174 nspc = NRMSECT*NTRAC; 175 break; 176 case RP: 177 sizes = hp_sizes; 178 nspc = NSECT*NTRAC; 179 break; 180 default: 181 printf("hp: unknown device type 0%o\n", hp_type[unit]); 182 u.u_error = ENXIO; 183 unit = NHP+1; /* force error */ 184 } 185 if (unit >= NHP || 186 bp->b_blkno < 0 || 187 (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) { 188 bp->b_flags |= B_ERROR; 189 iodone(bp); 190 return; 191 } 192 bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff; 193 dp = &hputab[unit]; 194 (void) spl5(); 195 disksort(dp, bp); 196 if (dp->b_active == 0) { 197 hpustart(unit); 198 if(hptab.b_active == 0) 199 hpstart(); 200 } 201 (void) spl0(); 202 } 203 204 hpustart(unit) 205 register unit; 206 { 207 register struct buf *bp, *dp; 208 register struct device *hpaddr; 209 daddr_t bn; 210 int sn, cn, csn; 211 212 ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; 213 hpaddr = mbadev(HPMBA, 0); 214 hpaddr->hpas = 1<<unit; 215 216 if(unit >= NHP) 217 return; 218 if (unit+DK_N <= DK_NMAX) 219 dk_busy &= ~(1<<(unit+DK_N)); 220 dp = &hputab[unit]; 221 if((bp=dp->b_actf) == NULL) 222 return; 223 hpaddr = mbadev(HPMBA, unit); 224 if((hpaddr->hpds & VV) == 0) { 225 hpaddr->hpcs1 = PRESET|GO; 226 hpaddr->hpof = FMT22; 227 } 228 if(dp->b_active) 229 goto done; 230 dp->b_active++; 231 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) 232 goto done; 233 234 bn = dkblock(bp); 235 cn = bp->b_cylin; 236 switch (hp_type[unit]) { 237 238 case RM: 239 sn = bn%(NRMSECT*NRMTRAC); 240 sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 241 break; 242 case RM5: 243 sn = bn%(NRMSECT*NTRAC); 244 sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 245 break; 246 case RP: 247 sn = bn%(NSECT*NTRAC); 248 sn = (sn+NSECT-hpSDIST)%NSECT; 249 break; 250 default: 251 panic("hpustart"); 252 } 253 254 if(cn - (hpaddr->hpdc & 0xffff)) 255 goto search; 256 else if (hpseek) 257 goto done; 258 csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1; 259 if(csn < 0) 260 csn += NSECT; 261 if(csn > NSECT-hpRDIST) 262 goto done; 263 264 search: 265 hpaddr->hpdc = cn; 266 if (hpseek) 267 hpaddr->hpcs1 = SEEK|GO; 268 else { 269 hpaddr->hpda = sn; 270 hpaddr->hpcs1 = SEARCH|GO; 271 } 272 unit += DK_N; 273 if (unit <= DK_NMAX && DK_N+NHP <= DK_NMAX) { 274 dk_busy |= 1<<unit; 275 dk_numb[unit]++; 276 } 277 return; 278 279 done: 280 dp->b_forw = NULL; 281 if(hptab.b_actf == NULL) 282 hptab.b_actf = dp; 283 else 284 hptab.b_actl->b_forw = dp; 285 hptab.b_actl = dp; 286 } 287 288 hpstart() 289 { 290 register struct buf *bp, *dp; 291 register unit; 292 register struct device *hpaddr; 293 daddr_t bn; 294 int dn, sn, tn, cn, nspc, ns; 295 296 loop: 297 if ((dp = hptab.b_actf) == NULL) 298 return; 299 if ((bp = dp->b_actf) == NULL) { 300 hptab.b_actf = dp->b_forw; 301 goto loop; 302 } 303 hptab.b_active++; 304 unit = minor(bp->b_dev) & 077; 305 dn = dkunit(bp); 306 bn = dkblock(bp); 307 switch (hp_type[dn]) { 308 case RM: 309 nspc = NRMSECT*NRMTRAC; 310 ns = NRMSECT; 311 cn = rm_sizes[unit&07].cyloff; 312 break; 313 case RM5: 314 nspc = NRMSECT*NTRAC; 315 ns = NRMSECT; 316 cn = rm5_sizes[unit&07].cyloff; 317 break; 318 case RP: 319 nspc = NSECT*NTRAC; 320 ns = NSECT; 321 cn = hp_sizes[unit&07].cyloff; 322 break; 323 default: 324 panic("hpstart"); 325 } 326 cn += bn/nspc; 327 sn = bn%nspc; 328 tn = sn/ns; 329 sn = sn%ns; 330 331 hpaddr = mbadev(HPMBA, dn); 332 if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) { 333 hptab.b_active = 0; 334 hptab.b_errcnt = 0; 335 dp->b_actf = bp->av_forw; 336 bp->b_flags |= B_ERROR; 337 iodone(bp); 338 goto loop; 339 } 340 if(hptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE) == 0) { 341 hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22; 342 HPMBA->mba_cr &= ~MBAIE; 343 hpaddr->hpcs1 = OFFSET|GO; 344 while(hpaddr->hpds & PIP) 345 ; 346 HPMBA->mba_cr |= MBAIE; 347 } 348 hpaddr->hpdc = cn; 349 hpaddr->hpda = (tn << 8) + sn; 350 mbastart(bp, (int *)hpaddr); 351 352 unit = dn+DK_N; 353 if (NHP+DK_N == DK_NMAX) 354 unit = NHP+DK_N; 355 if (unit <= DK_NMAX) { 356 dk_busy |= 1<<unit; 357 dk_numb[unit]++; 358 dk_wds[unit] += bp->b_bcount>>6; 359 } 360 } 361 362 hpintr(mbastat, as) 363 { 364 register struct buf *bp, *dp; 365 register unit; 366 register struct device *hpaddr; 367 368 if(hptab.b_active) { 369 dp = hptab.b_actf; 370 bp = dp->b_actf; 371 unit = dkunit(bp); 372 if (DK_N+NHP == DK_NMAX) 373 dk_busy &= ~(1<<(DK_N+NHP)); 374 else if (DK_N+unit <= DK_NMAX) 375 dk_busy &= ~(1<<(DK_N+unit)); 376 hpaddr = mbadev(HPMBA, unit); 377 if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { 378 while((hpaddr->hpds & DRY) == 0) 379 ; 380 if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE) 381 bp->b_flags |= B_ERROR; 382 else 383 hptab.b_active = 0; 384 if(hptab.b_errcnt > 27) 385 deverror(bp, mbastat, hpaddr->hper1); 386 if ((hpaddr->hper1&0xffff) == DCK) { 387 if (hpecc(hpaddr, bp)) 388 return; 389 } 390 hpaddr->hpcs1 = DCLR|GO; 391 if((hptab.b_errcnt&07) == 4) { 392 HPMBA->mba_cr &= ~MBAIE; 393 hpaddr->hpcs1 = RECAL|GO; 394 while(hpaddr->hpds & PIP) 395 ; 396 HPMBA->mba_cr |= MBAIE; 397 } 398 } 399 if(hptab.b_active) { 400 if(hptab.b_errcnt) { 401 HPMBA->mba_cr &= ~MBAIE; 402 hpaddr->hpcs1 = RTC|GO; 403 while(hpaddr->hpds & PIP) 404 ; 405 HPMBA->mba_cr |= MBAIE; 406 } 407 hptab.b_active = 0; 408 hptab.b_errcnt = 0; 409 hptab.b_actf = dp->b_forw; 410 dp->b_active = 0; 411 dp->b_errcnt = 0; 412 dp->b_actf = bp->av_forw; 413 bp->b_resid = -HPMBA->mba_bcr & 0xffff; 414 iodone(bp); 415 if(dp->b_actf) 416 hpustart(unit); 417 } 418 as &= ~(1<<unit); 419 } else { 420 if(as == 0) 421 HPMBA->mba_cr |= MBAIE; 422 } 423 for(unit=0; unit<NHP; unit++) 424 if(as & (1<<unit)) 425 hpustart(unit); 426 hpstart(); 427 } 428 429 hpread(dev) 430 { 431 432 physio(hpstrategy, &rhpbuf, dev, B_READ, minphys); 433 } 434 435 hpwrite(dev) 436 { 437 438 physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys); 439 } 440 441 hpecc(rp, bp) 442 register struct device *rp; 443 register struct buf *bp; 444 { 445 struct mba_regs *mbp = HPMBA; 446 register int i; 447 caddr_t addr; 448 int reg, bit, byte, npf, mask, o; 449 int dn, bn, cn, tn, sn, ns, nt; 450 extern char buffers[NBUF][BSIZE]; 451 struct pte mpte; 452 int bcr; 453 454 /* 455 * Npf is the number of sectors transferred before the sector 456 * containing the ECC error, and reg is the MBA register 457 * mapping (the first part of)the transfer. 458 * O is offset within a memory page of the first byte transferred. 459 */ 460 bcr = mbp->mba_bcr & 0xffff; 461 if (bcr) 462 bcr |= 0xffff0000; /* sxt */ 463 npf = btop(bcr + bp->b_bcount) - 1; 464 printf("bcr %d npf %d\n", bcr, npf); 465 if (bp->b_flags&B_PHYS) 466 reg = 128 + npf; 467 else 468 reg = btop(bp->b_un.b_addr - buffers[0]) + npf; 469 o = (int)bp->b_un.b_addr & PGOFSET; 470 printf("%D ", bp->b_blkno + npf); 471 prdev("ECC", bp->b_dev); 472 mask = rp->hpec2&0xffff; 473 if (mask == 0) { 474 rp->hpof = FMT22; 475 return (0); 476 } 477 478 /* 479 * Compute the byte and bit position of the error. 480 * The variable i is the byte offset in the transfer, 481 * the variable byte is the offset from a page boundary 482 * in main memory. 483 */ 484 i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 485 bit = i&07; 486 i = (i&~07)>>3; 487 byte = i + o; 488 /* 489 * Correct while possible bits remain of mask. Since mask 490 * contains 11 bits, we continue while the bit offset is > -11. 491 * Also watch out for end of this block and the end of the whole 492 * transfer. 493 */ 494 while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 495 mpte = mbp->mba_map[reg+btop(byte)]; 496 addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 497 putmemc(addr, getmemc(addr)^(mask<<bit)); 498 byte++; 499 i++; 500 bit -= 8; 501 } 502 hptab.b_active++; /* Either complete or continuing */ 503 if (bcr == 0) 504 return (0); 505 /* 506 * Have to continue the transfer... clear the drive, 507 * and compute the position where the transfer is to continue. 508 * We have completed npf+1 sectores of the transfer already; 509 * restart at offset o of next sector (i.e. in MBA register reg+1). 510 */ 511 rp->hpcs1 = DCLR|GO; 512 dn = dkunit(bp); 513 bn = dkblock(bp); 514 switch (hp_type[dn]) { 515 516 case RM: 517 ns = NRMSECT; nt = NRMTRAC; break; 518 case RM5: 519 ns = NRMSECT; nt = NTRAC; break; 520 case RP: 521 ns = NSECT; nt = NTRAC; break; 522 default: 523 panic("hpecc"); 524 } 525 cn = bp->b_cylin; 526 sn = bn%(ns*nt) + npf + 1; 527 tn = sn/ns; 528 sn %= ns; 529 cn += tn/nt; 530 tn %= nt; 531 rp->hpdc = cn; 532 rp->hpda = (tn<<8) + sn; 533 mbp->mba_sr = -1; 534 mbp->mba_var = (int)ptob(reg+1) + o; 535 rp->hpcs1 = RCOM|GO; 536 return (1); 537 } 538