1 /* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Harris Corp. 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)hd.c 7.8 (Berkeley) 08/23/89 21 */ 22 23 #include "hd.h" 24 25 #if NHD > 0 26 #include "param.h" 27 #include "buf.h" 28 #include "conf.h" 29 #include "dir.h" 30 #include "dkstat.h" 31 #include "disklabel.h" 32 #include "file.h" 33 #include "systm.h" 34 #include "vmmac.h" 35 #include "time.h" 36 #include "proc.h" 37 #include "uio.h" 38 #include "syslog.h" 39 #include "kernel.h" 40 #include "ioctl.h" 41 #include "stat.h" 42 #include "errno.h" 43 44 #include "../tahoe/cpu.h" 45 #include "../tahoe/mtpr.h" 46 47 #include "../tahoevba/vbavar.h" 48 #include "../tahoevba/hdreg.h" 49 50 #define b_cylin b_resid 51 52 #define hdunit(dev) (minor(dev)>>3) 53 #define hdpart(dev) (minor(dev)&0x07) 54 #define hdminor(unit, part) (((unit)<<3)|(part)) 55 56 struct vba_ctlr *hdcminfo[NHDC]; 57 struct vba_device *hddinfo[NHD]; 58 int hdcprobe(), hdslave(), hdattach(), hddgo(), hdstrategy(); 59 long hdstd[] = { 0 }; 60 struct vba_driver hdcdriver = 61 { hdcprobe, hdslave, hdattach, hddgo, hdstd, "hd", hddinfo, "hdc", hdcminfo }; 62 63 /* 64 * Per-controller state. 65 */ 66 struct hdcsoftc { 67 u_short hdc_flags; 68 #define HDC_INIT 0x01 /* controller initialized */ 69 #define HDC_STARTED 0x02 /* start command issued */ 70 #define HDC_LOCKED 0x04 /* locked for direct controller access */ 71 #define HDC_WAIT 0x08 /* someone needs direct controller access */ 72 u_short hdc_wticks; /* timeout */ 73 struct master_mcb *hdc_mcbp; /* address of controller mcb */ 74 struct registers *hdc_reg; /* base address of i/o regs */ 75 struct vb_buf hdc_rbuf; /* vba resources */ 76 struct master_mcb hdc_mcb; /* controller mcb */ 77 } hdcsoftc[NHDC]; 78 79 #define HDCMAXTIME 20 /* max time for operation, sec. */ 80 #define HDCINTERRUPT 0xf0 /* interrupt vector */ 81 82 /* 83 * Per-drive state; probably everything should be "hd_", not "dk_", 84 * but it's not worth it, and dk is a better mnemonic for disk anyway. 85 */ 86 struct dksoftc { 87 #ifdef COMPAT_42 88 u_short dk_def_cyl; /* definition track cylinder address */ 89 #endif 90 int dk_state; /* open fsm */ 91 u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ 92 int dk_wlabel; /* if label sector is writeable */ 93 u_long dk_copenpart; /* character units open on this drive */ 94 u_long dk_bopenpart; /* block units open on this drive */ 95 u_long dk_openpart; /* all units open on this drive */ 96 int dk_unit; /* unit# */ 97 int dk_ctlr; /* controller# */ 98 int dk_format; /* if format program is using disk */ 99 struct buf dk_utab; /* i/o queue header */ 100 struct disklabel dk_label; /* disklabel for this disk */ 101 struct mcb dk_mcb; /* disk mcb */ 102 } dksoftc[NHD]; 103 104 /* 105 * Drive states. Used during steps of open/initialization. 106 * States < OPEN (> 0) are transient, during an open operation. 107 * OPENRAW is used for unlabeled disks, to allow format operations. 108 */ 109 #define CLOSED 0 /* disk is closed */ 110 #define WANTOPEN 1 /* open requested, not started */ 111 #define WANTOPENRAW 2 /* open requested, no label */ 112 #define RDLABEL 3 /* reading pack label */ 113 #define OPEN 4 /* intialized and ready */ 114 #define OPENRAW 5 /* open, no label */ 115 116 int hdcwstart, hdcwatch(); 117 118 /* see if the controller is really there, if so, init it. */ 119 /* ARGSUSED */ 120 hdcprobe(reg, vm) 121 caddr_t reg; 122 /* register */ struct vba_ctlr *vm; 123 { 124 register int br, cvec; /* must be r12, r11 */ 125 register struct hdcsoftc *hdc; 126 static struct module_id id; 127 struct pte *dummypte; 128 caddr_t putl; 129 130 /* initialize the hdc controller structure. */ 131 hdc = &hdcsoftc[vm->um_ctlr]; 132 if (!vbmemalloc(1, reg, &dummypte, &putl)) { 133 printf("hdc%d: vbmemalloc failed.\n", vm->um_ctlr); 134 return(0); 135 } 136 hdc->hdc_reg = (struct registers *)putl; 137 138 /* 139 * try and ping the MID register; side effect of wbadaddr is to read 140 * the module id; the controller is bad if it's not an hdc, the hdc's 141 * writeable control store is not loaded, or the hdc failed the 142 * functional integrity test; 143 */ 144 if (wbadaddr(&hdc->hdc_reg->module_id, 4, 145 vtoph((struct process *)NULL, &id))) 146 return(0); 147 DELAY(10000); 148 mtpr(PADC, 0); 149 if (id.module_id != (u_char)HDC_MID) { 150 printf("hdc%d: bad module id; id = %x.\n", 151 vm->um_ctlr, id.module_id); 152 return(0); 153 } 154 if (id.code_rev == (u_char)0xff) { 155 printf("hdc%d: micro-code not loaded.\n", vm->um_ctlr); 156 return(0); 157 } 158 if (id.fit != (u_char)0xff) { 159 printf("hdc%d: FIT test failed.\n", vm->um_ctlr); 160 return(0); 161 } 162 163 /* reset that pup; flag as inited */ 164 hdc->hdc_reg->soft_reset = 0; 165 DELAY(1000000); 166 hdc->hdc_flags |= HDC_INIT; 167 168 /* allocate page tables and i/o buffer. */ 169 if (!vbainit(&hdc->hdc_rbuf, MAXPHYS, VB_32BIT|VB_SCATTER)) { 170 printf("hdc%d: vbainit failed\n", vm->um_ctlr); 171 return (0); 172 } 173 174 /* set pointer to master control block */ 175 hdc->hdc_mcbp = 176 (struct master_mcb *)vtoph((struct proc *)NULL, &hdc->hdc_mcb); 177 178 br = 0x17, cvec = HDCINTERRUPT + vm->um_ctlr; /* XXX */ 179 return(sizeof(struct registers)); 180 } 181 182 /* ARGSUSED */ 183 hdslave(vi, vdaddr) 184 struct vba_device *vi; 185 struct vddevice *vdaddr; 186 { 187 register struct mcb *mcb; 188 register struct disklabel *lp; 189 register struct dksoftc *dk; 190 static struct status status; 191 192 dk = &dksoftc[vi->ui_unit]; 193 dk->dk_unit = vi->ui_unit; 194 dk->dk_ctlr = vi->ui_ctlr; 195 196 mcb = &dk->dk_mcb; 197 mcb->command = HCMD_STATUS; 198 mcb->chain[0].wcount = sizeof(struct status) / sizeof(long); 199 mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &status); 200 if (hdimcb(dk)) { 201 printf(" (no status)\n"); 202 return(0); 203 } 204 205 /* 206 * Report the drive down if anything in the drive status looks bad. 207 * If the drive is offline and it is not on cylinder, then the drive 208 * is not there. If there is a fault condition, the hdc will try to 209 * clear it when we read the disklabel information. 210 */ 211 if (!(status.drs&DRS_ONLINE)) { 212 if (status.drs&DRS_ON_CYLINDER) 213 printf(" (not online)\n"); 214 return(0); 215 } 216 if (status.drs&DRS_FAULT) 217 printf(" (clearing fault)"); 218 219 lp = &dk->dk_label; 220 #ifdef RAW_SIZE 221 lp->d_secsize = status.bytes_per_sec; 222 #else 223 lp->d_secsize = 512; 224 #endif 225 lp->d_nsectors = status.max_sector + 1; 226 lp->d_ntracks = status.max_head + 1; 227 lp->d_ncylinders = status.max_cyl + 1; 228 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 229 lp->d_npartitions = 1; 230 lp->d_partitions[0].p_offset = 0; 231 lp->d_partitions[0].p_size = LABELSECTOR + 1; 232 lp->d_rpm = status.rpm; 233 lp->d_typename[0] = 'h'; 234 lp->d_typename[1] = 'd'; 235 lp->d_typename[2] = '\0'; 236 #ifdef COMPAT_42 237 dk->dk_def_cyl = status.def_cyl; 238 #endif 239 return(1); 240 } 241 242 hdattach(vi) 243 register struct vba_device *vi; 244 { 245 register struct dksoftc *dk; 246 register struct disklabel *lp; 247 register int unit; 248 249 unit = vi->ui_unit; 250 if (hdinit(hdminor(unit, 0), 0)) { 251 printf(": unknown drive type"); 252 return; 253 } 254 dk = &dksoftc[unit]; 255 lp = &dk->dk_label; 256 hd_setsecsize(dk, lp); 257 if (dk->dk_state == OPEN) 258 printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", 259 lp->d_typename, lp->d_secsize, lp->d_ntracks, 260 lp->d_ncylinders, lp->d_nsectors); 261 262 /* 263 * (60 / rpm) / (sectors per track * (bytes per sector / 2)) 264 */ 265 if (vi->ui_dk >= 0) 266 dk_wpms[vi->ui_dk] = 267 (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120; 268 #ifdef notyet 269 addswap(makedev(HDMAJOR, hdminor(unit, 0)), lp); 270 #endif 271 } 272 273 hdopen(dev, flags, fmt) 274 dev_t dev; 275 int flags, fmt; 276 { 277 register struct disklabel *lp; 278 register struct dksoftc *dk; 279 register struct partition *pp; 280 register int unit; 281 struct vba_device *vi; 282 int s, error, part = hdpart(dev), mask = 1 << part; 283 daddr_t start, end; 284 285 unit = hdunit(dev); 286 if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0) 287 return(ENXIO); 288 dk = &dksoftc[unit]; 289 lp = &dk->dk_label; 290 s = spl7(); 291 while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && 292 dk->dk_state != CLOSED) 293 sleep((caddr_t)dk, PZERO+1); 294 splx(s); 295 if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) 296 if (error = hdinit(dev, flags)) 297 return(error); 298 299 if (hdcwstart == 0) { 300 timeout(hdcwatch, (caddr_t)0, hz); 301 hdcwstart++; 302 } 303 /* 304 * Warn if a partion is opened that overlaps another partition 305 * which is open unless one is the "raw" partition (whole disk). 306 */ 307 #define RAWPART 8 /* 'x' partition */ /* XXX */ 308 if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { 309 pp = &lp->d_partitions[part]; 310 start = pp->p_offset; 311 end = pp->p_offset + pp->p_size; 312 for (pp = lp->d_partitions; 313 pp < &lp->d_partitions[lp->d_npartitions]; pp++) { 314 if (pp->p_offset + pp->p_size <= start || 315 pp->p_offset >= end) 316 continue; 317 if (pp - lp->d_partitions == RAWPART) 318 continue; 319 if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) 320 log(LOG_WARNING, 321 "hd%d%c: overlaps open partition (%c)\n", 322 unit, part + 'a', 323 pp - lp->d_partitions + 'a'); 324 } 325 } 326 if (part >= lp->d_npartitions) 327 return(ENXIO); 328 dk->dk_openpart |= mask; 329 switch (fmt) { 330 case S_IFCHR: 331 dk->dk_copenpart |= mask; 332 break; 333 case S_IFBLK: 334 dk->dk_bopenpart |= mask; 335 break; 336 } 337 return(0); 338 } 339 340 /* ARGSUSED */ 341 hdclose(dev, flags, fmt) 342 dev_t dev; 343 int flags, fmt; 344 { 345 register struct dksoftc *dk; 346 int mask; 347 348 dk = &dksoftc[hdunit(dev)]; 349 mask = 1 << hdpart(dev); 350 switch (fmt) { 351 case S_IFCHR: 352 dk->dk_copenpart &= ~mask; 353 break; 354 case S_IFBLK: 355 dk->dk_bopenpart &= ~mask; 356 break; 357 } 358 if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) 359 dk->dk_openpart &= ~mask; 360 /* 361 * Should wait for i/o to complete on this partition 362 * even if others are open, but wait for work on blkflush(). 363 */ 364 if (dk->dk_openpart == 0) { 365 int s = spl7(); 366 while (dk->dk_utab.b_actf) 367 sleep((caddr_t)dk, PZERO-1); 368 splx(s); 369 dk->dk_state = CLOSED; 370 dk->dk_wlabel = 0; 371 } 372 return(0); 373 } 374 375 hdinit(dev, flags) 376 dev_t dev; 377 int flags; 378 { 379 register struct dksoftc *dk; 380 register struct disklabel *lp; 381 struct vba_device *vi; 382 int error, unit; 383 char *msg, *readdisklabel(); 384 extern int cold; 385 386 vi = hddinfo[unit = hdunit(dev)]; 387 dk = &dksoftc[unit]; 388 dk->dk_unit = vi->ui_slave; 389 dk->dk_ctlr = vi->ui_ctlr; 390 391 if (flags & O_NDELAY) { 392 dk->dk_state = OPENRAW; 393 return(0); 394 } 395 396 error = 0; 397 lp = &dk->dk_label; 398 dk->dk_state = RDLABEL; 399 if (msg = readdisklabel(dev, hdstrategy, lp)) { 400 if (cold) { 401 printf(": %s\n", msg); 402 dk->dk_state = CLOSED; 403 } else { 404 log(LOG_ERR, "hd%d: %s\n", unit, msg); 405 dk->dk_state = OPENRAW; 406 } 407 #ifdef COMPAT_42 408 hdclock(vi->ui_ctlr); 409 if (!(error = hdreadgeometry(dk))) 410 dk->dk_state = OPEN; 411 hdcunlock(vi->ui_ctlr); 412 #endif 413 } else 414 dk->dk_state = OPEN; 415 wakeup((caddr_t)dk); 416 return(error); 417 } 418 419 hd_setsecsize(dk, lp) 420 register struct dksoftc *dk; 421 struct disklabel *lp; 422 { 423 register int mul; 424 425 /* 426 * Calculate scaling shift for mapping 427 * DEV_BSIZE blocks to drive sectors. 428 */ 429 mul = DEV_BSIZE / lp->d_secsize; 430 dk->dk_bshift = 0; 431 while ((mul >>= 1) > 0) 432 dk->dk_bshift++; 433 } 434 435 /* ARGSUSED */ 436 hddgo(vm) 437 struct vba_device *vm; 438 {} 439 440 extern int name_ext; 441 hdstrategy(bp) 442 register struct buf *bp; 443 { 444 register struct vba_device *vi; 445 register struct disklabel *lp; 446 register struct dksoftc *dk; 447 struct buf *dp; 448 register int unit; 449 daddr_t sn, sz, maxsz; 450 int part, s; 451 452 vi = hddinfo[unit = hdunit(bp->b_dev)]; 453 if (unit >= NHD || vi == 0 || vi->ui_alive == 0) { 454 bp->b_error = ENXIO; 455 goto bad; 456 } 457 dk = &dksoftc[unit]; 458 if (dk->dk_state < OPEN) 459 goto q; 460 if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { 461 bp->b_error = EROFS; 462 goto bad; 463 } 464 part = hdpart(bp->b_dev); 465 if ((dk->dk_openpart & (1 << part)) == 0) { 466 bp->b_error = ENODEV; 467 goto bad; 468 } 469 lp = &dk->dk_label; 470 sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; 471 maxsz = lp->d_partitions[part].p_size; 472 sn = bp->b_blkno << dk->dk_bshift; 473 if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && 474 #if LABELSECTOR != 0 475 sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && 476 #endif 477 (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { 478 bp->b_error = EROFS; 479 goto bad; 480 } 481 if (sn < 0 || sn + sz > maxsz) { 482 if (sn == maxsz) { 483 bp->b_resid = bp->b_bcount; 484 goto done; 485 } 486 sz = maxsz - sn; 487 if (sz <= 0) { 488 bp->b_error = EINVAL; 489 goto bad; 490 } 491 bp->b_bcount = sz * lp->d_secsize; 492 } 493 bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; 494 495 q: s = spl7(); 496 dp = &dk->dk_utab; 497 disksort(dp, bp); 498 if (!dp->b_active) { 499 (void)hdustart(vi); 500 if (!vi->ui_mi->um_tab.b_active) 501 hdcstart(vi->ui_mi); 502 } 503 splx(s); 504 return; 505 bad: 506 bp->b_flags |= B_ERROR; 507 done: 508 biodone(bp); 509 } 510 511 hdustart(vi) 512 register struct vba_device *vi; 513 { 514 register struct buf *bp, *dp; 515 register struct vba_ctlr *vm; 516 register struct dksoftc *dk; 517 518 dk = &dksoftc[vi->ui_unit]; 519 dp = &dk->dk_utab; 520 521 /* if queue empty, nothing to do. impossible? */ 522 if (dp->b_actf == NULL) 523 return; 524 525 /* place on controller transfer queue */ 526 vm = vi->ui_mi; 527 if (vm->um_tab.b_actf == NULL) 528 vm->um_tab.b_actf = dp; 529 else 530 vm->um_tab.b_actl->b_forw = dp; 531 vm->um_tab.b_actl = dp; 532 dp->b_forw = NULL; 533 dp->b_active++; 534 } 535 536 hdcstart(vm) 537 register struct vba_ctlr *vm; 538 { 539 register struct buf *bp; 540 register struct dksoftc *dk; 541 register struct disklabel *lp; 542 register struct master_mcb *master; 543 register struct mcb *mcb; 544 struct vba_device *vi; 545 struct hdcsoftc *hdc; 546 struct buf *dp; 547 int sn; 548 549 /* pull a request off the controller queue */ 550 for (;;) { 551 if ((dp = vm->um_tab.b_actf) == NULL) 552 return; 553 if (bp = dp->b_actf) 554 break; 555 vm->um_tab.b_actf = dp->b_forw; 556 } 557 558 /* mark controller active */ 559 vm->um_tab.b_active++; 560 561 vi = hddinfo[hdunit(bp->b_dev)]; 562 dk = &dksoftc[vi->ui_unit]; 563 lp = &dk->dk_label; 564 sn = bp->b_blkno << dk->dk_bshift; 565 566 /* fill in mcb */ 567 mcb = &dk->dk_mcb; 568 mcb->forw_phaddr = 0; 569 /* mcb->priority = 0; */ 570 mcb->interrupt = 1; 571 mcb->command = (bp->b_flags & B_READ) ? HCMD_READ:HCMD_WRITE; 572 mcb->cyl = bp->b_cylin; 573 /* assumes partition starts on cylinder boundary */ 574 mcb->head = (sn / lp->d_nsectors) % lp->d_ntracks; 575 mcb->sector = sn % lp->d_nsectors; 576 mcb->drive = vi->ui_slave; 577 /* mcb->context = 0; /* what do we want on interrupt? */ 578 579 hdc = &hdcsoftc[vm->um_ctlr]; 580 if (!hd_sgsetup(bp, &hdc->hdc_rbuf, mcb->chain)) { 581 mcb->chain[0].wcount = (bp->b_bcount+3) >> 2; 582 mcb->chain[0].memadr = 583 vbasetup(bp, &hdc->hdc_rbuf, (int)lp->d_secsize); 584 } 585 586 if (vi->ui_dk >= 0) { 587 dk_busy |= 1<<vi->ui_dk; 588 dk_xfer[vi->ui_dk]++; 589 dk_wds[vi->ui_dk] += bp->b_bcount>>6; 590 } 591 592 master = &hdc->hdc_mcb; 593 master->mcw = MCL_QUEUED; 594 master->interrupt = HDCINTERRUPT + vm->um_ctlr; 595 master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb); 596 hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp; 597 } 598 599 /* 600 * Wait for controller to finish current operation 601 * so that direct controller accesses can be done. 602 */ 603 hdclock(ctlr) 604 int ctlr; 605 { 606 register struct vba_ctlr *vm = hdcminfo[ctlr]; 607 register struct hdcsoftc *hdc; 608 int s; 609 610 hdc = &hdcsoftc[ctlr]; 611 s = spl7(); 612 while (vm->um_tab.b_active || hdc->hdc_flags & HDC_LOCKED) { 613 hdc->hdc_flags |= HDC_WAIT; 614 sleep((caddr_t)hdc, PRIBIO); 615 } 616 hdc->hdc_flags |= HDC_LOCKED; 617 splx(s); 618 } 619 620 /* 621 * Continue normal operations after pausing for 622 * munging the controller directly. 623 */ 624 hdcunlock(ctlr) 625 int ctlr; 626 { 627 register struct vba_ctlr *vm; 628 register struct hdcsoftc *hdc = &hdcsoftc[ctlr]; 629 630 hdc->hdc_flags &= ~HDC_LOCKED; 631 if (hdc->hdc_flags & HDC_WAIT) { 632 hdc->hdc_flags &= ~HDC_WAIT; 633 wakeup((caddr_t)hdc); 634 } else { 635 vm = hdcminfo[ctlr]; 636 if (vm->um_tab.b_actf) 637 hdcstart(vm); 638 } 639 } 640 641 hdintr(ctlr) 642 int ctlr; 643 { 644 register struct buf *bp, *dp; 645 register struct vba_ctlr *vm; 646 register struct vba_device *vi; 647 register struct hdcsoftc *hdc; 648 register struct mcb *mcb; 649 struct master_mcb *master; 650 register int status; 651 int timedout; 652 struct dksoftc *dk; 653 654 hdc = &hdcsoftc[ctlr]; 655 master = &hdc->hdc_mcb; 656 uncache(&master->mcs); 657 uncache(&master->context); 658 659 vm = hdcminfo[ctlr]; 660 if (!vm->um_tab.b_active || !(master->mcs&MCS_DONE)) { 661 printf("hd%d: stray interrupt\n", ctlr); 662 return; 663 } 664 665 dp = vm->um_tab.b_actf; 666 bp = dp->b_actf; 667 vi = hddinfo[hdunit(bp->b_dev)]; 668 dk = &dksoftc[vi->ui_unit]; 669 if (vi->ui_dk >= 0) 670 dk_busy &= ~(1<<vi->ui_dk); 671 timedout = (hdc->hdc_wticks >= HDCMAXTIME); 672 673 mcb = &dk->dk_mcb; 674 675 if (master->mcs & (MCS_SOFTERROR | MCS_FATALERROR) || timedout) 676 hdcerror(ctlr, *(u_long *)master->xstatus); 677 else 678 hdc->hdc_wticks = 0; 679 if (vm->um_tab.b_active) { 680 vm->um_tab.b_active = 0; 681 vm->um_tab.b_actf = dp->b_forw; 682 dp->b_active = 0; 683 dp->b_errcnt = 0; 684 dp->b_actf = bp->av_forw; 685 bp->b_resid = 0; 686 vbadone(bp, &hdc->hdc_rbuf); 687 biodone(bp); 688 /* start up now, if more work to do */ 689 if (dp->b_actf) 690 hdustart(vi); 691 else if (dk->dk_openpart == 0) 692 wakeup((caddr_t)dk); 693 } 694 /* if there are devices ready to transfer, start the controller. */ 695 if (hdc->hdc_flags & HDC_WAIT) { 696 hdc->hdc_flags &= ~HDC_WAIT; 697 wakeup((caddr_t)hdc); 698 } else if (vm->um_tab.b_actf) 699 hdcstart(vm); 700 } 701 702 hdioctl(dev, cmd, data, flag) 703 dev_t dev; 704 int cmd, flag; 705 caddr_t data; 706 { 707 register int unit; 708 register struct dksoftc *dk; 709 register struct disklabel *lp; 710 int error; 711 712 unit = hdunit(dev); 713 dk = &dksoftc[unit]; 714 lp = &dk->dk_label; 715 error = 0; 716 switch (cmd) { 717 case DIOCGDINFO: 718 *(struct disklabel *)data = *lp; 719 break; 720 case DIOCGPART: 721 ((struct partinfo *)data)->disklab = lp; 722 ((struct partinfo *)data)->part = 723 &lp->d_partitions[hdpart(dev)]; 724 break; 725 case DIOCSDINFO: 726 if ((flag & FWRITE) == 0) 727 error = EBADF; 728 else 729 error = setdisklabel(lp, (struct disklabel *)data, 730 (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); 731 if (error == 0 && dk->dk_state == OPENRAW) 732 dk->dk_state = OPEN; 733 break; 734 case DIOCWLABEL: 735 if ((flag & FWRITE) == 0) 736 error = EBADF; 737 else 738 dk->dk_wlabel = *(int *)data; 739 break; 740 case DIOCWDINFO: 741 if ((flag & FWRITE) == 0) 742 error = EBADF; 743 else if ((error = setdisklabel(lp, (struct disklabel *)data, 744 (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { 745 int wlab; 746 747 if (error == 0 && dk->dk_state == OPENRAW) 748 dk->dk_state = OPEN; 749 /* simulate opening partition 0 so write succeeds */ 750 dk->dk_openpart |= (1 << 0); /* XXX */ 751 wlab = dk->dk_wlabel; 752 dk->dk_wlabel = 1; 753 error = writedisklabel(dev, hdstrategy, lp); 754 dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; 755 dk->dk_wlabel = wlab; 756 } 757 break; 758 default: 759 error = ENOTTY; 760 break; 761 } 762 return (error); 763 } 764 765 /* 766 * Watch for lost interrupts. 767 */ 768 hdcwatch() 769 { 770 register struct hdcsoftc *hdc; 771 register struct vba_ctlr **vmp; 772 register int ctlr; 773 int s; 774 775 timeout(hdcwatch, (caddr_t)0, hz); 776 for (vmp = hdcminfo, hdc = hdcsoftc, ctlr = 0; ctlr < NHDC; 777 ++ctlr, ++vmp, ++hdc) { 778 if (*vmp == 0 || (*vmp)->um_alive == 0) 779 continue; 780 s = spl7(); 781 if ((*vmp)->um_tab.b_active && 782 hdc->hdc_wticks++ >= HDCMAXTIME) { 783 printf("hd%d: lost interrupt\n", ctlr); 784 hdintr(ctlr); 785 } 786 splx(s); 787 } 788 } 789 790 hddump(dev) 791 dev_t dev; 792 { 793 return(ENXIO); 794 } 795 796 hdsize(dev) 797 dev_t dev; 798 { 799 register int unit = hdunit(dev); 800 register struct dksoftc *dk; 801 struct vba_device *vi; 802 struct disklabel *lp; 803 804 if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0 || 805 (dk = &dksoftc[unit])->dk_state != OPEN) 806 return (-1); 807 lp = &dk->dk_label; 808 return ((int)lp->d_partitions[hdpart(dev)].p_size >> dk->dk_bshift); 809 } 810 811 hdimcb(dk) 812 register struct dksoftc *dk; 813 { 814 register struct master_mcb *master; 815 register struct mcb *mcb; 816 register struct hdcsoftc *hdc; 817 int timeout; 818 819 /* fill in mcb */ 820 mcb = &dk->dk_mcb; 821 mcb->interrupt = 0; 822 mcb->forw_phaddr = 0; 823 mcb->drive = dk->dk_unit; 824 825 hdc = &hdcsoftc[dk->dk_ctlr]; 826 master = &hdc->hdc_mcb; 827 828 /* fill in master mcb */ 829 master->mcw = MCL_IMMEDIATE; 830 master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb); 831 master->mcs = 0; 832 833 /* kick controller and wait */ 834 hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp; 835 for (timeout = 15000; timeout; --timeout) { 836 DELAY(1000); 837 mtpr(PADC, 0); 838 if (master->mcs&MCS_FATALERROR) { 839 printf("hdc%d: fatal error\n", dk->dk_ctlr); 840 hdcerror(dk->dk_ctlr, *(u_long *)master->xstatus); 841 return(1); 842 } 843 if (master->mcs&MCS_DONE) 844 return(0); 845 } 846 printf("hdc%d: timed out\n", dk->dk_ctlr); 847 return(1); 848 } 849 850 hdcerror(ctlr, code) 851 int ctlr; 852 u_long code; 853 { 854 printf("hd%d: error %lx\n", ctlr, code); 855 } 856 857 #ifdef COMPAT_42 858 hdreadgeometry(dk) 859 struct dksoftc *dk; 860 { 861 static geometry_sector geometry; 862 register struct mcb *mcb; 863 register struct disklabel *lp; 864 geometry_block *geo; 865 int cnt; 866 867 /* 868 * Read the geometry block (at head = 0 sector = 0 of the drive 869 * definition cylinder), validate it (must have the correct version 870 * number, header, and checksum). 871 */ 872 mcb = &dk->dk_mcb; 873 mcb->command = HCMD_READ; 874 mcb->cyl = dk->dk_def_cyl; 875 mcb->head = 0; 876 mcb->sector = 0; 877 mcb->chain[0].wcount = sizeof(geometry_sector) / sizeof(long); 878 mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &geometry); 879 /* mcb->chain[0].memadr = (long)&geometry; */ 880 if (hdimcb(dk)) { 881 printf("hd%d: can't read default geometry.\n", dk->dk_unit); 882 return(1); 883 } 884 geo = &geometry.geometry_block; 885 if (geo->version > 64000 || geo->version < 0) { 886 printf("hd%d: bad default geometry version#.\n", dk->dk_unit); 887 return(1); 888 } 889 if (bcmp(&geo->id[0], GB_ID, GB_ID_LEN)) { 890 printf("hd%d: bad default geometry header.\n", dk->dk_unit); 891 return(1); 892 } 893 GB_CHECKSUM(geo, cnt); 894 if (geometry.checksum != cnt) { 895 printf("hd%d: bad default geometry checksum.\n", dk->dk_unit); 896 return(1); 897 } 898 lp = &dk->dk_label; 899 900 /* 1K block in Harris geometry; convert to sectors for disklabels */ 901 for (cnt = 0; cnt < GB_MAXPART; cnt++) { 902 lp->d_partitions[cnt].p_offset = 903 geo->partition[cnt].start * (1024 / lp->d_secsize); 904 lp->d_partitions[cnt].p_size = 905 geo->partition[cnt].length * (1024 / lp->d_secsize); 906 } 907 lp->d_npartitions = GB_MAXPART; 908 return(0); 909 } 910 #endif /* COMPAT_42 */ 911 #endif /* NHD */ 912