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