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