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