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