1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Computer Consoles Inc. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)vd.c 7.14 (Berkeley) 04/01/91 11 */ 12 13 #include "dk.h" 14 #if NVD > 0 15 /* 16 * Versabus VDDC/SMDE driver. 17 */ 18 #include "sys/param.h" 19 #include "sys/buf.h" 20 #include "sys/cmap.h" 21 #include "sys/conf.h" 22 #include "sys/dkstat.h" 23 #include "sys/disklabel.h" 24 #include "sys/map.h" 25 #include "sys/file.h" 26 #include "sys/systm.h" 27 #include "sys/user.h" 28 #include "sys/vmmac.h" 29 #include "sys/proc.h" 30 #include "sys/syslog.h" 31 #include "sys/kernel.h" 32 #include "sys/ioctl.h" 33 #include "sys/stat.h" 34 35 #include "../include/cpu.h" 36 #include "../include/mtpr.h" 37 #include "../include/pte.h" 38 39 #include "../vba/vbavar.h" 40 #include "../vba/vdreg.h" 41 42 #ifndef COMPAT_42 43 #define COMPAT_42 44 #endif 45 #define B_FORMAT B_XXX /* XXX */ 46 47 #define vdunit(dev) (minor(dev) >> 3) 48 #define vdpart(dev) (minor(dev) & 0x07) 49 #define vdminor(unit,part) (((unit) << 3) | (part)) 50 51 struct vba_ctlr *vdminfo[NVD]; 52 struct vba_device *vddinfo[NDK]; 53 int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy(); 54 long vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; 55 struct vba_driver vddriver = 56 { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo }; 57 58 /* 59 * Per-controller state. 60 */ 61 struct vdsoftc { 62 u_short vd_flags; 63 #define VD_PRINT 0x1 /* controller info printed */ 64 #define VD_STARTED 0x2 /* start command issued */ 65 #define VD_DOSEEKS 0x4 /* should overlap seeks */ 66 #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */ 67 #define VD_LOCKED 0x10 /* locked for direct controller access */ 68 #define VD_WAIT 0x20 /* someone needs direct controller access */ 69 u_short vd_type; /* controller type */ 70 u_short vd_wticks; /* timeout */ 71 u_short vd_secsize; /* sector size for controller */ 72 struct mdcb vd_mdcb; /* master command block */ 73 u_long vd_mdcbphys; /* physical address of vd_mdcb */ 74 struct dcb vd_dcb; /* i/o command block */ 75 u_long vd_dcbphys; /* physical address of vd_dcb */ 76 struct vb_buf vd_rbuf; /* vba resources */ 77 } vdsoftc[NVD]; 78 79 #define VDMAXTIME 20 /* max time for operation, sec. */ 80 81 /* 82 * Per-drive state. 83 */ 84 struct dksoftc { 85 int dk_state; /* open fsm */ 86 #ifndef SECSIZE 87 u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 88 #endif SECSIZE 89 int dk_wlabel; /* label sector is currently writable */ 90 u_long dk_copenpart; /* character units open on this drive */ 91 u_long dk_bopenpart; /* block units open on this drive */ 92 u_long dk_openpart; /* all units open on this drive */ 93 u_int dk_curcyl; /* last selected cylinder */ 94 struct skdcb dk_dcb; /* seek command block */ 95 u_long dk_dcbphys; /* physical address of dk_dcb */ 96 int df_reg[3]; /* for formatting, in-out parameters */ 97 } dksoftc[NDK]; 98 99 /* 100 * Drive states. Used during steps of open/initialization. 101 * States < OPEN (> 0) are transient, during an open operation. 102 * OPENRAW is used for unlabeled disks, to allow format operations. 103 */ 104 #define CLOSED 0 /* disk is closed */ 105 #define WANTOPEN 1 /* open requested, not started */ 106 #define WANTOPENRAW 2 /* open requested, no label */ 107 #define RDLABEL 3 /* reading pack label */ 108 #define OPEN 4 /* intialized and ready */ 109 #define OPENRAW 5 /* open, no label */ 110 111 struct buf dkutab[NDK]; /* i/o queue headers */ 112 struct disklabel dklabel[NDK]; /* pack labels */ 113 114 #define b_cylin b_resid 115 #define b_track b_error /* used for seek commands */ 116 #define b_seekf b_forw /* second queue on um_tab */ 117 #define b_seekl b_back /* second queue on um_tab */ 118 119 int vdwstart, vdwatch(); 120 121 /* 122 * See if the controller is really there; if so, initialize it. 123 */ 124 vdprobe(reg, vm) 125 caddr_t reg; 126 struct vba_ctlr *vm; 127 { 128 register br, cvec; /* must be r12, r11 */ 129 register struct vddevice *vdaddr = (struct vddevice *)reg; 130 struct vdsoftc *vd; 131 int s; 132 133 #ifdef lint 134 br = 0; cvec = br; br = cvec; 135 vdintr(0); 136 #endif 137 if (badaddr((caddr_t)reg, 2)) 138 return (0); 139 vd = &vdsoftc[vm->um_ctlr]; 140 vdaddr->vdreset = 0xffffffff; 141 DELAY(1000000); 142 if (vdaddr->vdreset != (unsigned)0xffffffff) { 143 vd->vd_type = VDTYPE_VDDC; 144 vd->vd_flags &= ~VD_DOSEEKS; 145 DELAY(1000000); 146 } else { 147 vd->vd_type = VDTYPE_SMDE; 148 vd->vd_flags |= VD_DOSEEKS; 149 vdaddr->vdrstclr = 0; 150 DELAY(3000000); 151 } 152 vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); 153 vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); 154 vm->um_addr = reg; /* XXX */ 155 s = spl7(); 156 if (vdinit_ctlr(vm, vd) == 0) { 157 splx(s); 158 return (0); 159 } 160 if (vd->vd_type == VDTYPE_SMDE) { 161 #ifdef notdef 162 /* 163 * Attempt PROBE to get all drive status; 164 * we take advantage of this in vdreset_drive 165 * to try to avoid guessing games. 166 */ 167 (void) vdcmd(vm, VDOP_PROBE, 5, 0); 168 #endif 169 /* 170 * Check for scatter-gather by checking firmware date 171 * with IDENT command. The date is printed when 172 * vdslave is first called, thus this must be 173 * the last controller operation in vdprobe. 174 */ 175 vd->vd_dcb.trail.idtrail.date = 0; 176 if (vdcmd(vm, VDOP_IDENT, 10, 0)) { 177 uncache(&vd->vd_dcb.trail.idtrail.date); 178 if (vd->vd_dcb.trail.idtrail.date != 0) 179 vd->vd_flags |= VD_SCATGATH; 180 } 181 } 182 splx(s); 183 /* 184 * Allocate page tables and i/o buffer. 185 */ 186 if (vbainit(&vd->vd_rbuf, MAXPHYS, 187 vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { 188 printf("vd%d: vbainit failed\n", vm->um_ctlr); 189 return (0); 190 } 191 br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 192 return (sizeof (struct vddevice)); 193 } 194 195 /* 196 * See if a drive is really there. 197 * 198 * Can't read pack label here as various data structures 199 * aren't setup for doing a read in a straightforward 200 * manner. Instead just probe for the drive and leave 201 * the pack label stuff to the attach routine. 202 */ 203 /* ARGSUSED */ 204 vdslave(vi, vdaddr) 205 register struct vba_device *vi; 206 struct vddevice *vdaddr; 207 { 208 register struct disklabel *lp = &dklabel[vi->ui_unit]; 209 register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 210 struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 211 int bcd(); 212 213 if ((vd->vd_flags&VD_PRINT) == 0) { 214 printf("vd%d: %s controller", vi->ui_ctlr, 215 vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); 216 if (vd->vd_flags & VD_SCATGATH) { 217 char rev[5]; 218 219 bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev, 220 sizeof(vd->vd_dcb.trail.idtrail.rev)); 221 printf(" firmware rev %s (%d-%d-%d)", rev, 222 bcd((vd->vd_dcb.trail.idtrail.date >> 8) & 0xff), 223 bcd(vd->vd_dcb.trail.idtrail.date & 0xff), 224 bcd((vd->vd_dcb.trail.idtrail.date >> 16)&0xffff)); 225 } 226 printf("\n"); 227 vd->vd_flags |= VD_PRINT; 228 } 229 230 /* 231 * Initialize label enough to do a reset on 232 * the drive. The remainder of the default 233 * label values will be filled in in vdinit 234 * at attach time. 235 */ 236 if (vd->vd_type == VDTYPE_SMDE) 237 lp->d_secsize = VD_MAXSECSIZE; 238 else 239 lp->d_secsize = VDDC_SECSIZE; 240 lp->d_nsectors = 66; /* only used on smd-e */ 241 lp->d_ntracks = 23; 242 lp->d_ncylinders = 850; 243 lp->d_secpercyl = 66*23; 244 lp->d_rpm = 3600; 245 lp->d_npartitions = 1; 246 lp->d_partitions[0].p_offset = 0; 247 lp->d_partitions[0].p_size = LABELSECTOR + 1; 248 249 /* 250 * Initialize invariant portion of 251 * dcb used for overlapped seeks. 252 */ 253 dk->dk_dcb.opcode = VDOP_SEEK; 254 dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; 255 dk->dk_dcb.devselect = vi->ui_slave; 256 dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); 257 dk->dk_dcb.trail.sktrail.skaddr.sector = 0; 258 dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); 259 #ifndef SECSIZE 260 vd_setsecsize(dk, lp); 261 #endif 262 return (vdreset_drive(vi)); 263 } 264 265 static int 266 bcd(n) 267 register u_int n; 268 { 269 register int bin = 0; 270 register int mul = 1; 271 272 while (n) { 273 bin += (n & 0xf) * mul; 274 n >>= 4; 275 mul *= 10; 276 } 277 return (bin); 278 } 279 280 vdattach(vi) 281 register struct vba_device *vi; 282 { 283 register int unit = vi->ui_unit; 284 register struct disklabel *lp = &dklabel[unit]; 285 286 /* 287 * Try to initialize device and read pack label. 288 */ 289 if (vdinit(vdminor(unit, 0), 0) != 0) { 290 printf(": unknown drive type"); 291 return; 292 } 293 if (dksoftc[unit].dk_state == OPEN) 294 printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 295 lp->d_typename, lp->d_secsize, 296 lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); 297 /* 298 * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 299 */ 300 if (vi->ui_dk >= 0) 301 dk_wpms[vi->ui_dk] = 302 (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120; 303 #ifdef notyet 304 addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); 305 #endif 306 } 307 308 vdopen(dev, flags, fmt) 309 dev_t dev; 310 int flags, fmt; 311 { 312 register unit = vdunit(dev); 313 register struct disklabel *lp; 314 register struct dksoftc *dk; 315 register struct partition *pp; 316 struct vba_device *vi; 317 int s, error = 0, part = vdpart(dev), mask = 1 << part; 318 daddr_t start, end; 319 320 if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 321 return (ENXIO); 322 lp = &dklabel[unit]; 323 dk = &dksoftc[unit]; 324 325 s = spl7(); 326 while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 327 dk->dk_state != CLOSED) 328 if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, devopn, 0)) 329 break; 330 splx(s); 331 if (error) 332 return (error); 333 if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 334 if (error = vdinit(dev, flags)) 335 return (error); 336 337 if (vdwstart == 0) { 338 timeout(vdwatch, (caddr_t)0, hz); 339 vdwstart++; 340 } 341 /* 342 * Warn if a partion is opened 343 * that overlaps another partition which is open 344 * unless one is the "raw" partition (whole disk). 345 */ 346 #define RAWPART 8 /* 'x' partition */ /* XXX */ 347 if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { 348 pp = &lp->d_partitions[part]; 349 start = pp->p_offset; 350 end = pp->p_offset + pp->p_size; 351 for (pp = lp->d_partitions; 352 pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 353 if (pp->p_offset + pp->p_size <= start || 354 pp->p_offset >= end) 355 continue; 356 if (pp - lp->d_partitions == RAWPART) 357 continue; 358 if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 359 log(LOG_WARNING, 360 "dk%d%c: overlaps open partition (%c)\n", 361 unit, part + 'a', 362 pp - lp->d_partitions + 'a'); 363 } 364 } 365 if (part >= lp->d_npartitions) 366 return (ENXIO); 367 dk->dk_openpart |= mask; 368 switch (fmt) { 369 case S_IFCHR: 370 dk->dk_copenpart |= mask; 371 break; 372 case S_IFBLK: 373 dk->dk_bopenpart |= mask; 374 break; 375 } 376 return (0); 377 } 378 379 /* ARGSUSED */ 380 vdclose(dev, flags, fmt) 381 dev_t dev; 382 int flags, fmt; 383 { 384 register int unit = vdunit(dev); 385 register struct dksoftc *dk = &dksoftc[unit]; 386 int part = vdpart(dev), mask = 1 << part; 387 388 switch (fmt) { 389 case S_IFCHR: 390 dk->dk_copenpart &= ~mask; 391 break; 392 case S_IFBLK: 393 dk->dk_bopenpart &= ~mask; 394 break; 395 } 396 if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 397 dk->dk_openpart &= ~mask; 398 /* 399 * Should wait for i/o to complete on this partition 400 * even if others are open, but wait for work on blkflush(). 401 */ 402 if (dk->dk_openpart == 0) { 403 int s = spl7(); 404 while (dkutab[unit].b_actf) 405 sleep((caddr_t)dk, PZERO-1); 406 splx(s); 407 dk->dk_state = CLOSED; 408 dk->dk_wlabel = 0; 409 } 410 return (0); 411 } 412 413 vdinit(dev, flags) 414 dev_t dev; 415 int flags; 416 { 417 register struct disklabel *lp; 418 register struct dksoftc *dk; 419 struct vba_device *vi; 420 int unit = vdunit(dev), error = 0; 421 char *msg, *readdisklabel(); 422 extern int cold; 423 424 dk = &dksoftc[unit]; 425 if (flags & O_NDELAY) { 426 dk->dk_state = OPENRAW; 427 return (0); 428 } 429 dk->dk_state = RDLABEL; 430 lp = &dklabel[unit]; 431 vi = vddinfo[unit]; 432 if (msg = readdisklabel(dev, vdstrategy, lp)) { 433 if (cold) { 434 printf(": %s", msg); 435 dk->dk_state = CLOSED; 436 } else { 437 log(LOG_ERR, "dk%d: %s\n", unit, msg); 438 dk->dk_state = OPENRAW; 439 } 440 #ifdef COMPAT_42 441 vdlock(vi->ui_ctlr); 442 if (vdmaptype(vi, lp)) 443 dk->dk_state = OPEN; 444 vdunlock(vi->ui_ctlr); 445 #endif 446 } else { 447 /* 448 * Now that we have the label, configure 449 * the correct drive parameters. 450 */ 451 vdlock(vi->ui_ctlr); 452 if (vdreset_drive(vi)) 453 dk->dk_state = OPEN; 454 else { 455 dk->dk_state = CLOSED; 456 error = ENXIO; 457 } 458 vdunlock(vi->ui_ctlr); 459 } 460 #ifndef SECSIZE 461 vd_setsecsize(dk, lp); 462 #endif 463 wakeup((caddr_t)dk); 464 return (error); 465 } 466 467 #ifndef SECSIZE 468 vd_setsecsize(dk, lp) 469 register struct dksoftc *dk; 470 register struct disklabel *lp; 471 { 472 int mul; 473 474 /* 475 * Calculate scaling shift for mapping 476 * DEV_BSIZE blocks to drive sectors. 477 */ 478 mul = DEV_BSIZE / lp->d_secsize; 479 dk->dk_bshift = 0; 480 while ((mul >>= 1) > 0) 481 dk->dk_bshift++; 482 } 483 #endif SECSIZE 484 485 /*ARGSUSED*/ 486 vddgo(vm) 487 struct vba_device *vm; 488 { 489 490 } 491 492 vdstrategy(bp) 493 register struct buf *bp; 494 { 495 register struct vba_device *vi; 496 register struct disklabel *lp; 497 register struct dksoftc *dk; 498 register int unit; 499 register daddr_t sn; 500 struct buf *dp; 501 daddr_t sz, maxsz; 502 int part, s; 503 504 unit = vdunit(bp->b_dev); 505 if (unit >= NDK) { 506 bp->b_error = ENXIO; 507 goto bad; 508 } 509 vi = vddinfo[unit]; 510 lp = &dklabel[unit]; 511 if (vi == 0 || vi->ui_alive == 0) { 512 bp->b_error = ENXIO; 513 goto bad; 514 } 515 dk = &dksoftc[unit]; 516 if (dk->dk_state < OPEN) { 517 if (dk->dk_state == CLOSED) { 518 bp->b_error = EIO; 519 goto bad; 520 } 521 goto q; 522 } 523 if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { 524 bp->b_error = EROFS; 525 goto bad; 526 } 527 part = vdpart(bp->b_dev); 528 if ((dk->dk_openpart & (1 << part)) == 0) { 529 bp->b_error = ENODEV; 530 goto bad; 531 } 532 sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 533 maxsz = lp->d_partitions[part].p_size; 534 #ifndef SECSIZE 535 sn = bp->b_blkno << dk->dk_bshift; 536 #else SECSIZE 537 sn = bp->b_blkno; 538 #endif SECSIZE 539 if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && 540 #if LABELSECTOR != 0 541 sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && 542 #endif 543 (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { 544 bp->b_error = EROFS; 545 goto bad; 546 } 547 if (sn < 0 || sn + sz > maxsz) { 548 if (sn == maxsz) { 549 bp->b_resid = bp->b_bcount; 550 goto done; 551 } 552 sz = maxsz - sn; 553 if (sz <= 0) { 554 bp->b_error = EINVAL; 555 goto bad; 556 } 557 bp->b_bcount = sz * lp->d_secsize; 558 } 559 bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 560 #ifdef SECSIZE 561 if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) 562 panic("vdstrat blksize"); 563 #endif SECSIZE 564 q: 565 s = spl7(); 566 dp = &dkutab[vi->ui_unit]; 567 disksort(dp, bp); 568 if (!dp->b_active) { 569 (void) vdustart(vi); 570 if (!vi->ui_mi->um_tab.b_active) 571 vdstart(vi->ui_mi); 572 } 573 splx(s); 574 return; 575 bad: 576 bp->b_flags |= B_ERROR; 577 done: 578 biodone(bp); 579 return; 580 } 581 582 vdustart(vi) 583 register struct vba_device *vi; 584 { 585 register struct buf *bp, *dp; 586 register struct vba_ctlr *vm; 587 register int unit = vi->ui_unit; 588 register struct dksoftc *dk; 589 register struct vdsoftc *vd; 590 struct disklabel *lp; 591 592 dp = &dkutab[unit]; 593 /* 594 * If queue empty, nothing to do. 595 */ 596 if ((bp = dp->b_actf) == NULL) 597 return; 598 /* 599 * If drive is off-cylinder and controller supports seeks, 600 * place drive on seek queue for controller. 601 * Otherwise, place on transfer queue. 602 */ 603 vd = &vdsoftc[vi->ui_ctlr]; 604 dk = &dksoftc[unit]; 605 vm = vi->ui_mi; 606 if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { 607 lp = &dklabel[unit]; 608 bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; 609 if (vm->um_tab.b_seekf == NULL) 610 vm->um_tab.b_seekf = dp; 611 else 612 vm->um_tab.b_seekl->b_forw = dp; 613 vm->um_tab.b_seekl = dp; 614 } else { 615 if (vm->um_tab.b_actf == NULL) 616 vm->um_tab.b_actf = dp; 617 else 618 vm->um_tab.b_actl->b_forw = dp; 619 vm->um_tab.b_actl = dp; 620 } 621 dp->b_forw = NULL; 622 dp->b_active++; 623 } 624 625 /* 626 * Start next transfer on a controller. 627 * There are two queues of drives, the first on-cylinder 628 * and the second off-cylinder from their next transfers. 629 * Perform the first transfer for the first drive on the on-cylinder 630 * queue, if any, otherwise the first transfer for the first drive 631 * on the second queue. Initiate seeks on remaining drives on the 632 * off-cylinder queue, then move them all to the on-cylinder queue. 633 */ 634 vdstart(vm) 635 register struct vba_ctlr *vm; 636 { 637 register struct buf *bp; 638 register struct vba_device *vi; 639 register struct vdsoftc *vd; 640 register struct dksoftc *dk; 641 register struct disklabel *lp; 642 register struct dcb **dcbp; 643 struct buf *dp; 644 int sn, tn; 645 646 loop: 647 /* 648 * Pull a request off the controller queue. 649 */ 650 if ((dp = vm->um_tab.b_actf) == NULL && 651 (dp = vm->um_tab.b_seekf) == NULL) 652 return; 653 if ((bp = dp->b_actf) == NULL) { 654 if (dp == vm->um_tab.b_actf) 655 vm->um_tab.b_actf = dp->b_forw; 656 else 657 vm->um_tab.b_seekf = dp->b_forw; 658 goto loop; 659 } 660 661 /* 662 * Mark controller busy, and determine 663 * destination of this request. 664 */ 665 vm->um_tab.b_active++; 666 vi = vddinfo[vdunit(bp->b_dev)]; 667 dk = &dksoftc[vi->ui_unit]; 668 #ifndef SECSIZE 669 sn = bp->b_blkno << dk->dk_bshift; 670 #else SECSIZE 671 sn = bp->b_blkno; 672 #endif SECSIZE 673 lp = &dklabel[vi->ui_unit]; 674 sn %= lp->d_secpercyl; 675 tn = sn / lp->d_nsectors; 676 sn %= lp->d_nsectors; 677 678 /* 679 * Construct dcb for read/write command. 680 */ 681 vd = &vdsoftc[vm->um_ctlr]; 682 vd->vd_dcb.intflg = DCBINT_DONE; 683 vd->vd_dcb.devselect = dk->dk_dcb.devselect; 684 vd->vd_dcb.operrsta = 0; 685 vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 686 vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; 687 vd->vd_dcb.trail.rwtrail.disk.track = tn; 688 vd->vd_dcb.trail.rwtrail.disk.sector = sn; 689 dk->dk_curcyl = bp->b_cylin; 690 bp->b_track = 0; /* init overloaded field */ 691 vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 692 if (bp->b_flags & B_FORMAT) 693 vd->vd_dcb.opcode = dk->dk_op; 694 else if (vd->vd_flags & VD_SCATGATH && 695 ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) 696 vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; 697 else 698 vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; 699 700 switch (vd->vd_dcb.opcode) { 701 case VDOP_FSECT: 702 vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long); 703 vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount / 704 lp->d_secsize; 705 vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr; 706 vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags; 707 goto setupaddr; 708 709 case VDOP_RDRAW: 710 case VDOP_RD: 711 case VDOP_RHDE: 712 case VDOP_WD: 713 vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; 714 setupaddr: 715 vd->vd_dcb.trail.rwtrail.memadr = 716 vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize); 717 break; 718 719 case VDOP_RAS: 720 case VDOP_GAW: 721 vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf, 722 &vd->vd_dcb.trail.sgtrail); 723 break; 724 } 725 if (vi->ui_dk >= 0) { 726 dk_busy |= 1<<vi->ui_dk; 727 dk_xfer[vi->ui_dk]++; 728 dk_wds[vi->ui_dk] += bp->b_bcount>>6; 729 } 730 731 /* 732 * Look for any seeks to be performed on other drives on this 733 * controller. If overlapped seeks exist, insert seek commands 734 * on the controller's command queue before the transfer. 735 */ 736 dcbp = &vd->vd_mdcb.mdcb_head; 737 738 if (dp == vm->um_tab.b_seekf) 739 dp = dp->b_forw; 740 else 741 dp = vm->um_tab.b_seekf; 742 for (; dp != NULL; dp = dp->b_forw) { 743 if ((bp = dp->b_actf) == NULL) 744 continue; 745 vi = vddinfo[vdunit(bp->b_dev)]; 746 dk = &dksoftc[vi->ui_unit]; 747 dk->dk_curcyl = bp->b_cylin; 748 if (vi->ui_dk >= 0) 749 dk_seek[vi->ui_dk]++; 750 dk->dk_dcb.operrsta = 0; 751 dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; 752 dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; 753 *dcbp = (struct dcb *)dk->dk_dcbphys; 754 dcbp = &dk->dk_dcb.nxtdcb; 755 } 756 *dcbp = (struct dcb *)vd->vd_dcbphys; 757 if (vm->um_tab.b_actf) 758 vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; 759 else 760 vm->um_tab.b_actf = vm->um_tab.b_seekf; 761 if (vm->um_tab.b_seekf) 762 vm->um_tab.b_actl = vm->um_tab.b_seekl; 763 vm->um_tab.b_seekf = 0; 764 765 /* 766 * Initiate operation. 767 */ 768 vd->vd_mdcb.mdcb_status = 0; 769 VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 770 } 771 772 /* 773 * Wait for controller to finish current operation 774 * so that direct controller accesses can be done. 775 */ 776 vdlock(ctlr) 777 { 778 register struct vba_ctlr *vm = vdminfo[ctlr]; 779 register struct vdsoftc *vd = &vdsoftc[ctlr]; 780 int s; 781 782 s = spl7(); 783 while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) { 784 vd->vd_flags |= VD_WAIT; 785 sleep((caddr_t)vd, PRIBIO); 786 } 787 vd->vd_flags |= VD_LOCKED; 788 splx(s); 789 } 790 791 /* 792 * Continue normal operations after pausing for 793 * munging the controller directly. 794 */ 795 vdunlock(ctlr) 796 { 797 register struct vba_ctlr *vm = vdminfo[ctlr]; 798 register struct vdsoftc *vd = &vdsoftc[ctlr]; 799 800 vd->vd_flags &= ~VD_LOCKED; 801 if (vd->vd_flags & VD_WAIT) { 802 vd->vd_flags &= ~VD_WAIT; 803 wakeup((caddr_t)vd); 804 } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 805 vdstart(vm); 806 } 807 808 #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) 809 /* 810 * Handle a disk interrupt. 811 */ 812 vdintr(ctlr) 813 register ctlr; 814 { 815 register struct buf *bp, *dp; 816 register struct vba_ctlr *vm = vdminfo[ctlr]; 817 register struct vba_device *vi; 818 register struct vdsoftc *vd = &vdsoftc[ctlr]; 819 register status; 820 int timedout; 821 struct dksoftc *dk; 822 823 if (!vm->um_tab.b_active) { 824 printf("vd%d: stray interrupt\n", ctlr); 825 return; 826 } 827 /* 828 * Get device and block structures, and a pointer 829 * to the vba_device for the drive. 830 */ 831 dp = vm->um_tab.b_actf; 832 bp = dp->b_actf; 833 vi = vddinfo[vdunit(bp->b_dev)]; 834 dk = &dksoftc[vi->ui_unit]; 835 if (vi->ui_dk >= 0) 836 dk_busy &= ~(1<<vi->ui_dk); 837 timedout = (vd->vd_wticks >= VDMAXTIME); 838 /* 839 * Check for and process errors on 840 * either the drive or the controller. 841 */ 842 uncache(&vd->vd_dcb.operrsta); 843 status = vd->vd_dcb.operrsta; 844 if (bp->b_flags & B_FORMAT) { 845 dk->dk_operrsta = status; 846 uncache(&vd->vd_dcb.err_code); 847 /* ecodecnt gets err_code + err_wcnt from the same longword */ 848 dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code; 849 uncache(&vd->vd_dcb.err_trk); 850 /* erraddr gets error trk/sec/cyl from the same longword */ 851 dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk; 852 } else if (status & VDERR_HARD || timedout) { 853 if (vd->vd_type == VDTYPE_SMDE) 854 uncache(&vd->vd_dcb.err_code); 855 if (status & DCBS_WPT) { 856 /* 857 * Give up on write locked devices immediately. 858 */ 859 printf("dk%d: write locked\n", vi->ui_unit); 860 bp->b_flags |= B_ERROR; 861 } else if (status & VDERR_RETRY || timedout) { 862 if (status & VDERR_CTLR || timedout) { 863 vdharderr(timedout ? 864 "controller timeout" : "controller err", 865 vd, bp, &vd->vd_dcb); 866 printf("; resetting controller..."); 867 vdreset_ctlr(vm); 868 } else if (status & VDERR_DRIVE) { 869 vdharderr("drive err", vd, bp, &vd->vd_dcb); 870 printf("; resetting drive..."); 871 if (!vdreset_drive(vi)) 872 dk->dk_state = CLOSED; 873 } else 874 vdharderr("data err", vd, bp, &vd->vd_dcb); 875 /* 876 * Retry transfer once, unless reset failed. 877 */ 878 if (!vi->ui_alive || dp->b_errcnt++ >= 1) { 879 printf("\n"); 880 goto hard; 881 } 882 883 printf(" retrying\n"); 884 vm->um_tab.b_active = 0; /* force retry */ 885 } else { 886 vdharderr("hard error", vd, bp, &vd->vd_dcb); 887 printf("\n"); 888 hard: 889 bp->b_flags |= B_ERROR; 890 } 891 } else if (status & DCBS_SOFT) 892 vdsofterr(bp, &vd->vd_dcb); 893 if (vd->vd_wticks > 3) { 894 vd->vd_dcb.err_code = vd->vd_wticks; 895 vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb); 896 printf("\n"); 897 } 898 vd->vd_wticks = 0; 899 if (vm->um_tab.b_active) { 900 vm->um_tab.b_active = 0; 901 vm->um_tab.b_actf = dp->b_forw; 902 dp->b_active = 0; 903 dp->b_errcnt = 0; 904 dp->b_actf = bp->av_forw; 905 bp->b_resid = 0; 906 vbadone(bp, &vd->vd_rbuf); 907 biodone(bp); 908 /* 909 * If this unit has more work to do, 910 * then start it up right away. 911 */ 912 if (dp->b_actf) 913 vdustart(vi); 914 else if (dk->dk_openpart == 0) 915 wakeup((caddr_t)dk); 916 } 917 /* 918 * If there are devices ready to 919 * transfer, start the controller. 920 */ 921 if (vd->vd_flags & VD_WAIT) { 922 vd->vd_flags &= ~VD_WAIT; 923 wakeup((caddr_t)vd); 924 } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) 925 vdstart(vm); 926 } 927 928 vdharderr(what, vd, bp, dcb) 929 char *what; 930 struct vdsoftc *vd; 931 register struct buf *bp; 932 register struct dcb *dcb; 933 { 934 int unit = vdunit(bp->b_dev), status = dcb->operrsta; 935 register struct disklabel *lp = &dklabel[unit]; 936 int blkdone; 937 938 if (vd->vd_wticks < VDMAXTIME) 939 status &= ~DONTCARE; 940 blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 941 lp->d_nsectors + dcb->err_sec - 942 lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 943 dksoftc[unit].dk_bshift) - bp->b_blkno; 944 diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp); 945 printf(", status %b", status, VDERRBITS); 946 if (vd->vd_type == VDTYPE_SMDE) 947 printf(" ecode %x", dcb->err_code); 948 } 949 950 vdsofterr(bp, dcb) 951 register struct buf *bp; 952 register struct dcb *dcb; 953 { 954 int unit = vdunit(bp->b_dev); 955 struct disklabel *lp = &dklabel[unit]; 956 int status = dcb->operrsta; 957 int blkdone; 958 959 blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * 960 lp->d_nsectors + dcb->err_sec - 961 lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> 962 dksoftc[unit].dk_bshift) - bp->b_blkno; 963 964 if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { 965 diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp); 966 addlog(", status %b ecode %x\n", status, VDERRBITS, 967 dcb->err_code); 968 } else { 969 diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp); 970 addlog("\n"); 971 } 972 } 973 974 vdioctl(dev, cmd, data, flag) 975 dev_t dev; 976 int cmd; 977 caddr_t data; 978 int flag; 979 { 980 register int unit = vdunit(dev); 981 register struct disklabel *lp = &dklabel[unit]; 982 register struct dksoftc *dk = &dksoftc[unit]; 983 int error = 0, vdformat(); 984 985 switch (cmd) { 986 987 case DIOCGDINFO: 988 *(struct disklabel *)data = *lp; 989 break; 990 991 case DIOCGPART: 992 ((struct partinfo *)data)->disklab = lp; 993 ((struct partinfo *)data)->part = 994 &lp->d_partitions[vdpart(dev)]; 995 break; 996 997 case DIOCSDINFO: 998 if ((flag & FWRITE) == 0) 999 error = EBADF; 1000 else 1001 error = setdisklabel(lp, (struct disklabel *)data, 1002 (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); 1003 if (error == 0 && dk->dk_state == OPENRAW && 1004 vdreset_drive(vddinfo[unit])) 1005 dk->dk_state = OPEN; 1006 break; 1007 1008 case DIOCWLABEL: 1009 if ((flag & FWRITE) == 0) 1010 error = EBADF; 1011 else 1012 dk->dk_wlabel = *(int *)data; 1013 break; 1014 1015 case DIOCWDINFO: 1016 if ((flag & FWRITE) == 0) 1017 error = EBADF; 1018 else if ((error = setdisklabel(lp, (struct disklabel *)data, 1019 (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { 1020 int wlab; 1021 1022 if (error == 0 && dk->dk_state == OPENRAW && 1023 vdreset_drive(vddinfo[unit])) 1024 dk->dk_state = OPEN; 1025 /* simulate opening partition 0 so write succeeds */ 1026 dk->dk_openpart |= (1 << 0); /* XXX */ 1027 wlab = dk->dk_wlabel; 1028 dk->dk_wlabel = 1; 1029 error = writedisklabel(dev, vdstrategy, lp); 1030 dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; 1031 dk->dk_wlabel = wlab; 1032 } 1033 break; 1034 1035 case DIOCWFORMAT: 1036 { 1037 register struct format_op *fop; 1038 struct uio auio; 1039 struct iovec aiov; 1040 1041 if ((flag & FWRITE) == 0) { 1042 error = EBADF; 1043 break; 1044 } 1045 fop = (struct format_op *)data; 1046 aiov.iov_base = fop->df_buf; 1047 aiov.iov_len = fop->df_count; 1048 auio.uio_iov = &aiov; 1049 auio.uio_iovcnt = 1; 1050 auio.uio_resid = fop->df_count; 1051 auio.uio_segflg = UIO_USERSPACE; 1052 auio.uio_offset = fop->df_startblk * lp->d_secsize; 1053 /* This assumes one active format operation per disk... */ 1054 dk->dk_op = fop->dk_op; 1055 dk->dk_althdr = fop->dk_althdr; 1056 dk->dk_fmtflags = fop->dk_fmtflags; 1057 /* 1058 * Don't return errors, as the format op won't get copied 1059 * out if we return nonzero. Callers must check the returned 1060 * registers and count. 1061 */ 1062 error = physio(vdformat, (struct buf *)NULL, dev, 1063 B_WRITE, minphys, &auio); 1064 if (error == EIO) 1065 error = 0; 1066 fop->df_count -= auio.uio_resid; 1067 /* This assumes one active format operation per disk... */ 1068 fop->dk_operrsta = dk->dk_operrsta; 1069 fop->dk_ecodecnt = dk->dk_ecodecnt; 1070 fop->dk_erraddr = dk->dk_erraddr; 1071 break; 1072 } 1073 1074 default: 1075 error = ENOTTY; 1076 break; 1077 } 1078 return (error); 1079 } 1080 1081 vdformat(bp) 1082 struct buf *bp; 1083 { 1084 bp->b_flags |= B_FORMAT; 1085 vdstrategy(bp); 1086 } 1087 1088 /* 1089 * Watch for lost interrupts. 1090 */ 1091 vdwatch() 1092 { 1093 register struct vdsoftc *vd; 1094 register struct vba_ctlr *vm; 1095 register int ctlr; 1096 int s; 1097 1098 timeout(vdwatch, (caddr_t)0, hz); 1099 for (ctlr = 0; ctlr < NVD; ctlr++) { 1100 vm = vdminfo[ctlr]; 1101 if (vm == 0 || vm->um_alive == 0) 1102 continue; 1103 vd = &vdsoftc[ctlr]; 1104 s = spl7(); 1105 if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) { 1106 printf("vd%d: lost interrupt\n", ctlr); 1107 #ifdef maybe 1108 VDABORT((struct vddevice *)vm->um_addr, vd->vd_type); 1109 #endif 1110 vdintr(ctlr); 1111 } 1112 splx(s); 1113 } 1114 } 1115 1116 #define DBSIZE 64 /* controller limit with 1K sectors */ 1117 /* 1118 * Crash dump. 1119 */ 1120 vddump(dev) 1121 dev_t dev; 1122 { 1123 register struct vba_device *vi; 1124 register struct vba_ctlr *vm; 1125 register struct disklabel *lp; 1126 register struct vdsoftc *vd; 1127 struct dksoftc *dk; 1128 int part, unit, num; 1129 u_long start; 1130 1131 start = 0; 1132 unit = vdunit(dev); 1133 if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) 1134 return (ENXIO); 1135 dk = &dksoftc[unit]; 1136 if (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 1137 vdinit(vdminor(unit, 0), 0) != 0) 1138 return (ENXIO); 1139 lp = &dklabel[unit]; 1140 part = vdpart(dev); 1141 if (part >= lp->d_npartitions) 1142 return (ENXIO); 1143 vm = vi->ui_mi; 1144 vdreset_ctlr(vm); 1145 if (dumplo < 0) 1146 return (EINVAL); 1147 /* 1148 * Maxfree is in pages, dumplo is in DEV_BSIZE units. 1149 */ 1150 num = maxfree * (NBPG / lp->d_secsize); 1151 dumplo *= DEV_BSIZE / lp->d_secsize; 1152 if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) 1153 num = lp->d_partitions[vdpart(dev)].p_size - dumplo; 1154 vd = &vdsoftc[vm->um_ctlr]; 1155 vd->vd_dcb.intflg = DCBINT_NONE; 1156 vd->vd_dcb.opcode = VDOP_WD; 1157 vd->vd_dcb.devselect = dk->dk_dcb.devselect; 1158 vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 1159 while (num > 0) { 1160 int nsec, cn, sn, tn; 1161 1162 nsec = MIN(num, DBSIZE); 1163 sn = dumplo + start / lp->d_secsize; 1164 cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / 1165 lp->d_secpercyl; 1166 sn %= lp->d_secpercyl; 1167 tn = sn / lp->d_nsectors; 1168 sn %= lp->d_nsectors; 1169 vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1170 vd->vd_dcb.trail.rwtrail.memadr = start; 1171 vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; 1172 vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; 1173 vd->vd_dcb.trail.rwtrail.disk.track = tn; 1174 vd->vd_dcb.trail.rwtrail.disk.sector = sn; 1175 vd->vd_dcb.operrsta = 0; 1176 VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 1177 if (!vdpoll(vm, 5)) { 1178 printf(" during dump\n"); 1179 return (EIO); 1180 } 1181 if (vd->vd_dcb.operrsta & VDERR_HARD) { 1182 printf("dk%d: hard error, status=%b\n", unit, 1183 vd->vd_dcb.operrsta, VDERRBITS); 1184 return (EIO); 1185 } 1186 start += nsec * lp->d_secsize; 1187 num -= nsec; 1188 } 1189 return (0); 1190 } 1191 1192 vdsize(dev) 1193 dev_t dev; 1194 { 1195 register int unit = vdunit(dev); 1196 register struct dksoftc *dk; 1197 struct vba_device *vi; 1198 struct disklabel *lp; 1199 1200 if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || 1201 (dk = &dksoftc[unit])->dk_state != OPEN) 1202 return (-1); 1203 lp = &dklabel[unit]; 1204 #ifdef SECSIZE 1205 return ((int)lp->d_partitions[vdpart(dev)].p_size); 1206 #else SECSIZE 1207 return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); 1208 #endif SECSIZE 1209 } 1210 1211 /* 1212 * Initialize controller. 1213 */ 1214 vdinit_ctlr(vm, vd) 1215 struct vba_ctlr *vm; 1216 struct vdsoftc *vd; 1217 { 1218 register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 1219 1220 if (vd->vd_type == VDTYPE_SMDE) { 1221 vdaddr->vdcsr = 0; 1222 vdaddr->vdtcf_mdcb = AM_ENPDA; 1223 vdaddr->vdtcf_dcb = AM_ENPDA; 1224 vdaddr->vdtcf_trail = AM_ENPDA; 1225 vdaddr->vdtcf_data = AM_ENPDA; 1226 vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS | CCF_RFE | 1227 XMD_32BIT | BSZ_16WRD | 1228 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 1229 } 1230 if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) { 1231 printf("vd%d: %s cmd failed\n", vm->um_ctlr, 1232 vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); 1233 return (0); 1234 } 1235 vd->vd_secsize = vdaddr->vdsecsize << 1; 1236 return (1); 1237 } 1238 1239 /* 1240 * Perform a controller reset. 1241 */ 1242 vdreset_ctlr(vm) 1243 register struct vba_ctlr *vm; 1244 { 1245 register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 1246 register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 1247 register int unit; 1248 struct vba_device *vi; 1249 1250 VDRESET(vdaddr, vd->vd_type); 1251 if (vdinit_ctlr(vm, vd) == 0) 1252 return; 1253 for (unit = 0; unit < NDK; unit++) 1254 if (vi = vddinfo[unit] && vi->ui_mi == vm && vi->ui_alive) 1255 (void) vdreset_drive(vi); 1256 } 1257 1258 vdreset_drive(vi) 1259 register struct vba_device *vi; 1260 { 1261 register struct disklabel *lp = &dklabel[vi->ui_unit]; 1262 struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; 1263 struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 1264 register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; 1265 register struct dksoftc *dk = &dksoftc[vi->ui_unit]; 1266 int config_status, config_ecode, saw_drive = 0; 1267 1268 #ifdef notdef 1269 /* 1270 * check for ESDI distribution panel already configured, 1271 * e.g. on boot drive, or if PROBE on controller actually 1272 * worked. Status will be zero if drive hasn't 1273 * been probed yet. 1274 */ 1275 #if STA_ESDI != 0 1276 if ((vdaddr->vdstatus[vi->ui_slave] & STA_TYPE) == STA_ESDI) 1277 lp->d_devflags |= VD_ESDI; 1278 #endif 1279 #endif 1280 top: 1281 vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ 1282 vd->vd_dcb.intflg = DCBINT_NONE; 1283 vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1284 vd->vd_dcb.operrsta = 0; 1285 vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; 1286 vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; 1287 vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; 1288 if (vd->vd_type == VDTYPE_SMDE) { 1289 vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); 1290 vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; 1291 vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; 1292 vd->vd_dcb.trail.rstrail.recovery = 1293 (lp->d_flags & D_REMOVABLE) ? VDRF_NORMAL : 1294 (VDRF_NORMAL &~ (VDRF_OSP|VDRF_OSM)); 1295 } else 1296 vd->vd_dcb.trailcnt = 2; /* XXX */ 1297 vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1298 vd->vd_mdcb.mdcb_status = 0; 1299 VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); 1300 if (!vdpoll(vm, 5)) { 1301 printf(" during config\n"); 1302 return (0); 1303 } 1304 config_status = vd->vd_dcb.operrsta; 1305 config_ecode = (u_char)vd->vd_dcb.err_code; 1306 if (config_status & VDERR_HARD) { 1307 if (vd->vd_type == VDTYPE_SMDE) { 1308 /* 1309 * If drive status was updated successfully, 1310 * STA_US (unit selected) should be set 1311 * if the drive is attached and powered up. 1312 * (But only if we've guessed right on SMD 1313 * vs. ESDI; if that flag is wrong, we won't 1314 * see the drive.) If we don't see STA_US 1315 * with either SMD or ESDI set for the unit, 1316 * we assume that the drive doesn't exist, 1317 * and don't wait for it to spin up. 1318 */ 1319 (void) vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave); 1320 uncache(&vdaddr->vdstatus[vi->ui_slave]); 1321 if (vdaddr->vdstatus[vi->ui_slave] & STA_US) 1322 saw_drive = 1; 1323 else if (lp->d_devflags == 0) { 1324 lp->d_devflags = VD_ESDI; 1325 goto top; 1326 } 1327 } else 1328 saw_drive = 1; 1329 if ((config_status & (DCBS_OCYL|DCBS_NRDY)) == 0) 1330 printf("dk%d: config error %b ecode %x\n", vi->ui_unit, 1331 config_status, VDERRBITS, config_ecode); 1332 else if ((vd->vd_flags & VD_STARTED) == 0 && saw_drive) { 1333 int started; 1334 1335 printf(" starting drives, wait ... "); 1336 vd->vd_flags |= VD_STARTED; 1337 started = (vdcmd(vm, VDOP_START, 10) == 1); 1338 DELAY(62000000); 1339 printf("done\n"); 1340 lp->d_devflags = 0; 1341 if (started) 1342 goto top; 1343 } 1344 return (0); 1345 } 1346 dk->dk_dcb.devselect |= lp->d_devflags; 1347 return (1); 1348 } 1349 1350 /* 1351 * Perform a command w/o trailer. 1352 */ 1353 vdcmd(vm, cmd, t, slave) 1354 register struct vba_ctlr *vm; 1355 { 1356 register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 1357 1358 vd->vd_dcb.opcode = cmd; /* command */ 1359 vd->vd_dcb.intflg = DCBINT_NONE; 1360 vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1361 vd->vd_dcb.operrsta = 0; 1362 vd->vd_dcb.devselect = slave; 1363 vd->vd_dcb.trailcnt = 0; 1364 vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1365 vd->vd_mdcb.mdcb_status = 0; 1366 VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 1367 if (!vdpoll(vm, t)) { 1368 printf(" during init\n"); 1369 return (0); 1370 } 1371 return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); 1372 } 1373 1374 /* 1375 * Poll controller until operation 1376 * completes or timeout expires. 1377 */ 1378 vdpoll(vm, t) 1379 register struct vba_ctlr *vm; 1380 register int t; 1381 { 1382 register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; 1383 register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; 1384 1385 t *= 1000; 1386 for (;;) { 1387 uncache(&vd->vd_dcb.operrsta); 1388 if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) 1389 break; 1390 if (--t <= 0) { 1391 printf("vd%d: controller timeout", vm->um_ctlr); 1392 VDABORT(vdaddr, vd->vd_type); 1393 return (0); 1394 } 1395 DELAY(1000); 1396 } 1397 if (vd->vd_type == VDTYPE_SMDE) { 1398 do { 1399 DELAY(50); 1400 uncache(&vdaddr->vdcsr); 1401 } while (vdaddr->vdcsr & CS_GO); 1402 DELAY(300); 1403 uncache(&vd->vd_dcb.err_code); 1404 } 1405 DELAY(200); 1406 uncache(&vd->vd_dcb.operrsta); 1407 return (1); 1408 } 1409 1410 #ifdef COMPAT_42 1411 struct vdst { 1412 int nsec; /* sectors/track */ 1413 int ntrack; /* tracks/cylinder */ 1414 int ncyl; /* cylinders */ 1415 int secsize; /* sector size */ 1416 char *name; /* type name */ 1417 struct { 1418 int off; /* partition offset in sectors */ 1419 int size; /* partition size in sectors */ 1420 } parts[8]; 1421 } vdst[] = { 1422 { 66, 23, 850, 512, "NEC 800", 1423 {0, 1290300}, /* a cyl 0 - 849 */ 1424 }, 1425 { 64, 20, 842, 512, "2361a", 1426 {0, 61440}, /* a cyl 0 - 47 */ 1427 {61440, 67840}, /* b cyl 48 - 100 */ 1428 {129280, 942080}, /* c cyl 101 - 836 */ 1429 {0, 1071360}, /* d cyl 0 - 836 */ 1430 {449280, 311040}, /* e cyl 351 - 593 */ 1431 {760320, 311040}, /* f cyl 594 - 836 */ 1432 {449280, 622080}, /* g cyl 351 - 836 */ 1433 {129280, 320000} /* h cyl 101 - 350 */ 1434 }, 1435 { 48, 24, 711, 512, "xsd", 1436 {0, 61056}, /* a cyl 0 - 52 */ 1437 {61056, 61056}, /* b cyl 53 - 105 */ 1438 {122112, 691200}, /* c cyl 106 - 705 */ 1439 {237312, 576000}, /* d cyl 206 - 705 */ 1440 {352512, 460800}, /* e cyl 306 - 705 */ 1441 {467712, 345600}, /* f cyl 406 - 705 */ 1442 {582912, 230400}, /* g cyl 506 - 705 */ 1443 {698112, 115200} /* h cyl 606 - 705 */ 1444 }, 1445 { 44, 20, 842, 512, "eagle", 1446 {0, 52800}, /* egl0a cyl 0 - 59 */ 1447 {52800, 66000}, /* egl0b cyl 60 - 134 */ 1448 {118800, 617760}, /* egl0c cyl 135 - 836 */ 1449 {736560, 4400}, /* egl0d cyl 837 - 841 */ 1450 {0, 736560}, /* egl0e cyl 0 - 836 */ 1451 {0, 740960}, /* egl0f cyl 0 - 841 */ 1452 {118800, 310640}, /* egl0g cyl 135 - 487 */ 1453 {429440, 307120} /* egl0h cyl 488 - 836 */ 1454 }, 1455 { 64, 10, 823, 512, "fuj", 1456 {0, 38400}, /* fuj0a cyl 0 - 59 */ 1457 {38400, 48000}, /* fuj0b cyl 60 - 134 */ 1458 {86400, 437120}, /* fuj0c cyl 135 - 817 */ 1459 {159360, 364160}, /* fuj0d cyl 249 - 817 */ 1460 {232320, 291200}, /* fuj0e cyl 363 - 817 */ 1461 {305280, 218240}, /* fuj0f cyl 477 - 817 */ 1462 {378240, 145280}, /* fuj0g cyl 591 - 817 */ 1463 {451200, 72320} /* fug0h cyl 705 - 817 */ 1464 }, 1465 { 32, 24, 711, 512, "xfd", 1466 { 0, 40704 }, /* a cyl 0 - 52 */ 1467 { 40704, 40704 }, /* b cyl 53 - 105 */ 1468 { 81408, 460800 }, /* c cyl 106 - 705 */ 1469 { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ 1470 { 0, 542208 }, /* e cyl 0 - 705 */ 1471 { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ 1472 { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ 1473 { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ 1474 }, 1475 { 32, 19, 823, 512, "smd", 1476 {0, 40128}, /* a cyl 0-65 */ 1477 {40128, 27360}, /* b cyl 66-110 */ 1478 {67488, 429856}, /* c cyl 111-817 */ 1479 {139232, 358112}, /* d cyl 229 - 817 */ 1480 {210976, 286368}, /* e cyl 347 - 817 */ 1481 {282720, 214624}, /* f cyl 465 - 817 */ 1482 {354464, 142880}, /* g cyl 583 - 817 */ 1483 {426208, 71136} /* h cyl 701 - 817 */ 1484 }, 1485 { 18, 15, 1224, 1024, "mxd", 1486 {0, 21600}, /* a cyl 0-79 */ 1487 {21600, 22410}, /* b cyl 80-162 */ 1488 {44010, 285120}, /* c cyl 163-1217 */ 1489 #ifdef notyet 1490 {x, 237600}, /* d cyl y - 1217 */ 1491 {x, 190080}, /* e cyl y - 1217 */ 1492 {x, 142560}, /* f cyl y - 1217 */ 1493 {x, 95040}, /* g cyl y - 1217 */ 1494 {x, 47520} /* h cyl 701 - 817 */ 1495 #endif 1496 }, 1497 { 32, 10, 823, 512, "fsd", 1498 {0, 19200}, /* a cyl 0 - 59 */ 1499 {19200, 24000}, /* b cyl 60 - 134 */ 1500 {43200, 218560}, /* c cyl 135 - 817 */ 1501 } 1502 }; 1503 #define NVDST (sizeof (vdst) / sizeof (vdst[0])) 1504 1505 /* 1506 * Construct a label for an unlabeled pack. We 1507 * deduce the drive type by reading from the last 1508 * track on successively smaller drives until we 1509 * don't get an error. 1510 */ 1511 vdmaptype(vi, lp) 1512 register struct vba_device *vi; 1513 register struct disklabel *lp; 1514 { 1515 register struct vdsoftc *vd; 1516 register struct vdst *p; 1517 struct vba_ctlr *vm = vi->ui_mi; 1518 int i; 1519 1520 vd = &vdsoftc[vi->ui_ctlr]; 1521 for (p = vdst; p < &vdst[NVDST]; p++) { 1522 if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) 1523 continue; 1524 lp->d_nsectors = p->nsec; 1525 lp->d_ntracks = p->ntrack; 1526 lp->d_ncylinders = p->ncyl; 1527 lp->d_secsize = p->secsize; 1528 DELAY(100000); 1529 if (!vdreset_drive(vi)) 1530 return (0); 1531 DELAY(100000); 1532 vd->vd_dcb.opcode = VDOP_RD; 1533 vd->vd_dcb.intflg = DCBINT_NONE; 1534 vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ 1535 vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; 1536 vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); 1537 vd->vd_dcb.trail.rwtrail.memadr = 1538 vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); 1539 vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); 1540 vd->vd_dcb.operrsta = 0; 1541 vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; 1542 vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; 1543 vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; 1544 vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; 1545 vd->vd_mdcb.mdcb_status = 0; 1546 VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); 1547 if (!vdpoll(vm, 60)) 1548 printf(" during probe\n"); 1549 if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) 1550 break; 1551 } 1552 if (p >= &vdst[NVDST]) 1553 return (0); 1554 1555 for (i = 0; i < 8; i++) { 1556 lp->d_partitions[i].p_offset = p->parts[i].off; 1557 lp->d_partitions[i].p_size = p->parts[i].size; 1558 } 1559 lp->d_npartitions = 8; 1560 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1561 bcopy(p->name, lp->d_typename, 4); 1562 return (1); 1563 } 1564 #endif COMPAT_42 1565 #endif 1566