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