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