| 1 | /* hp.c 4.57 82/10/31 */ |
| 2 | |
| 3 | #ifdef HPDEBUG |
| 4 | int hpdebug; |
| 5 | #endif |
| 6 | #ifdef HPBDEBUG |
| 7 | int hpbdebug; |
| 8 | #endif |
| 9 | |
| 10 | #include "hp.h" |
| 11 | #if NHP > 0 |
| 12 | /* |
| 13 | * HP disk driver for RP0x+RMxx+ML11 |
| 14 | * |
| 15 | * TODO: |
| 16 | * check RM80 skip sector handling when ECC's occur later |
| 17 | * check offset recovery handling |
| 18 | * see if DCLR and/or RELEASE set attention status |
| 19 | * print bits of mr && mr2 symbolically |
| 20 | */ |
| 21 | |
| 22 | #include "../h/param.h" |
| 23 | #include "../h/systm.h" |
| 24 | #include "../h/dk.h" |
| 25 | #include "../h/buf.h" |
| 26 | #include "../h/conf.h" |
| 27 | #include "../h/dir.h" |
| 28 | #include "../h/user.h" |
| 29 | #include "../h/map.h" |
| 30 | #include "../h/pte.h" |
| 31 | #include "../vax/mtpr.h" |
| 32 | #include "../h/vm.h" |
| 33 | #include "../h/cmap.h" |
| 34 | #include "../h/dkbad.h" |
| 35 | #include "../h/ioctl.h" |
| 36 | #include "../h/uio.h" |
| 37 | |
| 38 | #include "../vax/dkio.h" |
| 39 | #include "../vaxmba/mbareg.h" |
| 40 | #include "../vaxmba/mbavar.h" |
| 41 | #include "../vaxmba/hpreg.h" |
| 42 | |
| 43 | /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ |
| 44 | struct size { |
| 45 | daddr_t nblocks; |
| 46 | int cyloff; |
| 47 | } hp6_sizes[8] = { |
| 48 | 15884, 0, /* A=cyl 0 thru 37 */ |
| 49 | 33440, 38, /* B=cyl 38 thru 117 */ |
| 50 | 340670, 0, /* C=cyl 0 thru 814 */ |
| 51 | 0, 0, |
| 52 | 0, 0, |
| 53 | 0, 0, |
| 54 | #ifndef NOBADSECT |
| 55 | 291280, 118, /* G=cyl 118 thru 814 */ |
| 56 | #else |
| 57 | 291346, 118, |
| 58 | #endif |
| 59 | 0, 0, |
| 60 | }, rm3_sizes[8] = { |
| 61 | 15884, 0, /* A=cyl 0 thru 99 */ |
| 62 | 33440, 100, /* B=cyl 100 thru 309 */ |
| 63 | 131680, 0, /* C=cyl 0 thru 822 */ |
| 64 | 0, 0, |
| 65 | 0, 0, |
| 66 | 0, 0, |
| 67 | #ifndef NOBADSECT |
| 68 | 81984, 310, /* G=cyl 310 thru 822 */ |
| 69 | #else |
| 70 | 82080, 310, |
| 71 | #endif |
| 72 | 0, 0, |
| 73 | }, rm5_sizes[8] = { |
| 74 | #ifndef CAD |
| 75 | 15884, 0, /* A=cyl 0 thru 26 */ |
| 76 | 33440, 27, /* B=cyl 27 thru 81 */ |
| 77 | 500384, 0, /* C=cyl 0 thru 822 */ |
| 78 | 15884, 562, /* D=cyl 562 thru 588 */ |
| 79 | 55936, 589, /* E=cyl 589 thru 680 */ |
| 80 | #ifndef NOBADSECT |
| 81 | 86240, 681, /* F=cyl 681 thru 822 */ |
| 82 | 158592, 562, /* G=cyl 562 thru 822 */ |
| 83 | #else |
| 84 | 86336, 681, |
| 85 | 158688, 562, |
| 86 | #endif |
| 87 | 291346, 82, /* H=cyl 82 thru 561 */ |
| 88 | #else |
| 89 | 15884, 0, /* A=cyl 0 thru 26 */ |
| 90 | 33440, 27, /* B=cyl 27 thru 81 */ |
| 91 | 495520, 0, /* C=cyl 0 thru 814 */ |
| 92 | 15884, 562, /* D=cyl 562 thru 588 */ |
| 93 | 55936, 589, /* E=cyl 589 thru 680 */ |
| 94 | #ifndef NOBADSECT |
| 95 | 81376, 681, /* F=cyl 681 thru 814 */ |
| 96 | 153728, 562, /* G=cyl 562 thru 814 */ |
| 97 | #else |
| 98 | 81472, 681, |
| 99 | 153824, 562, |
| 100 | #endif |
| 101 | 291346, 82, /* H=cyl 82 thru 561 */ |
| 102 | #endif |
| 103 | }, rm80_sizes[8] = { |
| 104 | 15884, 0, /* A=cyl 0 thru 36 */ |
| 105 | 33440, 37, /* B=cyl 37 thru 114 */ |
| 106 | 242606, 0, /* C=cyl 0 thru 558 */ |
| 107 | 0, 0, |
| 108 | 0, 0, |
| 109 | 0, 0, |
| 110 | 82080, 115, /* G=cyl 115 thru 304 */ |
| 111 | 110143, 305, /* H=cyl 305 thru 558 */ |
| 112 | }, hp7_sizes[8] = { |
| 113 | 15884, 0, /* A=cyl 0 thru 9 */ |
| 114 | 64000, 10, /* B=cyl 10 thru 49 */ |
| 115 | 1008000,0, /* C=cyl 0 thru 629 */ |
| 116 | 15884, 330, /* D=cyl 330 thru 339 */ |
| 117 | 256000, 340, /* E=cyl 340 thru 499 */ |
| 118 | 207850, 500, /* F=cyl 500 thru 629 */ |
| 119 | 479850, 330, /* G=cyl 330 thru 629 */ |
| 120 | 448000, 50, /* H=cyl 50 thru 329 */ |
| 121 | }, si9775_sizes[8] = { |
| 122 | 16640, 0, /* A=cyl 0 thru 12 */ |
| 123 | 34560, 13, /* B=cyl 13 thru 39 */ |
| 124 | 1079040, 0, /* C=cyl 0 thru 842 - whole disk */ |
| 125 | 0, 0, /* D unused */ |
| 126 | 0, 0, /* E unused */ |
| 127 | 0, 0, /* F unused */ |
| 128 | 513280, 40, /* G=cyl 40 thru 440 */ |
| 129 | 513280, 441, /* H=cyl 441 thru 841 */ |
| 130 | }, si9730_sizes[8] = { |
| 131 | 15884, 0, /* A=cyl 0 thru 49 */ |
| 132 | 33440, 50, /* B=cyl 50 thru 154 */ |
| 133 | 263360, 0, /* C=cyl 0 thru 822 */ |
| 134 | 0, 0, |
| 135 | 0, 0, |
| 136 | 0, 0, |
| 137 | 0, 0, |
| 138 | #ifndef NOBADSECT |
| 139 | 213664, 155, /* H=cyl 155 thru 822 */ |
| 140 | #else |
| 141 | 213760, 155, |
| 142 | #endif |
| 143 | }, hpam_sizes[8] = { |
| 144 | 15884, 0, /* A=cyl 0 thru 31 */ |
| 145 | 33440, 32, /* B=cyl 32 thru 97 */ |
| 146 | 524288, 0, /* C=cyl 0 thru 1023 */ |
| 147 | 27786, 668, |
| 148 | 27786, 723, |
| 149 | 125440, 778, |
| 150 | 181760, 668, /* G=cyl 668 thru 1022 */ |
| 151 | 291346, 98, /* H=cyl 98 thru 667 */ |
| 152 | }; |
| 153 | /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ |
| 154 | |
| 155 | #define _hpSDIST 2 |
| 156 | #define _hpRDIST 3 |
| 157 | |
| 158 | int hpSDIST = _hpSDIST; |
| 159 | int hpRDIST = _hpRDIST; |
| 160 | |
| 161 | /* |
| 162 | * Table for converting Massbus drive types into |
| 163 | * indices into the partition tables. Slots are |
| 164 | * left for those drives devined from other means |
| 165 | * (e.g. SI, AMPEX, etc.). |
| 166 | */ |
| 167 | short hptypes[] = { |
| 168 | #define HPDT_RM03 0 |
| 169 | MBDT_RM03, |
| 170 | #define HPDT_RM05 1 |
| 171 | MBDT_RM05, |
| 172 | #define HPDT_RP06 2 |
| 173 | MBDT_RP06, |
| 174 | #define HPDT_RM80 3 |
| 175 | MBDT_RM80, |
| 176 | #define HPDT_RP05 4 |
| 177 | MBDT_RP05, |
| 178 | #define HPDT_RP07 5 |
| 179 | MBDT_RP07, |
| 180 | #define HPDT_ML11A 6 |
| 181 | MBDT_ML11A, |
| 182 | #define HPDT_ML11B 7 |
| 183 | MBDT_ML11B, |
| 184 | #define HPDT_9775 8 |
| 185 | -1, |
| 186 | #define HPDT_9730 9 |
| 187 | -1, |
| 188 | #define HPDT_CAPRICORN 10 |
| 189 | -1, |
| 190 | #define HPDT_RM02 11 |
| 191 | MBDT_RM02, /* beware, actually capricorn */ |
| 192 | 0 |
| 193 | }; |
| 194 | struct mba_device *hpinfo[NHP]; |
| 195 | int hpattach(),hpustart(),hpstart(),hpdtint(); |
| 196 | struct mba_driver hpdriver = |
| 197 | { hpattach, 0, hpustart, hpstart, hpdtint, 0, |
| 198 | hptypes, "hp", 0, hpinfo }; |
| 199 | |
| 200 | struct hpst { |
| 201 | short nsect; |
| 202 | short ntrak; |
| 203 | short nspc; |
| 204 | short ncyl; |
| 205 | struct size *sizes; |
| 206 | } hpst[] = { |
| 207 | 32, 5, 32*5, 823, rm3_sizes, /* RM03 */ |
| 208 | 32, 19, 32*19, 823, rm5_sizes, /* RM05 */ |
| 209 | 22, 19, 22*19, 815, hp6_sizes, /* RP06 */ |
| 210 | 31, 14, 31*14, 559, rm80_sizes, /* RM80 */ |
| 211 | 22, 19, 22*19, 411, hp6_sizes, /* RP05 */ |
| 212 | 50, 32, 50*32, 630, hp7_sizes, /* RP07 */ |
| 213 | 1, 1, 1, 1, 0, /* ML11A */ |
| 214 | 1, 1, 1, 1, 0, /* ML11B */ |
| 215 | 32, 40, 32*40, 843, si9775_sizes, /* 9775 */ |
| 216 | 32, 10, 32*10, 823, si9730_sizes, /* 9730 */ |
| 217 | 32, 16, 32*16, 1024, hpam_sizes, /* AMPEX capricorn */ |
| 218 | }; |
| 219 | |
| 220 | u_char hp_offset[16] = { |
| 221 | HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, |
| 222 | HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, |
| 223 | HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, |
| 224 | 0, 0, 0, 0, |
| 225 | }; |
| 226 | |
| 227 | struct buf rhpbuf[NHP]; |
| 228 | #ifndef NOBADSECT |
| 229 | struct buf bhpbuf[NHP]; |
| 230 | struct dkbad hpbad[NHP]; |
| 231 | #endif |
| 232 | /* SHOULD CONSOLIDATE ALL THIS STUFF INTO A STRUCTURE */ |
| 233 | char hpinit[NHP]; |
| 234 | char hprecal[NHP]; |
| 235 | char hphdr[NHP]; |
| 236 | daddr_t mlsize[NHP]; |
| 237 | |
| 238 | #define b_cylin b_resid |
| 239 | |
| 240 | /* #define ML11 0 to remove ML11 support */ |
| 241 | #define ML11 (hptypes[mi->mi_type] == MBDT_ML11A) |
| 242 | #define RP06 (hptypes[mi->mi_type] <= MBDT_RP06) |
| 243 | #define RM80 (hptypes[mi->mi_type] == MBDT_RM80) |
| 244 | |
| 245 | #ifdef INTRLVE |
| 246 | daddr_t dkblock(); |
| 247 | #endif |
| 248 | |
| 249 | int hpseek; |
| 250 | |
| 251 | /*ARGSUSED*/ |
| 252 | hpattach(mi, slave) |
| 253 | struct mba_device *mi; |
| 254 | { |
| 255 | register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; |
| 256 | |
| 257 | switch (mi->mi_type) { |
| 258 | |
| 259 | /* |
| 260 | * Model-byte processing for SI 9400 controllers. |
| 261 | * NB: Only deals with RM03 and RM05 emulations. |
| 262 | */ |
| 263 | case HPDT_RM03: |
| 264 | case HPDT_RM05: { |
| 265 | register int hpsn; |
| 266 | |
| 267 | hpsn = hpaddr->hpsn; |
| 268 | if ((hpsn & SIMB_LU) != mi->mi_drive) |
| 269 | break; |
| 270 | switch ((hpsn & SIMB_MB) & ~(SIMB_S6|SIRM03|SIRM05)) { |
| 271 | |
| 272 | case SI9775D: |
| 273 | printf("hp%d: si 9775 (direct)\n", mi->mi_unit); |
| 274 | mi->mi_type = HPDT_9775; |
| 275 | break; |
| 276 | |
| 277 | case SI9730D: |
| 278 | printf("hp%d: si 9730 (direct)\n", mi->mi_unit); |
| 279 | mi->mi_type = HPDT_9730; |
| 280 | break; |
| 281 | |
| 282 | #ifdef CAD |
| 283 | /* |
| 284 | * AMPEX 9300, SI Combination needs a have the drive cleared |
| 285 | * before we start. We do not know why, but tests show |
| 286 | * that the recalibrate fixes the problem. |
| 287 | */ |
| 288 | case SI9766: |
| 289 | printf("hp%d: 9776/9300\n", mi->mi_unit); |
| 290 | mi->mi_type = HPDT_RM05; |
| 291 | hpaddr->hpcs1 = HP_RECAL|HP_GO; |
| 292 | DELAY(100000); |
| 293 | break; |
| 294 | |
| 295 | case SI9762: |
| 296 | printf("hp%d: 9762\n", mi->mi_unit); |
| 297 | mi->mi_type = HPDT_RM03; |
| 298 | break; |
| 299 | #endif |
| 300 | } |
| 301 | break; |
| 302 | } |
| 303 | |
| 304 | /* |
| 305 | * CAPRICORN KLUDGE...poke the holding register |
| 306 | * to find out the number of tracks. If it's 15 |
| 307 | * we believe it's a Capricorn. |
| 308 | */ |
| 309 | case HPDT_RM02: |
| 310 | hpaddr->hpcs1 = HP_NOP; |
| 311 | hpaddr->hphr = HPHR_MAXTRAK; |
| 312 | if ((hpaddr->hphr&0xffff) == 15) { |
| 313 | printf("hp%d: capricorn\n", mi->mi_unit); |
| 314 | mi->mi_type = HPDT_CAPRICORN; |
| 315 | } |
| 316 | hpaddr->hpcs1 = HP_DCLR|HP_GO; |
| 317 | break; |
| 318 | |
| 319 | case HPDT_ML11A: |
| 320 | case HPDT_ML11B: { |
| 321 | register int trt, sz; |
| 322 | |
| 323 | sz = hpaddr->hpmr & HPMR_SZ; |
| 324 | if ((hpaddr->hpmr & HPMR_ARRTYP) == 0) |
| 325 | sz >>= 2; |
| 326 | mlsize[mi->mi_unit] = sz; |
| 327 | if (mi->mi_dk >= 0) { |
| 328 | trt = (hpaddr->hpmr & HPMR_TRT) >> 8; |
| 329 | dk_mspw[mi->mi_dk] = 1.0 / (1<<(20-trt)); |
| 330 | } |
| 331 | /* A CHEAT - ML11B D.T. SHOULD == ML11A */ |
| 332 | mi->mi_type = HPDT_ML11A; |
| 333 | break; |
| 334 | } |
| 335 | } |
| 336 | if (!ML11 && mi->mi_dk >= 0) { |
| 337 | register struct hpst *st = &hpst[mi->mi_type]; |
| 338 | |
| 339 | dk_mspw[mi->mi_dk] = 1.0 / 60 / (st->nsect * 256); |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | hpopen(dev) |
| 344 | dev_t dev; |
| 345 | { |
| 346 | register int unit = minor(dev) >> 3; |
| 347 | register struct mba_device *mi; |
| 348 | |
| 349 | if (unit >= NHP || (mi = hpinfo[unit]) == 0 || mi->mi_alive == 0) |
| 350 | return (ENXIO); |
| 351 | return (0); |
| 352 | } |
| 353 | |
| 354 | hpstrategy(bp) |
| 355 | register struct buf *bp; |
| 356 | { |
| 357 | register struct mba_device *mi; |
| 358 | register struct hpst *st; |
| 359 | register int unit; |
| 360 | long sz, bn; |
| 361 | int xunit = minor(bp->b_dev) & 07; |
| 362 | int s; |
| 363 | |
| 364 | sz = bp->b_bcount; |
| 365 | sz = (sz+511) >> 9; |
| 366 | unit = dkunit(bp); |
| 367 | if (unit >= NHP) |
| 368 | goto bad; |
| 369 | mi = hpinfo[unit]; |
| 370 | if (mi == 0 || mi->mi_alive == 0) |
| 371 | goto bad; |
| 372 | st = &hpst[mi->mi_type]; |
| 373 | if (ML11) { |
| 374 | if (bp->b_blkno < 0 || |
| 375 | dkblock(bp)+sz > mlsize[mi->mi_unit]) |
| 376 | goto bad; |
| 377 | bp->b_cylin = 0; |
| 378 | } else { |
| 379 | if (bp->b_blkno < 0 || |
| 380 | (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) |
| 381 | goto bad; |
| 382 | bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; |
| 383 | } |
| 384 | s = spl5(); |
| 385 | disksort(&mi->mi_tab, bp); |
| 386 | if (mi->mi_tab.b_active == 0) |
| 387 | mbustart(mi); |
| 388 | splx(s); |
| 389 | return; |
| 390 | |
| 391 | bad: |
| 392 | bp->b_flags |= B_ERROR; |
| 393 | iodone(bp); |
| 394 | return; |
| 395 | } |
| 396 | |
| 397 | hpustart(mi) |
| 398 | register struct mba_device *mi; |
| 399 | { |
| 400 | register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; |
| 401 | register struct buf *bp = mi->mi_tab.b_actf; |
| 402 | register struct hpst *st = &hpst[mi->mi_type]; |
| 403 | daddr_t bn; |
| 404 | int sn, dist; |
| 405 | |
| 406 | hpaddr->hpcs1 = 0; |
| 407 | if ((hpaddr->hpcs1&HP_DVA) == 0) |
| 408 | return (MBU_BUSY); |
| 409 | if ((hpaddr->hpds & HPDS_VV) == 0 || hpinit[mi->mi_unit] == 0) { |
| 410 | #ifndef NOBADSECT |
| 411 | struct buf *bbp = &bhpbuf[mi->mi_unit]; |
| 412 | #endif |
| 413 | |
| 414 | hpinit[mi->mi_unit] = 1; |
| 415 | hpaddr->hpcs1 = HP_DCLR|HP_GO; |
| 416 | if (mi->mi_mba->mba_drv[0].mbd_as & (1<<mi->mi_drive)) |
| 417 | printf("DCLR attn\n"); |
| 418 | hpaddr->hpcs1 = HP_PRESET|HP_GO; |
| 419 | if (!ML11) |
| 420 | hpaddr->hpof = HPOF_FMT22; |
| 421 | mbclrattn(mi); |
| 422 | #ifndef NOBADSECT |
| 423 | if (!ML11) { |
| 424 | bbp->b_flags = B_READ|B_BUSY; |
| 425 | bbp->b_dev = bp->b_dev; |
| 426 | bbp->b_bcount = 512; |
| 427 | bbp->b_un.b_addr = (caddr_t)&hpbad[mi->mi_unit]; |
| 428 | bbp->b_blkno = st->ncyl*st->nspc - st->nsect; |
| 429 | bbp->b_cylin = st->ncyl - 1; |
| 430 | mi->mi_tab.b_actf = bbp; |
| 431 | bbp->av_forw = bp; |
| 432 | bp = bbp; |
| 433 | } |
| 434 | #endif |
| 435 | } |
| 436 | if (mi->mi_tab.b_active || mi->mi_hd->mh_ndrive == 1) |
| 437 | return (MBU_DODATA); |
| 438 | if (ML11) |
| 439 | return (MBU_DODATA); |
| 440 | if ((hpaddr->hpds & HPDS_DREADY) != HPDS_DREADY) |
| 441 | return (MBU_DODATA); |
| 442 | bn = dkblock(bp); |
| 443 | sn = bn%st->nspc; |
| 444 | sn = (sn+st->nsect-hpSDIST)%st->nsect; |
| 445 | if (bp->b_cylin == (hpaddr->hpdc & 0xffff)) { |
| 446 | if (hpseek) |
| 447 | return (MBU_DODATA); |
| 448 | dist = ((hpaddr->hpla & 0xffff)>>6) - st->nsect + 1; |
| 449 | if (dist < 0) |
| 450 | dist += st->nsect; |
| 451 | if (dist > st->nsect - hpRDIST) |
| 452 | return (MBU_DODATA); |
| 453 | } else |
| 454 | hpaddr->hpdc = bp->b_cylin; |
| 455 | if (hpseek) |
| 456 | hpaddr->hpcs1 = HP_SEEK|HP_GO; |
| 457 | else { |
| 458 | hpaddr->hpda = sn; |
| 459 | hpaddr->hpcs1 = HP_SEARCH|HP_GO; |
| 460 | } |
| 461 | return (MBU_STARTED); |
| 462 | } |
| 463 | |
| 464 | hpstart(mi) |
| 465 | register struct mba_device *mi; |
| 466 | { |
| 467 | register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; |
| 468 | register struct buf *bp = mi->mi_tab.b_actf; |
| 469 | register struct hpst *st = &hpst[mi->mi_type]; |
| 470 | daddr_t bn; |
| 471 | int sn, tn; |
| 472 | |
| 473 | bn = dkblock(bp); |
| 474 | if (ML11) |
| 475 | hpaddr->hpda = bn; |
| 476 | else { |
| 477 | sn = bn%st->nspc; |
| 478 | tn = sn/st->nsect; |
| 479 | sn %= st->nsect; |
| 480 | hpaddr->hpdc = bp->b_cylin; |
| 481 | hpaddr->hpda = (tn << 8) + sn; |
| 482 | } |
| 483 | if (hphdr[mi->mi_unit]) { |
| 484 | if (bp->b_flags & B_READ) |
| 485 | return (HP_RHDR|HP_GO); |
| 486 | else |
| 487 | return (HP_WHDR|HP_GO); |
| 488 | } |
| 489 | return (0); |
| 490 | } |
| 491 | |
| 492 | hpdtint(mi, mbsr) |
| 493 | register struct mba_device *mi; |
| 494 | int mbsr; |
| 495 | { |
| 496 | register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; |
| 497 | register struct buf *bp = mi->mi_tab.b_actf; |
| 498 | register int er1, er2; |
| 499 | int retry = 0; |
| 500 | |
| 501 | #ifndef NOBADSECT |
| 502 | if (bp->b_flags&B_BAD) { |
| 503 | if (hpecc(mi, CONT)) |
| 504 | return(MBD_RESTARTED); |
| 505 | } |
| 506 | #endif |
| 507 | if (hpaddr->hpds&HPDS_ERR || mbsr&MBSR_EBITS) { |
| 508 | #ifdef HPDEBUG |
| 509 | if (hpdebug) { |
| 510 | int dc = hpaddr->hpdc, da = hpaddr->hpda; |
| 511 | |
| 512 | printf("hperr: bp %x cyl %d blk %d as %o ", |
| 513 | bp, bp->b_cylin, bp->b_blkno, |
| 514 | hpaddr->hpas&0xff); |
| 515 | printf("dc %x da %x\n",dc&0xffff, da&0xffff); |
| 516 | printf("errcnt %d ", mi->mi_tab.b_errcnt); |
| 517 | printf("mbsr=%b ", mbsr, mbsr_bits); |
| 518 | printf("er1=%b er2=%b\n", |
| 519 | hpaddr->hper1, HPER1_BITS, |
| 520 | hpaddr->hper2, HPER2_BITS); |
| 521 | DELAY(1000000); |
| 522 | } |
| 523 | #endif |
| 524 | er1 = hpaddr->hper1; |
| 525 | er2 = hpaddr->hper2; |
| 526 | if (er1 & HPER1_HCRC) { |
| 527 | er1 &= ~(HPER1_HCE|HPER1_FER); |
| 528 | er2 &= ~HPER2_BSE; |
| 529 | } |
| 530 | if (er1&HPER1_WLE) { |
| 531 | printf("hp%d: write locked\n", dkunit(bp)); |
| 532 | bp->b_flags |= B_ERROR; |
| 533 | } else if ((er1&0xffff) == HPER1_FER && RP06 && |
| 534 | hphdr[mi->mi_unit] == 0) { |
| 535 | #ifndef NOBADSECT |
| 536 | if (hpecc(mi, BSE)) |
| 537 | return(MBD_RESTARTED); |
| 538 | else |
| 539 | #endif |
| 540 | goto hard; |
| 541 | } else if (++mi->mi_tab.b_errcnt > 27 || |
| 542 | mbsr & MBSR_HARD || |
| 543 | er1 & HPER1_HARD || |
| 544 | hphdr[mi->mi_unit] || |
| 545 | (!ML11 && (er2 & HPER2_HARD))) { |
| 546 | hard: |
| 547 | harderr(bp, "hp"); |
| 548 | if (mbsr & (MBSR_EBITS &~ (MBSR_DTABT|MBSR_MBEXC))) |
| 549 | printf("mbsr=%b ", mbsr, mbsr_bits); |
| 550 | printf("er1=%b er2=%b", |
| 551 | hpaddr->hper1, HPER1_BITS, |
| 552 | hpaddr->hper2, HPER2_BITS); |
| 553 | if (hpaddr->hpmr) |
| 554 | printf(" mr=%o", hpaddr->hpmr&0xffff); |
| 555 | if (hpaddr->hpmr2) |
| 556 | printf(" mr2=%o", hpaddr->hpmr2&0xffff); |
| 557 | printf("\n"); |
| 558 | bp->b_flags |= B_ERROR; |
| 559 | hprecal[mi->mi_unit] = 0; |
| 560 | } else if ((er2 & HPER2_BSE) && !ML11) { |
| 561 | #ifndef NOBADSECT |
| 562 | if (hpecc(mi, BSE)) |
| 563 | return(MBD_RESTARTED); |
| 564 | else |
| 565 | #endif |
| 566 | goto hard; |
| 567 | } else if (RM80 && er2&HPER2_SSE) { |
| 568 | (void) hpecc(mi, SSE); |
| 569 | return (MBD_RESTARTED); |
| 570 | } else if ((er1&(HPER1_DCK|HPER1_ECH))==HPER1_DCK) { |
| 571 | if (hpecc(mi, ECC)) |
| 572 | return (MBD_RESTARTED); |
| 573 | /* else done */ |
| 574 | } else |
| 575 | retry = 1; |
| 576 | hpaddr->hpcs1 = HP_DCLR|HP_GO; |
| 577 | if (ML11) { |
| 578 | if (mi->mi_tab.b_errcnt >= 16) |
| 579 | goto hard; |
| 580 | } else if ((mi->mi_tab.b_errcnt&07) == 4) { |
| 581 | hpaddr->hpcs1 = HP_RECAL|HP_GO; |
| 582 | hprecal[mi->mi_unit] = 1; |
| 583 | return(MBD_RESTARTED); |
| 584 | } |
| 585 | if (retry) |
| 586 | return (MBD_RETRY); |
| 587 | } |
| 588 | #ifdef HPDEBUG |
| 589 | else |
| 590 | if (hpdebug && hprecal[mi->mi_unit]) { |
| 591 | printf("recal %d ", hprecal[mi->mi_unit]); |
| 592 | printf("errcnt %d\n", mi->mi_tab.b_errcnt); |
| 593 | printf("mbsr=%b ", mbsr, mbsr_bits); |
| 594 | printf("er1=%b er2=%b\n", |
| 595 | hpaddr->hper1, HPER1_BITS, |
| 596 | hpaddr->hper2, HPER2_BITS); |
| 597 | } |
| 598 | #endif |
| 599 | switch (hprecal[mi->mi_unit]) { |
| 600 | |
| 601 | case 1: |
| 602 | hpaddr->hpdc = bp->b_cylin; |
| 603 | hpaddr->hpcs1 = HP_SEEK|HP_GO; |
| 604 | hprecal[mi->mi_unit]++; |
| 605 | return (MBD_RESTARTED); |
| 606 | case 2: |
| 607 | if (mi->mi_tab.b_errcnt < 16 || |
| 608 | (bp->b_flags & B_READ) == 0) |
| 609 | goto donerecal; |
| 610 | hpaddr->hpof = hp_offset[mi->mi_tab.b_errcnt & 017]|HPOF_FMT22; |
| 611 | hpaddr->hpcs1 = HP_OFFSET|HP_GO; |
| 612 | hprecal[mi->mi_unit]++; |
| 613 | return (MBD_RESTARTED); |
| 614 | donerecal: |
| 615 | case 3: |
| 616 | hprecal[mi->mi_unit] = 0; |
| 617 | return (MBD_RETRY); |
| 618 | } |
| 619 | hphdr[mi->mi_unit] = 0; |
| 620 | bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff; |
| 621 | if (mi->mi_tab.b_errcnt >= 16) { |
| 622 | /* |
| 623 | * This is fast and occurs rarely; we don't |
| 624 | * bother with interrupts. |
| 625 | */ |
| 626 | hpaddr->hpcs1 = HP_RTC|HP_GO; |
| 627 | while (hpaddr->hpds & HPDS_PIP) |
| 628 | ; |
| 629 | mbclrattn(mi); |
| 630 | } |
| 631 | if (!ML11) { |
| 632 | hpaddr->hpof = HPOF_FMT22; |
| 633 | hpaddr->hpcs1 = HP_RELEASE|HP_GO; |
| 634 | } |
| 635 | return (MBD_DONE); |
| 636 | } |
| 637 | |
| 638 | hpread(dev, uio) |
| 639 | dev_t dev; |
| 640 | struct uio *uio; |
| 641 | { |
| 642 | register int unit = minor(dev) >> 3; |
| 643 | |
| 644 | if (unit >= NHP) |
| 645 | return (ENXIO); |
| 646 | return (physio(hpstrategy, &rhpbuf[unit], dev, B_READ, minphys, uio)); |
| 647 | } |
| 648 | |
| 649 | hpwrite(dev, uio) |
| 650 | dev_t dev; |
| 651 | struct uio *uio; |
| 652 | { |
| 653 | register int unit = minor(dev) >> 3; |
| 654 | |
| 655 | if (unit >= NHP) |
| 656 | return (ENXIO); |
| 657 | return (physio(hpstrategy, &rhpbuf[unit], dev, B_WRITE, minphys, uio)); |
| 658 | } |
| 659 | |
| 660 | /*ARGSUSED*/ |
| 661 | hpioctl(dev, cmd, data, flag) |
| 662 | dev_t dev; |
| 663 | int cmd; |
| 664 | caddr_t data; |
| 665 | int flag; |
| 666 | { |
| 667 | |
| 668 | switch (cmd) { |
| 669 | |
| 670 | case DKIOCHDR: /* do header read/write */ |
| 671 | hphdr[minor(dev)>>3] = 1; |
| 672 | return (0); |
| 673 | |
| 674 | default: |
| 675 | return (ENXIO); |
| 676 | } |
| 677 | } |
| 678 | |
| 679 | hpecc(mi, flag) |
| 680 | register struct mba_device *mi; |
| 681 | int flag; |
| 682 | { |
| 683 | register struct mba_regs *mbp = mi->mi_mba; |
| 684 | register struct hpdevice *rp = (struct hpdevice *)mi->mi_drv; |
| 685 | register struct buf *bp = mi->mi_tab.b_actf; |
| 686 | register struct hpst *st = &hpst[mi->mi_type]; |
| 687 | int npf, o; |
| 688 | int bn, cn, tn, sn; |
| 689 | int bcr; |
| 690 | |
| 691 | bcr = mbp->mba_bcr & 0xffff; |
| 692 | if (bcr) |
| 693 | bcr |= 0xffff0000; /* sxt */ |
| 694 | #ifndef NOBADSECT |
| 695 | if (flag == CONT) |
| 696 | npf = bp->b_error; |
| 697 | else |
| 698 | #endif |
| 699 | npf = btop(bcr + bp->b_bcount); |
| 700 | o = (int)bp->b_un.b_addr & PGOFSET; |
| 701 | bn = dkblock(bp); |
| 702 | cn = bp->b_cylin; |
| 703 | sn = bn%(st->nspc) + npf; |
| 704 | tn = sn/st->nsect; |
| 705 | sn %= st->nsect; |
| 706 | cn += tn/st->ntrak; |
| 707 | tn %= st->ntrak; |
| 708 | switch (flag) { |
| 709 | case ECC: |
| 710 | { |
| 711 | register int i; |
| 712 | caddr_t addr; |
| 713 | struct pte mpte; |
| 714 | int bit, byte, mask; |
| 715 | |
| 716 | npf--; /* because block in error is previous block */ |
| 717 | printf("hp%d%c: soft ecc sn%d\n", dkunit(bp), |
| 718 | 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); |
| 719 | mask = rp->hpec2&0xffff; |
| 720 | i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ |
| 721 | bit = i&07; |
| 722 | i = (i&~07)>>3; |
| 723 | byte = i + o; |
| 724 | while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { |
| 725 | mpte = mbp->mba_map[npf+btop(byte)]; |
| 726 | addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); |
| 727 | putmemc(addr, getmemc(addr)^(mask<<bit)); |
| 728 | byte++; |
| 729 | i++; |
| 730 | bit -= 8; |
| 731 | } |
| 732 | if (bcr == 0) |
| 733 | return (0); |
| 734 | npf++; |
| 735 | break; |
| 736 | } |
| 737 | |
| 738 | case SSE: |
| 739 | rp->hpof |= HPOF_SSEI; |
| 740 | mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf)); |
| 741 | break; |
| 742 | |
| 743 | #ifndef NOBADSECT |
| 744 | case BSE: |
| 745 | #ifdef HPBDEBUG |
| 746 | if (hpbdebug) |
| 747 | printf("hpecc, BSE: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); |
| 748 | #endif |
| 749 | if ((bn = isbad(&hpbad[mi->mi_unit], cn, tn, sn)) < 0) |
| 750 | return(0); |
| 751 | bp->b_flags |= B_BAD; |
| 752 | bp->b_error = npf + 1; |
| 753 | bn = st->ncyl*st->nspc - st->nsect - 1 - bn; |
| 754 | cn = bn/st->nspc; |
| 755 | sn = bn%st->nspc; |
| 756 | tn = sn/st->nsect; |
| 757 | sn %= st->nsect; |
| 758 | mbp->mba_bcr = -512; |
| 759 | #ifdef HPBDEBUG |
| 760 | if (hpbdebug) |
| 761 | printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); |
| 762 | #endif |
| 763 | break; |
| 764 | |
| 765 | case CONT: |
| 766 | #ifdef HPBDEBUG |
| 767 | if (hpbdebug) |
| 768 | printf("hpecc, CONT: bn %d cn %d tn %d sn %d\n", bn,cn,tn,sn); |
| 769 | #endif |
| 770 | npf = bp->b_error; |
| 771 | bp->b_flags &= ~B_BAD; |
| 772 | mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf)); |
| 773 | if ((mbp->mba_bcr & 0xffff) == 0) |
| 774 | return(0); |
| 775 | break; |
| 776 | #endif |
| 777 | } |
| 778 | rp->hpcs1 = HP_DCLR|HP_GO; |
| 779 | if (rp->hpof&HPOF_SSEI) |
| 780 | sn++; |
| 781 | rp->hpdc = cn; |
| 782 | rp->hpda = (tn<<8) + sn; |
| 783 | mbp->mba_sr = -1; |
| 784 | mbp->mba_var = (int)ptob(npf) + o; |
| 785 | rp->hpcs1 = bp->b_flags&B_READ ? HP_RCOM|HP_GO : HP_WCOM|HP_GO; |
| 786 | mi->mi_tab.b_errcnt = 0; /* error has been corrected */ |
| 787 | return (1); |
| 788 | } |
| 789 | |
| 790 | #define DBSIZE 20 |
| 791 | |
| 792 | hpdump(dev) |
| 793 | dev_t dev; |
| 794 | { |
| 795 | register struct mba_device *mi; |
| 796 | register struct mba_regs *mba; |
| 797 | struct hpdevice *hpaddr; |
| 798 | char *start; |
| 799 | int num, unit; |
| 800 | register struct hpst *st; |
| 801 | |
| 802 | num = maxfree; |
| 803 | start = 0; |
| 804 | unit = minor(dev) >> 3; |
| 805 | if (unit >= NHP) |
| 806 | return (ENXIO); |
| 807 | #define phys(a,b) ((b)((int)(a)&0x7fffffff)) |
| 808 | mi = phys(hpinfo[unit],struct mba_device *); |
| 809 | if (mi == 0 || mi->mi_alive == 0) |
| 810 | return (ENXIO); |
| 811 | mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; |
| 812 | mba->mba_cr = MBCR_INIT; |
| 813 | hpaddr = (struct hpdevice *)&mba->mba_drv[mi->mi_drive]; |
| 814 | if ((hpaddr->hpds & HPDS_VV) == 0) { |
| 815 | hpaddr->hpcs1 = HP_DCLR|HP_GO; |
| 816 | hpaddr->hpcs1 = HP_PRESET|HP_GO; |
| 817 | hpaddr->hpof = HPOF_FMT22; |
| 818 | } |
| 819 | st = &hpst[mi->mi_type]; |
| 820 | if (dumplo < 0 || dumplo + num >= st->sizes[minor(dev)&07].nblocks) |
| 821 | return (EINVAL); |
| 822 | while (num > 0) { |
| 823 | register struct pte *hpte = mba->mba_map; |
| 824 | register int i; |
| 825 | int blk, cn, sn, tn; |
| 826 | daddr_t bn; |
| 827 | |
| 828 | blk = num > DBSIZE ? DBSIZE : num; |
| 829 | bn = dumplo + btop(start); |
| 830 | cn = bn/st->nspc + st->sizes[minor(dev)&07].cyloff; |
| 831 | sn = bn%st->nspc; |
| 832 | tn = sn/st->nsect; |
| 833 | sn = sn%st->nsect; |
| 834 | hpaddr->hpdc = cn; |
| 835 | hpaddr->hpda = (tn << 8) + sn; |
| 836 | for (i = 0; i < blk; i++) |
| 837 | *(int *)hpte++ = (btop(start)+i) | PG_V; |
| 838 | mba->mba_sr = -1; |
| 839 | mba->mba_bcr = -(blk*NBPG); |
| 840 | mba->mba_var = 0; |
| 841 | hpaddr->hpcs1 = HP_WCOM | HP_GO; |
| 842 | while ((hpaddr->hpds & HPDS_DRY) == 0) |
| 843 | ; |
| 844 | if (hpaddr->hpds&HPDS_ERR) |
| 845 | return (EIO); |
| 846 | start += blk*NBPG; |
| 847 | num -= blk; |
| 848 | } |
| 849 | return (0); |
| 850 | } |
| 851 | #endif |