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