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