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