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