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