1 /* vd.c 1.14 87/02/18 */ 2 3 #include "dk.h" 4 #if NVD > 0 5 /* 6 * Versabus VDDC/SMDE driver. 7 */ 8 #include "param.h" 9 #include "buf.h" 10 #include "cmap.h" 11 #include "conf.h" 12 #include "dir.h" 13 #include "dkstat.h" 14 #include "disklabel.h" 15 #include "map.h" 16 #include "file.h" 17 #include "systm.h" 18 #include "user.h" 19 #include "vmmac.h" 20 #include "proc.h" 21 #include "uio.h" 22 #include "syslog.h" 23 #include "kernel.h" 24 #include "ioctl.h" 25 26 #include "../tahoe/cpu.h" 27 #include "../tahoe/mtpr.h" 28 #include "../tahoe/pte.h" 29 30 #include "../tahoevba/vbavar.h" 31 #include "../tahoevba/vdreg.h" 32 33 #define COMPAT_42 34 35 #define VDMAXIO (MAXBPTE*NBPG) 36 37 #define vdunit(dev) (minor(dev) >> 3) 38 #define vdpart(dev) (minor(dev) & 0x07) 39 #define vdminor(unit,part) (((unit) << 3) | (part)) 40 41 struct vba_ctlr *vdminfo[NVD]; 42 struct vba_device *vddinfo[NDK]; 43 int vdprobe(), vdslave(), vdattach(), vddgo(); 44 long vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 45 struct vba_driver vddriver = 46 { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo }; 47 48 /* 49 * Per-controller state. 50 */ 51 struct vdsoftc { 52 u_short vd_flags; 53 #define VD_INIT 0x1 /* controller initialized */ 54 #define VD_STARTED 0x2 /* start command issued */ 55 #define VD_DOSEEKS 0x4 /* should overlap seeks */ 56 u_short vd_type; /* controller type */ 57 u_short vd_wticks; /* timeout */ 58 u_short vd_offcyl; /* off cylinder bitmask */ 59 struct mdcb vd_mdcb; /* master command block */ 60 u_long vd_mdcbphys; /* physical address of vd_mdcb */ 61 struct dcb vd_dcb; /* i/o command block */ 62 u_long vd_dcbphys; /* physical address of vd_dcb */ 63 struct pte *vd_map; /* i/o page map */ 64 caddr_t vd_utl; /* mapped i/o space */ 65 caddr_t vd_rawbuf; /* buffer for raw+swap i/o */ 66 } vdsoftc[NVD]; 67 68 /* 69 * Per-drive state. 70 */ 71 struct dksoftc { 72 u_short dk_state; /* open fsm */ 73 u_short dk_openpart; /* units open on this drive */ 74 u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 75 u_short dk_curdaddr; /* last selected track & sector */ 76 u_int dk_curcyl; /* last selected cylinder */ 77 struct dcb dk_dcb; /* seek command block */ 78 u_long dk_dcbphys; /* physical address of dk_dcb */ 79 } dksoftc[NDK]; 80 81 /* 82 * Drive states. Used during steps of open/initialization. 83 * States < OPEN (> 0) are transient, during an open operation. 84 * OPENRAW is used for unabeled disks, to allow format operations. 85 */ 86 #define CLOSED 0 /* disk is closed */ 87 #define WANTOPEN 1 /* open requested, not started */ 88 #define WANTOPENRAW 2 /* open requested, no label */ 89 #define RDLABEL 3 /* reading pack label */ 90 #define OPEN 4 /* intialized and ready */ 91 #define OPENRAW 5 /* open, no label */ 92 93 struct buf rdkbuf[NDK]; /* raw i/o buffer headers */ 94 struct buf dkutab[NDK]; /* i/o queue headers */ 95 struct disklabel dklabel[NDK]; /* pack labels */ 96 97 #define b_cylin b_resid 98 #define b_daddr b_error 99 100 int vdwstart, vdwatch(); 101 102 /* 103 * See if the controller is really there; if so, initialize it. 104 */ 105 vdprobe(reg, vm) 106 caddr_t reg; 107 struct vba_ctlr *vm; 108 { 109 register br, cvec; /* must be r12, r11 */ 110 register struct vddevice *vdaddr = (struct vddevice *)reg; 111 struct vdsoftc *vd; 112 113 #ifdef lint 114 br = 0; cvec = br; br = cvec; 115 vdintr(0); 116 #endif 117 if (badaddr((caddr_t)reg, 2)) 118 return (0); 119 vd = &vdsoftc[vm->um_ctlr]; 120 vdaddr->vdreset = 0xffffffff; 121 DELAY(1000000); 122 if (vdaddr->vdreset != (unsigned)0xffffffff) { 123 vd->vd_type = VDTYPE_VDDC; 124 vd->vd_flags &= ~VD_DOSEEKS; 125 DELAY(1000000); 126 } else { 127 vd->vd_type = VDTYPE_SMDE; 128 vd->vd_flags |= VD_DOSEEKS; 129 vdaddr->vdrstclr = 0; 130 DELAY(3000000); 131 vdaddr->vdcsr = 0; 132 vdaddr->vdtcf_mdcb = AM_ENPDA; 133 vdaddr->vdtcf_dcb = AM_ENPDA; 134 vdaddr->vdtcf_trail = AM_ENPDA; 135 vdaddr->vdtcf_data = AM_ENPDA; 136 vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS | 137 XMD_32BIT | BSZ_16WRD | 138 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 139 } 140 vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 141 vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 142 vm->um_addr = reg; /* XXX */ 143 if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 144 printf("vd%d: %s cmd failed\n", vm->um_ctlr, 145 vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 146 return (0); 147 } 148 /* 149 * Allocate page tables and i/o buffer. 150 */ 151 vbmapalloc(btoc(VDMAXIO)+1, &vd->vd_map, &vd->vd_utl); 152 vd->vd_rawbuf = calloc(VDMAXIO); 153 br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 154 return (sizeof (struct vddevice)); 155 } 156 157 /* 158 * See if a drive is really there. 159 * 160 * Can't read pack label here as various data structures 161 * aren't setup for doing a read in a straightforward 162 * manner. Instead just probe for the drive and leave 163 * the pack label stuff to the attach routine. 164 */ 165 vdslave(vi, addr) 166 register struct vba_device *vi; 167 struct vddevice *vdaddr; 168 { 169 register struct disklabel *lp = &dklabel[vi->ui_unit]; 170 struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 171 172 if ((vd->vd_flags&VD_INIT) == 0) { 173 printf("vd%d: %s controller\n", vi->ui_ctlr, 174 vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); 175 vd->vd_flags |= VD_INIT; 176 } 177 178 /* 179 * Initialize label enough to do a reset on 180 * the drive. The remainder of the default 181 * label values will be filled in in vdinit 182 * at attach time. 183 */ 184 lp->d_secsize = DEV_BSIZE / 2; /* XXX */ 185 lp->d_nsectors = 32; 186 lp->d_ntracks = 24; 187 lp->d_ncylinders = 711; 188 lp->d_secpercyl = 32*24; 189 return (vdreset_drive(vi)); 190 } 191 192 /* 193 * Read pack label. 194 */ 195 vdattach(vi) 196 register struct vba_device *vi; 197 { 198 register int unit = vi->ui_unit; 199 register struct dksoftc *dk = &dksoftc[unit]; 200 register struct disklabel *lp; 201 202 if (vdwstart == 0) { 203 timeout(vdwatch, (caddr_t)0, hz); 204 vdwstart++; 205 } 206 /* 207 * Try to initialize device and read pack label. 208 */ 209 if (vdinit(vdminor(unit, 0), 0) != 0) { 210 printf(": unknown drive type"); 211 return; 212 } 213 /* 214 * Initialize invariant portion of 215 * dcb used for overlapped seeks. 216 */ 217 dk->dk_dcb.opcode = VDOP_SEEK; 218 dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 219 dk->dk_dcb.devselect = vi->ui_slave; 220 dk->dk_dcb.trailcnt = sizeof (trseek) / sizeof (long); 221 dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 222 dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 223 lp = &dklabel[unit]; 224 printf(": %s <ntrak %d, ncyl %d, nsec %d>", 225 lp->d_typename, lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 226 /* 227 * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 228 */ 229 if (vi->ui_dk >= 0) 230 dk_mspw[vi->ui_dk] = 120.0 / 231 (lp->d_rpm * lp->d_nsectors * lp->d_secsize); 232 #ifdef notyet 233 addwap(makedev(VDMAJOR, vdminor(unit, 0)), &dklabel[unit]); 234 #endif 235 } 236 237 /*ARGSUSED*/ 238 vdopen(dev, flags) 239 dev_t dev; 240 int flags; 241 { 242 register unit = vdunit(dev); 243 register struct disklabel *lp; 244 register struct dksoftc *dk; 245 register struct partition *pp; 246 struct vba_device *vi; 247 int s, error, part = vdpart(dev); 248 daddr_t start, end; 249 250 if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 251 return (ENXIO); 252 lp = &dklabel[unit]; 253 dk = &dksoftc[unit]; 254 255 s = spl7(); 256 while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 257 dk->dk_state != CLOSED) 258 sleep((caddr_t)dk, PZERO+1); 259 splx(s); 260 if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 261 if (error = vdinit(dev, flags)) 262 return (error); 263 /* 264 * Warn if a partion is opened 265 * that overlaps another partition which is open 266 * unless one is the "raw" partition (whole disk). 267 */ 268 #define RAWPART 2 /* 'c' partition */ /* XXX */ 269 if ((dk->dk_openpart & (1 << part)) == 0 && 270 part != RAWPART) { 271 pp = &lp->d_partitions[part]; 272 start = pp->p_offset; 273 end = pp->p_offset + pp->p_size; 274 for (pp = lp->d_partitions; 275 pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 276 if (pp->p_offset + pp->p_size <= start || 277 pp->p_offset >= end) 278 continue; 279 if (pp - lp->d_partitions == RAWPART) 280 continue; 281 if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 282 log(LOG_WARNING, 283 "dk%d%c: overlaps open partition (%c)\n", 284 unit, part + 'a', 285 pp - lp->d_partitions + 'a'); 286 } 287 } 288 if (part >= lp->d_npartitions) 289 return (ENXIO); 290 dk->dk_openpart |= 1 << part; 291 return (0); 292 } 293 294 vdclose(dev, flags) 295 dev_t dev; 296 int flags; 297 { 298 register int unit = vdunit(dev); 299 register struct dksoftc *dk = &dksoftc[unit]; 300 301 dk->dk_openpart &= ~(1 << vdpart(dev)); 302 #ifdef notdef 303 /* 304 * Should wait for i/o to complete on this partition 305 * even if others are open, but wait for work on blkflush(). 306 */ 307 if (dk->dk_openpart == 0) { 308 struct vba_device *vi = vddinfo[unit]; 309 int s; 310 311 s = spl7(); 312 /* can't sleep on b_actf, it might be async. */ 313 while (vi->ui_tab.b_actf) 314 sleep((caddr_t)&vi->ui_tab.b_actf, PZERO-1); 315 splx(s); 316 dk->dk_state = CLOSED; 317 } 318 #endif 319 } 320 321 vdinit(dev, flags) 322 dev_t dev; 323 int flags; 324 { 325 register struct buf *bp = NULL; 326 register struct disklabel *lp; 327 register struct dksoftc *dk; 328 struct vba_device *vi; 329 struct disklabel *dlp; 330 int unit = vdunit(dev), error = 0; 331 extern int cold; 332 333 dk = &dksoftc[unit]; 334 if (flags & O_NDELAY) { 335 dk->dk_state = OPENRAW; 336 goto done; 337 } 338 339 /* 340 * Initialize portion of the label 341 * not set up in the slave routine. 342 */ 343 dk->dk_bshift = 1; /* DEV_BSIZE / 512 */ 344 dk->dk_state = RDLABEL; 345 lp = &dklabel[unit]; 346 lp->d_secperunit = 0x1fffffff; 347 lp->d_npartitions = 1; 348 lp->d_partitions[0].p_size = 0x1fffffff; 349 lp->d_partitions[0].p_offset = 0; 350 351 bp = geteblk(DEV_BSIZE); /* max sector size */ 352 bp->b_dev = dev; 353 bp->b_blkno = LABELSECTOR; 354 bp->b_bcount = DEV_BSIZE; 355 bp->b_flags = B_BUSY | B_READ; 356 bp->b_cylin = LABELSECTOR / lp->d_secpercyl; 357 vdstrategy(bp); 358 biowait(bp); 359 if (bp->b_flags & B_ERROR) { 360 error = u.u_error; /* XXX */ 361 u.u_error = 0; 362 dk->dk_state = CLOSED; 363 goto done; 364 } 365 vi = vddinfo[unit]; 366 dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 367 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 368 dkcksum(dlp) == 0) { 369 *lp = *dlp; 370 /* 371 * Now that we have the label, configure 372 * the correct drive parameters. 373 */ 374 if (!vdreset_drive(vi)) 375 dk->dk_state = CLOSED; 376 else 377 dk->dk_state = OPEN; 378 } else { 379 if (cold) 380 printf(": no disk label"); 381 else 382 log(LOG_ERR, "dk%d: no disk label\n", vi->ui_unit); 383 #ifdef COMPAT_42 384 if (!vdmaptype(vi, lp)) { 385 error = ENXIO; 386 dk->dk_state = CLOSED; 387 } else 388 dk->dk_state = OPEN; 389 #else 390 dk->dk_state = OPENRAW; 391 #endif 392 } 393 done: 394 /* 395 * If open, calculate scaling shift for 396 * mapping DEV_BSIZE blocks to drive sectors. 397 */ 398 if (dk->dk_state == OPEN || dk->dk_state == OPENRAW) { 399 int mul = DEV_BSIZE / lp->d_secsize; 400 dk->dk_bshift = 0; 401 while ((mul >>= 1) > 0) 402 dk->dk_bshift++; 403 } 404 if (bp) { 405 bp->b_flags = B_INVAL | B_AGE; 406 brelse(bp); 407 } 408 wakeup((caddr_t)dk); 409 return (error); 410 } 411 412 /*ARGSUSED*/ 413 vddgo(vm) 414 struct vba_device *vm; 415 { 416 417 } 418 419 vdstrategy(bp) 420 register struct buf *bp; 421 { 422 register struct vba_device *vi; 423 register struct disklabel *lp; 424 register struct dksoftc *dk; 425 register int unit; 426 struct buf *dp; 427 daddr_t sz, sn, maxsz; 428 int part, s; 429 430 sz = bp->b_bcount; 431 sz = (sz + DEV_BSIZE - 1) >> DEV_BSHIFT; 432 unit = vdunit(bp->b_dev); 433 if (unit > NDK) { 434 bp->b_error = ENXIO; 435 goto bad; 436 } 437 vi = vddinfo[unit]; 438 lp = &dklabel[unit]; 439 if (vi == 0 || vi->ui_alive == 0) { 440 bp->b_error = ENXIO; 441 goto bad; 442 } 443 dk = &dksoftc[unit]; 444 if (dk->dk_state < OPEN) 445 goto q; 446 part = vdpart(bp->b_dev); 447 if ((dk->dk_openpart & (1 << part)) == 0) { 448 bp->b_error = ENODEV; 449 goto bad; 450 } 451 maxsz = lp->d_partitions[part].p_size; 452 sn = bp->b_blkno << dk->dk_bshift; 453 if (sn < 0 || sn + sz > maxsz) { 454 if (sn == maxsz) { 455 bp->b_resid = bp->b_bcount; 456 goto done; 457 } 458 bp->b_error = EINVAL; 459 goto bad; 460 } 461 bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 462 q: 463 vbasetup(bp, lp->d_secsize); 464 s = spl7(); 465 dp = &dkutab[vi->ui_unit]; 466 disksort(dp, bp); 467 if (!dp->b_active) { 468 (void) vdustart(vi); 469 bp = &vi->ui_mi->um_tab; 470 if (bp->b_actf && !bp->b_active) 471 vdstart(vi->ui_mi); 472 } 473 splx(s); 474 return; 475 bad: 476 bp->b_flags |= B_ERROR; 477 done: 478 biodone(bp); 479 return; 480 } 481 482 vdustart(vi) 483 register struct vba_device *vi; 484 { 485 register struct buf *bp, *dp; 486 register struct vba_ctlr *vm; 487 register int unit = vi->ui_unit; 488 register struct dksoftc *dk; 489 register struct vdsoftc *vd; 490 struct disklabel *lp; 491 492 dk_busy &= ~(1<<vi->ui_dk); 493 dp = &dkutab[unit]; 494 /* 495 * If queue empty, nothing to do. 496 */ 497 if ((bp = dp->b_actf) == NULL) 498 return; 499 /* 500 * If drive is off-cylinder, mark unit to force 501 * overlap seek with next transfer on this controller. 502 */ 503 vd = &vdsoftc[vi->ui_ctlr]; 504 dk = &dksoftc[unit]; 505 if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 506 int sn = bp->b_blkno << dk->dk_bshift; 507 lp = &dklabel[unit]; 508 bp->b_daddr = (sn % lp->d_secpercyl) / lp->d_nsectors; 509 if (bp->b_daddr != dk->dk_curdaddr) 510 vd->vd_offcyl |= 1 << vi->ui_slave; 511 } 512 /* 513 * If controller is not busy, place request on the 514 * controller's ready queue (unless its already there). 515 */ 516 if (!dp->b_active) { 517 dp->b_forw = NULL; 518 vm = vi->ui_mi; 519 if (vm->um_tab.b_actf == NULL) 520 vm->um_tab.b_actf = dp; 521 else 522 vm->um_tab.b_actl->b_forw = dp; 523 vm->um_tab.b_actl = dp; 524 dp->b_active++; 525 } 526 } 527 528 /* 529 * Start next transfer on a controller. 530 */ 531 vdstart(vm) 532 register struct vba_ctlr *vm; 533 { 534 register struct buf *bp; 535 register struct vba_device *vi; 536 register struct vdsoftc *vd; 537 register struct dksoftc *dk; 538 register struct disklabel *lp; 539 register int slave; 540 register struct dcb **dcbp; 541 struct mdcb *mdcb; 542 struct buf *dp; 543 int sn, tn; 544 545 loop: 546 /* 547 * Pull a request off the controller queue. 548 */ 549 if ((dp = vm->um_tab.b_actf) == NULL) 550 return; 551 if ((bp = dp->b_actf) == NULL) { 552 vm->um_tab.b_actf = dp->b_forw; 553 goto loop; 554 } 555 556 /* 557 * Mark controller busy, and determine 558 * destination of this request. 559 */ 560 vm->um_tab.b_active++; 561 vi = vddinfo[vdunit(bp->b_dev)]; 562 dk = &dksoftc[vi->ui_unit]; 563 sn = bp->b_blkno << dk->dk_bshift; 564 lp = &dklabel[vi->ui_unit]; 565 sn %= lp->d_secpercyl; 566 tn = sn / lp->d_nsectors; 567 sn %= lp->d_nsectors; 568 569 /* 570 * Construct dcb for read/write command. 571 */ 572 vd = &vdsoftc[vm->um_ctlr]; 573 slave = vi->ui_slave; 574 vd->vd_dcb.opcode = (bp->b_flags & B_READ) ? VDOP_RD : VDOP_WD; 575 vd->vd_dcb.intflg = DCBINT_DONE; 576 vd->vd_dcb.devselect = slave; 577 vd->vd_dcb.operrsta = 0; 578 vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 579 vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 580 vd->vd_dcb.trail.rwtrail.memadr = (char *) 581 vbastart(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl); 582 vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 583 vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 584 vd->vd_dcb.trail.rwtrail.disk.track = tn; 585 vd->vd_dcb.trail.rwtrail.disk.sector = sn; 586 587 /* 588 * Look for any seeks to be performed on other drives on this 589 * controller. If overlapped seeks exist, insert seek commands 590 * on the controller's command queue before the transfer. 591 */ 592 dcbp = &vd->vd_mdcb.mdcb_head; 593 if (vd->vd_offcyl &~ (1<<slave)) { 594 register struct dksoftc *tdk; 595 register struct buf *tp; 596 597 for (dp = dp->b_forw; dp != NULL; dp = dp->b_forw) { 598 if ((tp = dp->b_actf) == NULL) 599 continue; 600 slave = (vi = vddinfo[vdunit(tp->b_dev)])->ui_slave; 601 if ((vd->vd_offcyl & (1<<slave)) == 0) 602 continue; 603 vd->vd_offcyl &= ~(1 << slave); 604 tdk = &dksoftc[vi->ui_unit]; 605 if (tdk->dk_curcyl != tp->b_cylin) { 606 tdk->dk_curcyl = tp->b_cylin; 607 dk_seek[vi->ui_dk]++; 608 } 609 tdk->dk_curdaddr = tp->b_daddr; 610 tdk->dk_dcb.operrsta = 0; 611 tdk->dk_dcb.trail.sktrail.skaddr.cylinder = tp->b_cylin; 612 tdk->dk_dcb.trail.sktrail.skaddr.track = tp->b_daddr>>8; 613 tdk->dk_dcb.trail.sktrail.skaddr.sector = 614 tp->b_daddr & 0xff; 615 *dcbp = (struct dcb *)tdk->dk_dcbphys; 616 dcbp = &tdk->dk_dcb.nxtdcb; 617 } 618 } else { 619 dk->dk_curcyl = bp->b_cylin; 620 dk->dk_curdaddr = (tn << 8) | sn; 621 vd->vd_offcyl = 0; 622 } 623 *dcbp = (struct dcb *)vd->vd_dcbphys; 624 625 /* 626 * Initiate operation. 627 */ 628 bp->b_daddr = 0; /* init overloaded field */ 629 if (vi->ui_dk >= 0) { 630 dk_busy |= 1<<vi->ui_dk; 631 dk_xfer[vi->ui_dk]++; 632 dk_wds[vi->ui_dk] += bp->b_bcount>>6; 633 } 634 vd->vd_mdcb.mdcb_status = 0; 635 VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 636 } 637 638 #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 639 /* 640 * Handle a disk interrupt. 641 */ 642 vdintr(ctlr) 643 register ctlr; 644 { 645 register struct buf *bp, *dp; 646 register struct vba_ctlr *vm = vdminfo[ctlr]; 647 register struct vba_device *vi; 648 register struct vdsoftc *vd = &vdsoftc[ctlr]; 649 register status; 650 651 vd->vd_wticks = 0; 652 if (!vm->um_tab.b_active) { 653 printf("vd%d: stray interrupt\n", ctlr); 654 return; 655 } 656 /* 657 * Get device and block structures, and a pointer 658 * to the vba_device for the drive. 659 */ 660 dp = vm->um_tab.b_actf; 661 bp = dp->b_actf; 662 vi = vddinfo[vdunit(bp->b_dev)]; 663 dk_busy &= ~(1<<vi->ui_dk); 664 /* 665 * Check for and process errors on 666 * either the drive or the controller. 667 */ 668 uncache(&vd->vd_dcb.operrsta); 669 status = vd->vd_dcb.operrsta; 670 if (status & VDERR_HARD) { 671 if (status & DCBS_WPT) { 672 /* 673 * Give up on write locked devices immediately. 674 */ 675 printf("dk%d: write locked\n", vdunit(bp->b_dev)); 676 bp->b_flags |= B_ERROR; 677 } else if (status & VDERR_SOFT) { 678 if (status & VDERR_DRIVE) { 679 if (!vdreset_drive(vi)) 680 vi->ui_alive = 0; 681 } else if (status & VDERR_CTLR) 682 vdreset_ctlr(vm); 683 /* 684 * Retry transfer once, unless reset failed. 685 */ 686 if (!vi->ui_alive || bp->b_errcnt++ >= 2) 687 goto hard; 688 vm->um_tab.b_active = 0; /* force retry */ 689 } else { 690 hard: 691 bp->b_flags |= B_ERROR; 692 /* NEED TO ADJUST b_blkno to failed sector */ 693 harderr(bp, "dk"); 694 printf("status %x (%b)", status, 695 status &~ DONTCARE, VDERRBITS); 696 if (vd->vd_type == VDTYPE_SMDE) { 697 uncache(&vd->vd_dcb.err_code); 698 printf(" ecode %x", vd->vd_dcb.err_code); 699 } 700 printf("\n"); 701 } 702 } else if (status & DCBS_SOFT) 703 vdsofterr(vd, bp, &vd->vd_dcb); 704 if (vm->um_tab.b_active) { 705 vm->um_tab.b_active = 0; 706 vm->um_tab.b_errcnt = 0; 707 vm->um_tab.b_actf = dp->b_forw; 708 dp->b_active = 0; 709 dp->b_errcnt = 0; 710 dp->b_actf = bp->av_forw; 711 bp->b_resid = 0; 712 vbadone(bp, vd->vd_rawbuf, (long *)vd->vd_map, vd->vd_utl); 713 biodone(bp); 714 /* 715 * If this unit has more work to do, 716 * then start it up right away. 717 */ 718 if (dp->b_actf) 719 vdustart(vi); 720 } 721 /* 722 * If there are devices ready to 723 * transfer, start the controller. 724 */ 725 if (vm->um_tab.b_actf) 726 vdstart(vm); 727 } 728 729 vdsofterr(vd, bp, dcb) 730 struct vdsoftc *vd; 731 register struct buf *bp; 732 register struct dcb *dcb; 733 { 734 int unit = vdunit(bp->b_dev), status = dcb->operrsta; 735 char part = 'a' + vdpart(bp->b_dev); 736 737 if (status != (DCBS_DCE|DCBS_CCD|DCBS_SOFT|DCBS_ERR)) { 738 if (vd->vd_type == VDTYPE_SMDE) 739 uncache(&dcb->err_code); 740 log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n", 741 unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code); 742 } else 743 log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n", 744 unit, part, bp->b_blkno); 745 } 746 747 vdread(dev, uio) 748 dev_t dev; 749 struct uio *uio; 750 { 751 register int unit = vdunit(dev); 752 753 if (unit >= NDK) 754 return (ENXIO); 755 return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio)); 756 } 757 758 vdwrite(dev, uio) 759 dev_t dev; 760 struct uio *uio; 761 { 762 register int unit = vdunit(dev); 763 764 if (unit >= NDK) 765 return (ENXIO); 766 return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio)); 767 } 768 769 vdioctl(dev, cmd, data, flag) 770 dev_t dev; 771 int cmd; 772 caddr_t data; 773 int flag; 774 { 775 int unit = vdunit(dev); 776 register struct disklabel *lp = &dklabel[unit]; 777 int error = 0; 778 779 switch (cmd) { 780 781 case DIOCGDINFO: 782 *(struct disklabel *)data = *lp; 783 break; 784 785 case DIOCGDINFOP: 786 *(struct disklabel **)data = lp; 787 break; 788 789 case DIOCSDINFO: 790 if ((flag & FWRITE) == 0) 791 error = EBADF; 792 else 793 *lp = *(struct disklabel *)data; 794 break; 795 796 case DIOCWDINFO: { 797 struct buf *bp; 798 struct disklabel *dlp; 799 800 if ((flag & FWRITE) == 0) { 801 error = EBADF; 802 break; 803 } 804 *lp = *(struct disklabel *)data; 805 bp = geteblk(lp->d_secsize); 806 bp->b_dev = dev; 807 bp->b_blkno = LABELSECTOR; 808 bp->b_bcount = lp->d_secsize; 809 bp->b_flags = B_READ; 810 dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); 811 vdstrategy(bp); 812 biowait(bp); 813 if (bp->b_flags & B_ERROR) { 814 error = u.u_error; /* XXX */ 815 u.u_error = 0; 816 goto bad; 817 } 818 *dlp = *lp; 819 bp->b_flags = B_WRITE; 820 vdstrategy(bp); 821 biowait(bp); 822 if (bp->b_flags & B_ERROR) { 823 error = u.u_error; /* XXX */ 824 u.u_error = 0; 825 } 826 bad: 827 brelse(bp); 828 break; 829 } 830 831 default: 832 error = ENOTTY; 833 break; 834 } 835 return (0); 836 } 837 838 /* 839 * Watch for lost interrupts. 840 */ 841 vdwatch() 842 { 843 register struct vdsoftc *vd; 844 register struct vba_ctlr *vm; 845 register int ctlr, unit; 846 847 timeout(vdwatch, (caddr_t)0, hz); 848 for (ctlr = 0; ctlr < NVD; ctlr++) { 849 vm = vdminfo[ctlr]; 850 if (vm == 0 || vm->um_alive == 0) 851 continue; 852 vd = &vdsoftc[ctlr]; 853 if (!vm->um_tab.b_active) { 854 for (unit = 0; unit < NDK; unit++) 855 if (dkutab[unit].b_active && 856 vddinfo[unit]->ui_mi == vm) 857 goto active; 858 vd->vd_wticks = 0; 859 continue; 860 } 861 active: 862 vd->vd_wticks++; 863 if (vd->vd_wticks >= 20) { 864 vd->vd_wticks = 0; 865 printf("vd%d: lost interrupt\n", ctlr); 866 /* abort pending dcb's and restart controller */ 867 } 868 } 869 } 870 871 #define DBSIZE 64 /* controller limit with 1K sectors */ 872 /* 873 * Crash dump. 874 */ 875 vddump(dev) 876 dev_t dev; 877 { 878 register struct vba_device *vi; 879 register struct vba_ctlr *vm; 880 register struct disklabel *lp; 881 register struct vdsoftc *vd; 882 struct dksoftc *dk; 883 int part, unit, num; 884 caddr_t start; 885 886 start = 0; 887 unit = vdunit(dev); 888 if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 889 return (ENXIO); 890 dk = &dksoftc[unit]; 891 if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 892 return (ENXIO); 893 lp = &dklabel[unit]; 894 part = vdpart(dev); 895 if (part >= lp->d_npartitions) 896 return (ENXIO); 897 vm = vdminfo[vi->ui_ctlr]; 898 vdreset_ctlr(vm); 899 if (dumplo < 0) 900 return (EINVAL); 901 /* 902 * Dumplo and maxfree are in pages; 903 * dumplo will change soon (XXX). 904 */ 905 num = maxfree * (NBPG / lp->d_secsize); 906 dumplo *= NBPG / lp->d_secsize; /* XXX */ 907 if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 908 num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 909 vd = &vdsoftc[vm->um_ctlr]; 910 vd->vd_dcb.intflg = DCBINT_NONE; 911 vd->vd_dcb.opcode = VDOP_WD; 912 vd->vd_dcb.devselect = vi->ui_slave; 913 vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 914 while (num > 0) { 915 int nsec, cn, sn, tn; 916 917 nsec = MIN(num, DBSIZE); 918 sn = dumplo + (unsigned)start / lp->d_secsize; 919 cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 920 lp->d_secpercyl; 921 sn %= lp->d_secpercyl; 922 tn = sn / lp->d_nsectors; 923 sn %= lp->d_nsectors; 924 vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 925 vd->vd_dcb.trail.rwtrail.memadr = start; 926 vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 927 vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 928 vd->vd_dcb.trail.rwtrail.disk.track = tn; 929 vd->vd_dcb.trail.rwtrail.disk.sector = sn; 930 vd->vd_dcb.operrsta = 0; 931 VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 932 if (!vdpoll(vm, 5)) { 933 printf(" during dump\n"); 934 return (EIO); 935 } 936 if (vd->vd_dcb.operrsta & VDERR_HARD) { 937 printf("dk%d: hard error, status=%b\n", unit, 938 vd->vd_dcb.operrsta, VDERRBITS); 939 return (EIO); 940 } 941 start += nsec * lp->d_secsize; 942 num -= nsec; 943 } 944 return (0); 945 } 946 947 vdsize(dev) 948 dev_t dev; 949 { 950 register int unit = vdunit(dev); 951 register struct dksoftc *dk; 952 struct vba_device *vi; 953 struct disklabel *lp; 954 955 if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 956 (dk = &dksoftc[unit])->dk_state != OPEN) 957 return (-1); 958 lp = &dklabel[unit]; 959 return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 960 } 961 962 /* 963 * Perform a controller reset. 964 */ 965 vdreset_ctlr(vm) 966 register struct vba_ctlr *vm; 967 { 968 register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 969 register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 970 register int unit; 971 struct vba_device *vi; 972 973 VDRESET(vdaddr, vd->vd_type); 974 if (vd->vd_type == VDTYPE_SMDE) { 975 vdaddr->vdcsr = 0; 976 vdaddr->vdtcf_mdcb = AM_ENPDA; 977 vdaddr->vdtcf_dcb = AM_ENPDA; 978 vdaddr->vdtcf_trail = AM_ENPDA; 979 vdaddr->vdtcf_data = AM_ENPDA; 980 vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 981 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 982 } 983 if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) { 984 printf("%s cmd failed\n", 985 vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 986 return; 987 } 988 for (unit = 0; unit < NDK; unit++) 989 if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) 990 (void) vdreset_drive(vi); 991 } 992 993 vdreset_drive(vi) 994 register struct vba_device *vi; 995 { 996 register struct disklabel *lp = &dklabel[vi->ui_unit]; 997 struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 998 struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 999 struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 1000 1001 top: 1002 vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 1003 vd->vd_dcb.intflg = DCBINT_NONE; 1004 vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1005 vd->vd_dcb.operrsta = 0; 1006 vd->vd_dcb.devselect = vi->ui_slave; 1007 vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 1008 vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 1009 if (vd->vd_type == VDTYPE_SMDE) { 1010 vd->vd_dcb.trailcnt = sizeof (treset) / sizeof (long); 1011 vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 1012 vd->vd_dcb.trail.rstrail.slip_sec = lp->d_trackskew; 1013 vd->vd_dcb.trail.rstrail.recovery = 0x18f; 1014 } else 1015 vd->vd_dcb.trailcnt = 2; /* XXX */ 1016 vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1017 vd->vd_mdcb.mdcb_status = 0; 1018 VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 1019 if (!vdpoll(vm, 5)) { 1020 printf(" during config\n"); 1021 return (0); 1022 } 1023 if (vd->vd_dcb.operrsta & VDERR_HARD) { 1024 if (vd->vd_type == VDTYPE_SMDE && 1025 (vdaddr->vdstatus[vi->ui_slave]&STA_US) == 0) 1026 return (0); 1027 if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) 1028 printf("dk%d: config error\n", vi->ui_unit); 1029 else if ((vd->vd_flags&VD_STARTED) == 0) { 1030 int started; 1031 1032 printf("vd%d: starting drives, wait ... ", vm->um_ctlr); 1033 vd->vd_flags |= VD_STARTED; 1034 started = (vdcmd(vm, VDOP_START, 10) == 1); 1035 DELAY(62000000); 1036 printf("\n"); 1037 if (started) 1038 goto top; 1039 } 1040 return (0); 1041 } 1042 return (1); 1043 } 1044 1045 /* 1046 * Perform a command w/o trailer. 1047 */ 1048 vdcmd(vm, cmd, t) 1049 register struct vba_ctlr *vm; 1050 { 1051 register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 1052 1053 vd->vd_dcb.opcode = cmd; /* command */ 1054 vd->vd_dcb.intflg = DCBINT_NONE; 1055 vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1056 vd->vd_dcb.operrsta = 0; 1057 vd->vd_dcb.devselect = 0; 1058 vd->vd_dcb.trailcnt = 0; 1059 vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1060 vd->vd_mdcb.mdcb_status = 0; 1061 VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 1062 if (!vdpoll(vm, t)) { 1063 printf(" during init\n"); 1064 return (0); 1065 } 1066 return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 1067 } 1068 1069 /* 1070 * Poll controller until operation 1071 * completes or timeout expires. 1072 */ 1073 vdpoll(vm, t) 1074 register struct vba_ctlr *vm; 1075 register int t; 1076 { 1077 register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 1078 register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 1079 1080 t *= 1000; 1081 for (;;) { 1082 uncache(&vd->vd_dcb.operrsta); 1083 if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 1084 break; 1085 if (--t <= 0) { 1086 printf("vd%d: controller timeout", vm->um_ctlr); 1087 VDABORT(vdaddr, vd->vd_type); 1088 DELAY(30000); 1089 return (0); 1090 } 1091 DELAY(1000); 1092 } 1093 if (vd->vd_type == VDTYPE_SMDE) { 1094 do { 1095 DELAY(50); 1096 uncache(&vdaddr->vdcsr); 1097 } while (vdaddr->vdcsr & CS_GO); 1098 DELAY(300); 1099 } 1100 DELAY(200); 1101 uncache(&vd->vd_dcb.operrsta); 1102 return (1); 1103 } 1104 1105 #ifdef COMPAT_42 1106 struct vdst { 1107 int nsec; /* sectors/track */ 1108 int ntrack; /* tracks/cylinder */ 1109 int ncyl; /* cylinders */ 1110 char *name; /* type name */ 1111 struct { 1112 int off; /* partition offset in sectors */ 1113 int size; /* partition size in sectors */ 1114 } parts[3]; 1115 } vdst[] = { 1116 { 48, 24, 711, "xsd", {0,61056}, {61056,61056}, {122112,691200} }, 1117 { 44, 20, 842, "egl", {0,52800}, {52800,66000}, {118800,617760} }, 1118 { 64, 10, 823, "fuj", {0,38400}, {38400,48000}, { 86400,437120} }, 1119 { 32, 24, 711, "xfd", {0,40704}, {40704,40704}, { 81408,460800} }, 1120 { 32, 19, 823, "smd", {0,40128}, {40128,27360}, { 67488,429856} }, 1121 { 32, 10, 823, "fsd", {0,19200}, {19200,24000}, { 43200,218560} } 1122 }; 1123 #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 1124 1125 /* 1126 * Construct a label for an unlabeled pack. We 1127 * deduce the drive type by reading from the last 1128 * track on successively smaller drives until we 1129 * don't get an error. 1130 */ 1131 vdmaptype(vi, lp) 1132 register struct vba_device *vi; 1133 register struct disklabel *lp; 1134 { 1135 register struct vdsoftc *vd; 1136 register struct vdst *p; 1137 struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 1138 int i; 1139 1140 vd = &vdsoftc[vi->ui_ctlr]; 1141 for (p = vdst; p < &vdst[NVDST]; p++) { 1142 if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 1143 continue; 1144 lp->d_nsectors = p->nsec; 1145 lp->d_ntracks = p->ntrack; 1146 lp->d_ncylinders = p->ncyl; 1147 if (!vdreset_drive(vi)) 1148 return (0); 1149 vd->vd_dcb.opcode = VDOP_RD; 1150 vd->vd_dcb.intflg = DCBINT_NONE; 1151 vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1152 vd->vd_dcb.devselect = vi->ui_slave; 1153 vd->vd_dcb.trailcnt = sizeof (trrw) / sizeof (long); 1154 vd->vd_dcb.trail.rwtrail.memadr = (char *) 1155 vtoph((struct proc *)0, (unsigned)vd->vd_rawbuf); 1156 vd->vd_dcb.trail.rwtrail.wcount = 512 / sizeof(short); 1157 vd->vd_dcb.operrsta = 0; 1158 vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 1159 vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 1160 vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 1161 vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1162 vd->vd_mdcb.mdcb_status = 0; 1163 VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 1164 if (!vdpoll(vm, 60)) 1165 printf(" during probe\n"); 1166 if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 1167 break; 1168 } 1169 if (p >= &vdst[NVDST]) { 1170 printf("dk%d: unknown drive type\n", vi->ui_unit); 1171 return (0); 1172 } 1173 for (i = 0; i < 3; i++) { 1174 lp->d_partitions[i].p_offset = p->parts[i].off; 1175 lp->d_partitions[i].p_size = p->parts[i].size; 1176 } 1177 lp->d_npartitions = 3; 1178 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1179 lp->d_rpm = 3600; 1180 lp->d_secsize = 512; 1181 bcopy(p->name, lp->d_typename, 4); 1182 return (1); 1183 } 1184 #endif COMPAT_42 1185 #endif 1186