1 /* vd.c 1.1 85/07/21 */ 2 3 #include "fsd.h" 4 #if NVD > 0 5 /* 6 ** VDDC Driver - Versabus to SMD direct interface version. 7 ** Written for TAHOE vmunix, CCI-WDC 9/1/83. 8 */ 9 10 #include "../h/param.h" 11 #include "../h/buf.h" 12 #include "../h/cmap.h" 13 #include "../h/conf.h" 14 #include "../h/dir.h" 15 #include "../h/dk.h" 16 #include "../h/map.h" 17 #include "../machine/mtpr.h" 18 #include "../machine/pte.h" 19 #include "../h/systm.h" 20 #include "../vba/vbavar.h" 21 #include "../h/user.h" 22 #include "../h/vmmac.h" 23 #include "../h/proc.h" 24 #include "../h/uio.h" 25 #include "../vba/vddc.h" 26 27 int vddebug = 1; /* if = 1, error messages are printed on the console */ 28 int vdintflg = 0; /* if = 1, interrupts are handled by the driver, 29 * otherwise they are just ignored. (during setup) */ 30 31 static struct size FSD[] = { 32 9600, 0, /* minor 0/ 8/16/24 = fsd0a - fsd3a - cyl 0 - 59*/ 33 12000, 9600, /* minor 1/ 9/17/25 = fsd0b - fsd3b - cyl 60 - 134*/ 34 108480, 21600, /* minor 2/10/18/26 = fsd0c - fsd3c - cyl 135 - 812*/ 35 1600, 130080, /* minor 3/11/19/27 = fsd0d - fsd3d - cyl 813 - 822*/ 36 130080, 0, /* minor 4/12/20/28 = fsd0e - fsd3e - cyl 0 - 812*/ 37 131680, 0, /* minor 5/13/21/29 = fsd0f - fsd3f - cyl 0 - 822*/ 38 0, 0, /* Non existent minor device */ 39 0, 0, /* Non existent minor device */ 40 0, 0, /* Non existent minor device */ 41 0, 0, /* Non existent minor device */ 42 0, 0, /* Non existent minor device */ 43 0, 0, /* Non existent minor device */ 44 0, 0, /* Non existent minor device */ 45 0, 0, /* Non existent minor device */ 46 0, 0, /* Non existent minor device */ 47 0, 0, /* Non existent minor device */ 48 }; 49 50 static struct size SMD[]= { 51 20064, 0, /* minor 32/40/48/56 = smd0a - smd3a cyl 0- 65 */ 52 13680, 20064, /* minor 33/41/49/57 = smd0b - smd3b cyl 66- 110 */ 53 214928, 33744, /* minor 34/42/50/58 = smd0c - smd3c cyl 111-817 */ 54 1520, 248672, /* minor 35/43/51/59 = smd0d - smd3d cyl 818-822 */ 55 248672, 0, /* minor 36/44/52/60 = smd0e - smd3e cyl 0-817 */ 56 250192, 0, /* minor 37/45/53/61 = smd0f - smd3f cyl 0-822 */ 57 0, 0, /* minor 38/46/54/62 = smd0g - smd3g */ 58 0, 0, /* minor 39/47/55/63 = smd0h - smd3h */ 59 0, 0, /* Non existent minor device */ 60 0, 0, /* Non existent minor device */ 61 0, 0, /* Non existent minor device */ 62 0, 0, /* Non existent minor device */ 63 0, 0, /* Non existent minor device */ 64 0, 0, /* Non existent minor device */ 65 0, 0, /* Non existent minor device */ 66 0, 0, /* Non existent minor device */ 67 }; 68 69 static struct size XFSD[] = { 70 20352, 0, /* minor 64/72/80/88 = xfsd0a - xfsd3a cyl 0- 52 */ 71 20352, 20352, /* minor 65/73/81/89 = xfsd0b - xfsd3b cyl 53- 105 */ 72 230400, 40704, /* minor 66/74/82/90 = xfsd0c - xfsd3c cyl 106-705 */ 73 1920, 271104, /* minor 67/75/83/91 = xfsd0d - xfsd3d cyl 706-710 */ 74 271104, 0, /* minor 68/76/84/92 = xfsd0e - xfsd3e cyl 0-705 */ 75 273024, 0, /* minor 69/77/85/93 = xfsd0f - xfsd3f cyl 0-710 */ 76 0, 0, /* minor 70/78/86/94 = xfsd0g - xfsd3g */ 77 0, 0, /* minor 71/79/87/95 = xfsd0h - xfsd3h */ 78 0, 0, /* Non existent minor device */ 79 0, 0, /* Non existent minor device */ 80 0, 0, /* Non existent minor device */ 81 0, 0, /* Non existent minor device */ 82 0, 0, /* Non existent minor device */ 83 0, 0, /* Non existent minor device */ 84 0, 0, /* Non existent minor device */ 85 0, 0, /* Non existent minor device */ 86 }; 87 88 /* 89 /* 90 /* Layout of minor number assignments for the VDDC devices. 91 /* 92 /* 1 93 /* 5 3 2 0 94 /* +---------------------------+-----+ 95 /* | Unit number | FLS | 96 /* +---------------------------+-----+ 97 /* | |_____ File system # ( 0-7 ) 98 /* |__________ Unit # in the system 99 /* 100 /********************************************************/ 101 102 #define VDUNIT(x) (minor(x) >> 3) 103 #define FLSYS(x) (minor(x) & 0x07) 104 #define PHYS(x) ( vtoph( 0, (int) (x) ) ) 105 106 107 /* Drive types should be in order of drive capacity for auto-configuration */ 108 /* e.g: smallest capacity = drive type 0, highest capacity = type NXPDRV-1 */ 109 110 struct vdst { 111 short nsect; 112 short ntrak; 113 short nspc; 114 short ncyl; 115 struct size *sizes; 116 short dtype; /* type as in byte 5 (drive) of iopb */ 117 char *name; /* drive name for autoconf */ 118 } vdst[] = { 119 120 16, 10, 16*10, 823, FSD, 0, "fsd", 121 16, 19, 16*19, 823, SMD, 1, "smd", 122 16, 24, 16*24, 711, XFSD, 2, "xfd" 123 }; 124 125 126 struct vba_ctlr *vdminfo[NVD]; 127 struct vba_device *vddinfo[NFSD]; 128 129 /* 130 ** Internal Functions 131 */ 132 int vdopen(); 133 int vdclose(); 134 int vdprobe(); /* See if VDDC is really there */ 135 int vd_setup(); /* Called from vdprobe */ 136 int vdslave(); /* See if drive is really there */ 137 int vdattach(); 138 int vddgo(); 139 int vdstrategy(); /* VDDC strategy routine */ 140 int vdstart(); /* Top level interface to device queue */ 141 int vdintr(); /* Top Level ISR */ 142 int vdread(); /* raw i/o read routine */ 143 int vdwrite(); /* raw i/o write routine */ 144 int vddump(); /* dump routine */ 145 int vdsize(); /* sizes for swapconfig */ 146 int dskrst(); /* reset a drive after hard error */ 147 148 long vdstd[] = { 149 0x0f2000 }; 150 151 struct vba_driver vddriver = { 152 vdprobe, vdslave, vdattach, vddgo, vdstd, 153 "smd/fsd", vddinfo, "vd", vdminfo 154 }; 155 156 struct buf vdutab[NFSD]; 157 struct buf rvdbuf[NFSD]; 158 char vdbuf[NVD][MAXBPTE * NBPG]; /* internal buffer for raw/swap i/o */ 159 long vdbufused[NVD]; 160 extern char vd0utl[],vd1utl[],vd2utl[],vd3utl[]; 161 162 /* 163 ** Disk Address 164 */ 165 struct dskadr { 166 char track; /* all 8 bits */ 167 char sector; /* low order 5 bits */ 168 short cylinder; /* low order 12 bits */ 169 }; 170 171 /* 172 ** DCB Trailer Formats 173 **********************************/ 174 175 /* 176 ** Read / Write Trailer 177 */ 178 struct trrw { 179 char *memadr; /* memory address */ 180 long wcount; /* 16 bit word count */ 181 struct dskadr disk; /* disk address */ 182 }; 183 184 /* 185 ** Format Trailer 186 */ 187 struct trfmt { 188 char *addr; /* data buffer to be filled on sector*/ 189 long nsectors; /* # of sectors to be formatted */ 190 struct dskadr disk; 191 struct dskadr hdr; 192 }; 193 194 /* 195 ** Reset / Configure Trailer 196 */ 197 struct treset { 198 long ncyl; /* # cylinders */ 199 long nsurfaces; /* # surfaces */ 200 }; /* # of sectors is defined by VDDC */ 201 /* to be 32/track of 512 data bytes each */ 202 203 /* 204 ** Seek Trailer 205 */ 206 struct trseek { 207 struct dskadr disk; 208 }; 209 210 /* 211 ** DCB Format 212 */ 213 struct fmt_dcb { 214 struct fmt_dcb *nxtdcb; /* next dcb in chain or End of Chain */ 215 short intflg; /* interrupt settings and flags */ 216 short opcode; /* DCB Command code etc... */ 217 long operrsta; /* Error & Status info */ 218 short fill; /* not used */ 219 char devselect; /* Drive selection */ 220 char trailcnt; /* Trailer Word Count */ 221 long err_memadr; /* Error memory address */ 222 short fill2; 223 short err_wcount; /* Error word count */ 224 short err_track; /* Error track/sector */ 225 short err_cyl; /* Error cylinder adr */ 226 union { 227 struct trrw rwtrail; /* read/write trailer */ 228 struct trfmt fmtrail; /* format trailer */ 229 struct treset resetrail; /* reset/configure trailer */ 230 struct trseek seektrail; /* seek trailer */ 231 } trail; 232 }; 233 234 /* 235 ** MDCB Format 236 */ 237 struct fmt_mdcb { 238 struct fmt_dcb *firstdcb; /* first dcb in chain */ 239 struct fmt_dcb *procdcb; /* dcb being processed */ 240 struct fmt_dcb *intdcb; /* dcb causing interrupt */ 241 long vddcstat; /* VDDC status */ 242 }mdcbx[NVD]; 243 244 /* 245 ** DCB 246 */ 247 248 struct fmt_dcb dcbx[NVD]; 249 250 int vdtimeout; 251 #define POLLTILLDONE(x, name) { \ 252 vdtimeout = 1000*(x); \ 253 uncache((char *)&dcb->operrsta); \ 254 while (! (dcb->operrsta & DCBCMP)) { \ 255 DELAY(1000); \ 256 vdtimeout--; \ 257 uncache((char *)&dcb->operrsta); \ 258 if (vdtimeout <=0) { \ 259 printf("vd: timeout on %s\n", name);\ 260 return(0); \ 261 } \ 262 } \ 263 } 264 265 /* 266 ** See if the controller is really there. 267 ** if TRUE - initialize the controller. 268 */ 269 vdprobe(cntrl_vaddr) 270 caddr_t cntrl_vaddr; 271 { 272 if ( badaddr(cntrl_vaddr,2) ) return(0); /* no controller */ 273 else 274 if (vd_setup(cntrl_vaddr)) /* initialize the controller */ 275 return(1); 276 else return(0); /* initialization error */ 277 } 278 279 vd_setup(cntrl_vaddr) 280 caddr_t cntrl_vaddr; 281 { 282 register struct fmt_dcb *dcb = &dcbx[0]; 283 register struct fmt_mdcb *mdcb = &mdcbx[0]; 284 int j; 285 286 VDDC_RESET(cntrl_vaddr); /* Reset the controller */ 287 /* Burn some time ...... needed after accessing reset port */ 288 for (j=0; j<20; j++) 289 DELAY(1000); 290 291 /* setup & issue INIT to initialize VDDC */ 292 293 dcb->opcode = INIT; 294 dcb->nxtdcb = (struct fmt_dcb *)0; 295 dcb->intflg = NOINT; 296 mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb); 297 dcb->operrsta = 0; 298 VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ); /* do it */ 299 POLLTILLDONE(1,"INIT"); /* poll till done */ 300 if (dcb->operrsta & HRDERR) { 301 if (vddebug) 302 printf("vd: init error, err=%b\n", 303 dcb->operrsta, ERRBITS); 304 return(0); 305 } 306 /* setup & issue DIAGNOSE */ 307 308 dcb->opcode = DIAG; 309 dcb->nxtdcb = (struct fmt_dcb *)0; 310 dcb->intflg = NOINT; 311 mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb); 312 dcb->operrsta = 0; 313 VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */ 314 POLLTILLDONE(1,"DIAG") /* poll till done */ 315 if (dcb->operrsta & HRDERR) { 316 if (vddebug) 317 printf("vd: diagnose error, err=%b\n", 318 dcb->operrsta, ERRBITS); 319 return(0); 320 } 321 /* Start drives command */ 322 #ifdef notdef 323 dcb->opcode = VDSTART; 324 dcb->nxtdcb = (struct fmt_dcb *)0; 325 dcb->intflg = NOINT; 326 mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb); 327 dcb->operrsta = 0; 328 VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */ 329 POLLTILLDONE(20,"VDSTART") /* poll till done */ 330 if (dcb->operrsta & HRDERR) { 331 if (vddebug) 332 printf("vd: start error, err=%b\n", 333 dcb->operrsta, ERRBITS); 334 return(0); 335 } 336 #endif 337 return(1); 338 } 339 340 /* 341 * See if a drive is really there 342 * Try to Reset/Configure the drive, then test its status. 343 */ 344 vdslave(ui,cntrl_vaddr) 345 register struct vba_device *ui; 346 register caddr_t cntrl_vaddr; 347 { 348 register struct fmt_dcb *dcb = &dcbx[0]; 349 register struct fmt_mdcb *mdcb = &mdcbx[ui->ui_ctlr]; 350 register struct vdst *st; 351 int dsktype; 352 353 /* 354 ** check drive status - see if drive exists. 355 */ 356 dcb->opcode = VDSTATUS; 357 dcb->intflg = NOINT; 358 dcb->operrsta = 0; 359 dcb->devselect = (char)ui->ui_slave; 360 dcb->trailcnt = (char)0; 361 mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb); 362 mdcb->vddcstat = 0; 363 VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb)) /* do it */ 364 POLLTILLDONE(5,"VDSTATUS") 365 #ifdef notdef 366 if (dcb->operrsta & HRDERR) { 367 if (vddebug) 368 printf("vd%d: status error, err=%b\n", ui->ui_unit, 369 dcb->operrsta, ERRBITS); 370 return(0); 371 } 372 #endif 373 uncache((char *)&mdcb->vddcstat); 374 if (mdcb->vddcstat & DRVNRDY) return(0); /* not ready-> non existent */ 375 376 /* 377 * drive is alive, now get its type! 378 * Seek on all drive types starting from the largest one. 379 * a sucessful seek to the last sector/cylinder/track verifies 380 * the drive type connected to this port. 381 */ 382 for (dsktype = NVDDRV-1; dsktype >= 0; dsktype--) { 383 st = &vdst[dsktype]; 384 dcb->opcode = RSTCFG; /* configure drive command */ 385 dcb->intflg = NOINT; 386 dcb->operrsta = 0; 387 dcb->trail.resetrail.ncyl = st->ncyl; 388 dcb->trail.resetrail.nsurfaces = st->ntrak; 389 dcb->devselect = (char)ui->ui_slave; 390 dcb->trailcnt = (char)2; 391 mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb); 392 VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */ 393 POLLTILLDONE(3,"RSTCFG") 394 if (dcb->operrsta & HRDERR) { 395 if (vddebug) 396 printf("vd%d: reset error, err=%b\n", 397 ui->ui_unit, dcb->operrsta, ERRBITS); 398 return(0); 399 } 400 mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb); 401 dcb->intflg = NOINT; 402 dcb->opcode = RD; 403 dcb->operrsta = 0; 404 dcb->devselect = (char)ui->ui_slave; 405 dcb->trailcnt = (char)3; 406 dcb->trail.rwtrail.memadr = (char *)PHYS(vdbuf); 407 dcb->trail.rwtrail.wcount = 256; 408 dcb->trail.rwtrail.disk.cylinder = st->ncyl -4; 409 dcb->trail.rwtrail.disk.track = st->ntrak -1; 410 dcb->trail.rwtrail.disk.sector = 0; 411 VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */ 412 POLLTILLDONE(5,"RD") 413 if (vddebug) 414 printf("vd%d: cyl %d, trk %d, sec %d, operrsta err=%b\n", 415 ui->ui_unit, 416 dcb->trail.rwtrail.disk.cylinder, 417 dcb->trail.rwtrail.disk.track, 418 dcb->trail.rwtrail.disk.sector, 419 dcb->operrsta, ERRBITS); 420 if ( (dcb->operrsta & HRDERR) == 0) 421 /* found the drive type! */ 422 break; 423 } 424 if (dsktype < 0) { 425 /* If reached here, a drive which is not defined in the 426 * 'vdst' tables is connected. Cannot set it's type. 427 */ 428 printf("vd%d: unrecognized drive type\n", ui->ui_unit); 429 return(0); 430 } 431 ui->ui_type = dsktype; 432 vddriver.ud_dname = st->name; 433 return(1); 434 } 435 436 vdattach(ui) 437 struct vba_device *ui; 438 { 439 if (ui->ui_dk >= 0) 440 dk_mspw[ui->ui_dk] = .0000020345; /* BAD VALUE */ 441 } 442 443 vddgo(um) 444 struct vba_ctlr *um; 445 { 446 } 447 448 vdstrategy(bp) 449 register struct buf *bp; 450 { 451 register struct vba_device *ui; 452 register struct vba_ctlr *um; 453 register int unit; 454 register struct buf *dp; 455 register struct size *sizep; 456 int index, blocks, s; 457 458 vdintflg = 1; /* enable interrupts handling by the driver */ 459 blocks = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; 460 unit = VDUNIT(bp->b_dev); 461 ui = vddinfo[unit]; 462 if (ui == 0 || ui->ui_alive == 0) goto bad1; 463 index = FLSYS(bp->b_dev); /* get file system index */ 464 sizep = vdst[ui->ui_type].sizes; 465 if (bp->b_blkno < 0 || 466 (dkblock(bp)+blocks > sizep[index].nblocks)) /* disk overflow */ 467 goto bad1; 468 s = spl8(); 469 dp = &vdutab[ui->ui_unit]; 470 bp->b_resid = bp->b_blkno + sizep[index].block0; 471 /* block # plays same role as 472 cylinder # for disksort, as long 473 as increasing blocks correspond to 474 increasing cylinders on disk */ 475 476 buf_setup (bp, SECTSIZ); 477 478 disksort(dp, bp); 479 if (dp->b_active == 0) { /* unit is on controller queue */ 480 /* put the device on the controller queue */ 481 dp->b_forw = NULL; /* end of queue indicator */ 482 um = ui->ui_mi; /* get controller structure !! */ 483 if (um->um_tab.b_actf == NULL) /* controller queue is empty */ 484 um->um_tab.b_actf = dp; 485 else 486 um->um_tab.b_actl->b_forw = dp; /* add into queue */ 487 um->um_tab.b_actl = dp; /* update queue tail */ 488 dp->b_active ++; 489 } 490 bp = &ui->ui_mi->um_tab; /* controller structure addr */ 491 if (bp->b_actf && /* cntrl queue not empty */ 492 bp->b_active == 0) /* controller not active */ 493 (void) vdstart(ui->ui_mi);/* go start I/O */ 494 splx(s); 495 return; 496 497 bad1: 498 bp->b_flags |= B_ERROR; 499 iodone(bp); 500 return; 501 } 502 503 504 /* 505 * Start up a transfer on a drive. 506 */ 507 vdstart(um) 508 register struct vba_ctlr *um; 509 { 510 register struct buf *bp, *dp; 511 register struct fmt_dcb *dcb = &dcbx[um->um_ctlr]; 512 register struct fmt_mdcb *mdcb; 513 register struct size *sizep; /* Pointer to one of the tables */ 514 register struct vdst *st; 515 register int index ; /* Index in the relevant table */ 516 register int phadr; /* Buffer's physical address */ 517 register caddr_t cntrl_vaddr = um->um_addr; 518 int sblock, unit; 519 int ct; 520 521 loop: 522 /* 523 * Pull a request off the controller queue 524 */ 525 if ((dp = um->um_tab.b_actf) == NULL) 526 return ; 527 if ((bp = dp->b_actf) == NULL) { 528 dp->b_active = 0; /* device removed from ctlr queue */ 529 um->um_tab.b_actf = dp->b_forw; 530 goto loop; 531 } 532 /* 533 * Mark controller busy, and 534 * prepare a command packet for the controller. 535 */ 536 um->um_tab.b_active++; 537 unit = VDUNIT(bp->b_dev); 538 st = &vdst[vddinfo[unit]->ui_type]; 539 mdcb = &mdcbx[vddinfo[unit]->ui_ctlr]; 540 index = FLSYS(bp->b_dev); 541 sizep = st->sizes; 542 mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb); 543 dcb->intflg = INTDUN; /* interrupt on completion */ 544 dcb->opcode = (bp->b_flags & B_READ) ? RD : WD; 545 dcb->operrsta = 0; 546 dcb->devselect = (char)(vddinfo[unit])->ui_slave; 547 dcb->trailcnt = (char)3; 548 ct = vddinfo[unit]->ui_ctlr; 549 550 switch (ct) { 551 case 0: 552 phadr = get_ioadr(bp, vdbuf[0], VD0map, (caddr_t)vd0utl); 553 break; 554 case 1: 555 phadr = get_ioadr(bp, vdbuf[1], VD1map, (caddr_t)vd1utl); 556 break; 557 case 2: 558 phadr = get_ioadr(bp, vdbuf[2], VD2map, (caddr_t)vd2utl); 559 break; 560 case 3: 561 phadr = get_ioadr(bp, vdbuf[3], VD3map, (caddr_t)vd3utl); 562 break; 563 } 564 /* 565 phadr = get_ioadr(bp, vdbuf, IOmap, (caddr_t)ioutl); 566 */ 567 568 if (vddinfo[unit]->ui_dk >= 0) { 569 int dku = vddinfo[unit]->ui_dk; 570 dk_busy |= 1<<dku; 571 dk_xfer[dku]++; 572 dk_wds[dku] += bp->b_bcount>>6; 573 } 574 dcb->trail.rwtrail.memadr = (char *)phadr; 575 dcb->trail.rwtrail.wcount = (bp->b_bcount + 1) / 2; 576 sblock = sizep[index].block0 + bp->b_blkno; 577 dcb->trail.rwtrail.disk.cylinder = (short)(sblock / st->nspc); 578 dcb->trail.rwtrail.disk.track = (char)((sblock % st->nspc) / st->nsect); 579 dcb->trail.rwtrail.disk.sector = (char)(sblock*2 % (st->nsect*2)); 580 581 #ifdef VDDCPERF 582 scope_out(1); 583 #endif 584 585 VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb)) /* do it */ 586 } 587 588 589 /* 590 * Handle a disk interrupt. 591 */ 592 vdintr(vdnum) 593 register vdnum; 594 { 595 register struct buf *bp, *dp; 596 register struct vba_ctlr *um = vdminfo[vdnum]; 597 register struct fmt_dcb *dcb = &dcbx[vdnum]; 598 register struct fmt_mdcb *mdcb = &mdcbx[vdnum]; 599 register struct vdst *st; 600 int unit; 601 struct vba_device *ui; 602 603 #ifdef VDDCPERF 604 scope_out(2); 605 #endif 606 if (intenable == 0 || vdintflg == 0) /* ignore all interrupts */ 607 return; 608 if (um->um_tab.b_active == NULL) return;/* unexpected interrupt */ 609 uncache((char *)&mdcb->intdcb); 610 uncache((char *)&dcb->operrsta); 611 if ( mdcb->intdcb != (struct fmt_dcb *)PHYS(dcb)) { /* dcb causing interrupt */ 612 printf("vd%d: bad dcb=%x (phys=%x)\n", 613 vdnum, mdcb->intdcb, PHYS(dcb)); 614 return; 615 } 616 if (! (dcb->operrsta & DCBCMP)) { /* unexpected interrupt */ 617 printf("vd%d: unexpected interrupt, err=%b\n", vdnum, 618 dcb->operrsta, ERRBITS); 619 return; 620 } 621 dp = um->um_tab.b_actf; /* device queue head in ctlr queue */ 622 bp = dp->b_actf; /* first buffer in device queue */ 623 unit = VDUNIT(bp->b_dev); 624 ui = vddinfo[unit]; 625 if (ui->ui_dk >= 0) 626 dk_busy &= ~(1 << ui->ui_dk); 627 if (dcb->operrsta & (HRDERR|SFTERR)) { 628 st = &vdst[ui->ui_type]; 629 if (dcb->operrsta & HRDERR) { 630 harderr(bp, &st->name[7]); 631 printf("status=%b\n", dcb->operrsta, ERRBITS); 632 dskrst(bp); 633 bp->b_flags |= B_ERROR; 634 } else 635 #define SECTOR(x) ((x)*2) 636 printf("%s%d: soft error sn%d status=%b\n", &st->name[7], unit, 637 SECTOR(bp->b_blkno + st->sizes[FLSYS(bp->b_dev)].block0), 638 dcb->operrsta, ERRBITS); 639 } 640 switch (vdnum) { 641 case 0: 642 end_transfer(bp, vdbuf[0], VD0map, (caddr_t)vd0utl); 643 break; 644 case 1: 645 end_transfer(bp, vdbuf[1], VD1map, (caddr_t)vd1utl); 646 break; 647 case 2: 648 end_transfer(bp, vdbuf[2], VD2map, (caddr_t)vd2utl); 649 break; 650 case 3: 651 end_transfer(bp, vdbuf[3], VD3map, (caddr_t)vd3utl); 652 break; 653 } 654 655 um->um_tab.b_active = 0; 656 um->um_tab.b_errcnt = 0; 657 if (dp->b_forw != NULL) { /* more than 1 unit on queue */ 658 um->um_tab.b_actf = dp->b_forw; /* next device on ctlr queue */ 659 dp->b_forw = um->um_tab.b_actl->b_forw; /* be last in queue */ 660 um->um_tab.b_actl->b_forw = dp; /* last points now to dp */ 661 um->um_tab.b_actl = dp; /* pointer in ctlr structure */ 662 } 663 dp->b_errcnt = 0; 664 dp->b_actf = bp->av_forw; /* remove first from queue */ 665 bp->b_resid = 0; /* All data read here */ 666 667 #ifdef VDDCPERF 668 scope_out(3); 669 #endif 670 671 iodone(bp); 672 vdstart(um); /* start requests for next device on queue */ 673 } 674 675 676 vdread(dev, uio) 677 dev_t dev; 678 struct uio *uio; 679 { 680 register int unit = VDUNIT(dev); 681 register int error; 682 register int ct; 683 register int s; 684 685 if (unit >= NFSD) 686 error = ENXIO; 687 else { 688 ct = vddinfo[unit]->ui_ctlr; 689 s = spl8(); 690 while (vdbufused[ct]) sleep (&vdbufused[ct],PRIBIO+1); 691 vdbufused[ct] = 1; 692 splx(s); 693 error = physio(vdstrategy, &rvdbuf[unit], dev, B_READ, minphys, uio); 694 vdbufused[ct] = 0; 695 wakeup (&vdbufused[ct]); 696 } 697 return error; 698 } 699 700 vdwrite(dev, uio) 701 dev_t dev; 702 struct uio *uio; 703 { 704 register int unit = VDUNIT(dev); 705 register int error; 706 register int ct; 707 register int s; 708 709 if (unit >= NFSD) 710 error = ENXIO; 711 else { 712 ct = vddinfo[unit]->ui_ctlr; 713 s = spl8(); 714 while (vdbufused[ct]) sleep (&vdbufused[ct],PRIBIO+1); 715 vdbufused[ct] = 1; 716 splx(s); 717 error = physio(vdstrategy, &rvdbuf[unit], dev, B_WRITE, minphys, uio); 718 vdbufused[ct] = 0; 719 wakeup (&vdbufused[ct]); 720 } 721 return error; 722 } 723 724 #define DUMPSIZE 32 /* Up to 32k at a time - controller limit */ 725 726 vddump(dev) 727 dev_t dev; 728 /* 729 * Dump the main memory to the given device. 730 */ 731 { 732 register struct vba_ctlr *um; 733 register struct fmt_dcb *dcb = &dcbx[0]; 734 register struct fmt_mdcb *mdcb = &mdcbx[0]; 735 register struct vdst *st; 736 register int unit; 737 register caddr_t cntrl_vaddr ; 738 register struct size *sizep; /* Pointer to one of the tables */ 739 int index,sblock,blkcount,thiscount; 740 int memaddr; 741 742 unit = VDUNIT(dev); 743 um = (vddinfo[unit])->ui_mi; 744 st = &vdst[(vddinfo[unit])->ui_type]; 745 dcb = &dcbx[um->um_ctlr]; 746 cntrl_vaddr = um->um_addr; 747 memaddr = 0x0; 748 index = FLSYS(dev); 749 sizep = st->sizes; 750 blkcount = maxfree - 2; /* In 1k byte pages */ 751 if (dumplo + blkcount > sizep[index].nblocks) return(EINVAL); 752 sblock = sizep[index].block0 + dumplo; 753 while (blkcount > 0) { 754 thiscount = MIN (blkcount, DUMPSIZE); 755 mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb); 756 dcb->intflg = NOINT; 757 dcb->opcode = WD; 758 dcb->operrsta = 0; 759 dcb->devselect = (char)(vddinfo[unit])->ui_slave; 760 dcb->trailcnt = (char)3; 761 dcb->trail.rwtrail.memadr = (char *)memaddr; 762 dcb->trail.rwtrail.wcount = thiscount*512; 763 dcb->trail.rwtrail.disk.cylinder= (short)(sblock/st->nspc); 764 dcb->trail.rwtrail.disk.track = (char)((sblock % st->nspc) 765 / st->nsect); 766 dcb->trail.rwtrail.disk.sector = (char)(sblock*2 % (st->nsect*2)); 767 VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */ 768 POLLTILLDONE(5,"WD"); 769 if (dcb->operrsta & HRDERR) { 770 if (vddebug) 771 printf("vd%d: i/o error, err=%b\n", unit, 772 dcb->operrsta, ERRBITS); 773 return(EIO); 774 }; 775 blkcount -= thiscount; 776 memaddr += thiscount*NBPG; 777 sblock += thiscount; 778 } 779 return(0); 780 } 781 782 vdopen(dev, flag) 783 register dev_t dev; 784 int flag; 785 { 786 register struct vba_device *ui; 787 register unit = VDUNIT(dev); 788 789 ui = vddinfo[unit]; 790 if (ui == 0 || ui->ui_alive == 0 || ui->ui_type >= NVDDRV) 791 return ENXIO; 792 return 0; 793 } 794 795 vdsize(dev) 796 register dev_t dev; 797 { 798 register struct vba_device *ui; 799 register unit = VDUNIT(dev); 800 801 ui = vddinfo[unit]; 802 if (ui == 0 || ui->ui_alive == 0 || ui->ui_type >= NVDDRV) 803 return -1; 804 return vdst[ui->ui_type].sizes[FLSYS(dev)].nblocks; 805 } 806 807 /* reset a drive after a hard error */ 808 dskrst(bp) 809 register struct buf *bp; 810 { 811 register struct vdst *st; 812 register struct fmt_dcb *dcb; 813 register struct fmt_mdcb *mdcb; 814 register struct vba_device *ui; 815 register caddr_t cntrl_vaddr ; 816 int unit; 817 818 unit = VDUNIT(bp->b_dev); 819 ui = vddinfo[unit]; 820 mdcb = &mdcbx[ui->ui_ctlr]; 821 dcb = &dcbx[ui->ui_ctlr]; 822 cntrl_vaddr = (ui->ui_mi)->um_addr; 823 st = &vdst[vddinfo[unit]->ui_type]; 824 dcb->opcode = RSTCFG; /* configure drive command */ 825 dcb->intflg = NOINT; 826 dcb->operrsta = 0; 827 dcb->trail.resetrail.ncyl = st->ncyl; 828 dcb->trail.resetrail.nsurfaces = st->ntrak; 829 dcb->devselect = (char)ui->ui_slave; 830 dcb->trailcnt = (char)2; 831 mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb); 832 VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */ 833 POLLTILLDONE(3,"reset") 834 if (dcb->operrsta & HRDERR) { 835 if (vddebug) { 836 harderr(bp, &st->name[7]); 837 printf("reset failed, err=%b\n", dcb->operrsta,ERRBITS); 838 } 839 } 840 } 841 #endif 842