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