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