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