1 /* vd.c 1.4 86/01/12 */ 2 3 #include "fsd.h" 4 #if NVD > 0 5 /* 6 * VDDC - Versabus SMD/ESMD driver. 7 */ 8 #include "../tahoe/mtpr.h" 9 #include "../tahoe/pte.h" 10 11 #include "param.h" 12 #include "buf.h" 13 #include "cmap.h" 14 #include "conf.h" 15 #include "dir.h" 16 #include "dk.h" 17 #include "map.h" 18 #include "systm.h" 19 #include "user.h" 20 #include "vmmac.h" 21 #include "proc.h" 22 #include "uio.h" 23 24 #include "../tahoevba/vbavar.h" 25 #define VDGENDATA 26 #include "../tahoevba/vddcreg.h" 27 #undef VDGENDATA 28 29 #define MAX_BLOCKSIZE (MAXBPTE*NBPG) 30 #define DUMPSIZE 64 /* controller limit */ 31 32 #define VDUNIT(x) (minor(x) >> 3) 33 #define FILSYS(x) (minor(x) & 0x07) 34 #define PHYS(x) (vtoph((struct proc *)0, (unsigned)(x))) 35 #define TRUE 1 36 #define FALSE 0 37 38 #define CTLR_ERROR 1 39 #define DRIVE_ERROR 2 40 #define HARD_DATA_ERROR 3 41 #define SOFT_DATA_ERROR 4 42 43 #define b_cylin b_resid 44 #define b_daddr b_error 45 46 struct vba_ctlr *vdminfo[NVD]; 47 struct vba_device *vddinfo[NFSD]; 48 int vdprobe(), vdslave(), vdattach(), vddgo(); 49 struct vba_driver vddriver = 50 { vdprobe, vdslave, vdattach, vddgo, vddcaddr, "smd/fsd", 51 vddinfo, "vd", vdminfo }; 52 53 /* 54 * Per-drive state. 55 */ 56 typedef struct { 57 struct buf raw_q_element; 58 short sec_per_blk; 59 short sec_per_cyl; 60 char status; 61 struct buf xfer_queue; 62 int drive_type; 63 fs_tab info; 64 } unit_tab; 65 66 /* 67 * Per-controller state. 68 */ 69 typedef struct { 70 char ctlr_type; /* controller type */ 71 char *map; /* i/o page map */ 72 char *utl; /* mapped i/o space */ 73 u_int cur_slave:8; /* last active unit number */ 74 u_int int_expected:1; /* expect an interupt */ 75 u_int ctlr_started:1; /* start command was issued */ 76 u_int overlap_seeks:1;/* should overlap seeks */ 77 u_int off_cylinder:16;/* off cylinder bit map */ 78 u_int unit_type[16]; /* slave types */ 79 u_int cur_cyl[16]; /* cylinder last selected */ 80 long cur_trk[16]; /* track last selected */ 81 fmt_mdcb ctlr_mdcb; /* controller mdcb */ 82 fmt_dcb ctlr_dcb; /* r/w dcb */ 83 fmt_dcb seek_dcb[4]; /* dcbs for overlapped seeks */ 84 /* buffer for raw/swap i/o */ 85 char rawbuf[MAX_BLOCKSIZE]; 86 } ctlr_tab; 87 88 extern char vd0utl[]; 89 #if NVD > 1 90 extern char vd1utl[]; 91 #endif 92 #if NVD > 2 93 extern char vd2utl[]; 94 #endif 95 #if NVD > 3 96 extern char vd3utl[]; 97 #endif 98 99 #define VDCINIT(map, utl) { \ 100 UNKNOWN, (char *)map, utl, 0, FALSE, FALSE, TRUE, 0, \ 101 { UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, \ 102 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN } \ 103 } 104 ctlr_tab vdctlr_info[NVD] = { 105 VDCINIT(VD0map, vd0utl), 106 #if NVD > 1 107 VDCINIT(VD1map, vd1utl), 108 #endif 109 #if NVD > 2 110 VDCINIT(VD2map, vd2utl), 111 #endif 112 #if NVD > 3 113 VDCINIT(VD3map, vd3utl), 114 #endif 115 }; 116 117 unit_tab vdunit_info[NFSD]; 118 119 /* 120 * See if the controller is really there; if so, initialize it. 121 */ 122 vdprobe(reg, vm) 123 caddr_t reg; 124 struct vba_ctlr *vm; 125 { 126 register br, cvec; /* must be r12, r11 */ 127 register cdr *cp = (cdr *)reg; 128 129 if (badaddr((caddr_t)reg, 2)) 130 return (0); 131 cp->cdr_reset = 0xffffffff; 132 DELAY(1000000); 133 if (cp->cdr_reset != (unsigned)0xffffffff) { 134 DELAY(1000000); 135 } else { 136 cp->cdr_reserved = 0x0; 137 DELAY(3000000); 138 } 139 br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 140 return (sizeof (*cp)); 141 } 142 143 /* 144 * See if a drive is really there 145 * Try to reset/configure the drive, then test its status. 146 */ 147 vdslave(vi, addr) 148 register struct vba_device *vi; 149 register cdr *addr; 150 { 151 register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr]; 152 register unit_tab *ui = &vdunit_info[vi->ui_unit]; 153 register fmt_mdcb *mdcb = &ci->ctlr_mdcb; 154 register fmt_dcb *dcb = &ci->ctlr_dcb; 155 register int type; 156 157 if (ci->ctlr_type == UNKNOWN) { 158 addr->cdr_reset = 0xffffffff; 159 DELAY(1000000); 160 if (addr->cdr_reset != (unsigned)0xffffffff) { 161 ci->ctlr_type = SMDCTLR; 162 ci->overlap_seeks = 0; 163 DELAY(1000000); 164 } else { 165 ci->overlap_seeks = 1; 166 ci->ctlr_type = SMD_ECTLR; 167 addr->cdr_reserved = 0x0; 168 DELAY(3000000); 169 addr->cdr_csr = 0; 170 addr->mdcb_tcf = AM_ENPDA; 171 addr->dcb_tcf = AM_ENPDA; 172 addr->trail_tcf = AM_ENPDA; 173 addr->data_tcf = AM_ENPDA; 174 addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 175 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 176 } 177 printf("vd%d: %s controller\n", vi->ui_unit, 178 ci->ctlr_type == SMDCTLR ? "smd" : "xsmd"); 179 if (vdnotrailer(addr, 180 vi->ui_ctlr, vi->ui_slave, INIT, 10) & HRDERR) { 181 printf("vd%d: init error\n", vi->ui_unit); 182 return (0); 183 } 184 if (vdnotrailer(addr, 185 vi->ui_ctlr, vi->ui_slave, DIAG, 10) & HRDERR) { 186 printf("vd%d: diagnostic error\n", vi->ui_unit); 187 return (0); 188 } 189 } 190 /* 191 * Seek on all drive types starting from the largest one. 192 * a successful seek to the last sector/cylinder/track verifies 193 * the drive type connected to this port. 194 */ 195 for (type = 0; type < nvddrv; type++) { 196 /* XXX */ 197 if (ci->ctlr_type == SMDCTLR && vdst[type].nsec != 32) 198 continue; 199 /* XXX */ 200 if (!vdconfigure_drive(addr, vi->ui_ctlr, vi->ui_slave, type,0)) 201 return (0); 202 dcb->opcode = (short)RD; 203 dcb->intflg = NOINT; 204 dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */ 205 dcb->operrsta = 0; 206 dcb->devselect = (char)(vi->ui_slave); 207 dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long)); 208 dcb->trail.rwtrail.memadr = (char *)PHYS(ci->rawbuf); 209 dcb->trail.rwtrail.wcount = vdst[type].secsize/sizeof(short); 210 dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2; 211 dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1; 212 dcb->trail.rwtrail.disk.sector = vdst[type].nsec - 1; 213 mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 214 mdcb->vddcstat = 0; 215 VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 216 POLLTILLDONE(addr, dcb, 60, ci->ctlr_type); 217 if (vdtimeout <= 0) 218 printf(" during probe\n"); 219 if ((dcb->operrsta&HRDERR) == 0) 220 break; 221 } 222 if (type >= nvddrv) { 223 /* 224 * If reached here, a drive which is not defined in the 225 * 'vdst' tables is connected. Cannot set it's type. 226 */ 227 printf("vd%d: unknown drive type\n", vi->ui_unit); 228 return (0); 229 } 230 ui->drive_type = type; 231 ui->info = vdst[type]; 232 ui->sec_per_blk = DEV_BSIZE / ui->info.secsize; 233 vi->ui_type = type; 234 vi->ui_dk = 1; 235 vddriver.ud_dname = ui->info.type_name; 236 return (1); 237 } 238 239 vdconfigure_drive(addr, ctlr, slave, type, pass) 240 register cdr *addr; 241 int ctlr, slave, type, pass; 242 { 243 register ctlr_tab *ci = &vdctlr_info[ctlr]; 244 245 ci->ctlr_dcb.opcode = RSTCFG; /* command */ 246 ci->ctlr_dcb.intflg = NOINT; 247 ci->ctlr_dcb.nxtdcb = (fmt_dcb *)0; /* end of chain */ 248 ci->ctlr_dcb.operrsta = 0; 249 ci->ctlr_dcb.devselect = (char)slave; 250 ci->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl; 251 ci->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak; 252 if (ci->ctlr_type == SMD_ECTLR) { 253 ci->ctlr_dcb.trailcnt = (char)4; 254 ci->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec; 255 ci->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip; 256 } else 257 ci->ctlr_dcb.trailcnt = (char)2; 258 ci->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&ci->ctlr_dcb)); 259 ci->ctlr_mdcb.vddcstat = 0; 260 VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(&ci->ctlr_mdcb)), ci->ctlr_type); 261 POLLTILLDONE(addr, &ci->ctlr_dcb, 5, ci->ctlr_type); 262 if (vdtimeout <= 0) { 263 printf(" during config\n"); 264 return (0); 265 } 266 if (ci->ctlr_dcb.operrsta & HRDERR) { 267 if ((ci->ctlr_dcb.operrsta & (NOTCYLERR|DRVNRDY)) == 0) 268 printf("vd%d: drive %d: config error\n", ctlr, slave); 269 else if (pass == 0) { 270 vdstart_drive(addr, ctlr, slave); 271 return (vdconfigure_drive(addr, ctlr, slave, type, 1)); 272 } else if (pass == 2) 273 return (vdconfigure_drive(addr, ctlr, slave, type, 3)); 274 return (0); 275 } 276 return (1); 277 } 278 279 vdstart_drive(addr, ctlr, slave) 280 cdr *addr; 281 register int ctlr, slave; 282 { 283 int error = 0; 284 285 printf("vd%d: starting drive %d, wait...", ctlr, slave); 286 if (vdctlr_info[ctlr].ctlr_started) { 287 printf("DELAY(5500000)..."); 288 DELAY(5500000); 289 goto done; 290 } 291 vdctlr_info[ctlr].ctlr_started = 1; 292 error = vdnotrailer(addr, ctlr, 0, VDSTART, (slave*6)+62) & HRDERR; 293 if (!error) { 294 printf("DELAY(%d)...", (slave * 5500000) + 62000000); 295 DELAY((slave * 5500000) + 62000000); 296 } 297 done: 298 printf("\n"); 299 return (error == 0); 300 } 301 302 vdnotrailer(addr, ctlr, unit, function, time) 303 register cdr *addr; 304 int ctlr, unit, function, time; 305 { 306 fmt_mdcb *mdcb = &vdctlr_info[ctlr].ctlr_mdcb; 307 fmt_dcb *dcb = &vdctlr_info[ctlr].ctlr_dcb; 308 int type = vdctlr_info[ctlr].ctlr_type; 309 310 dcb->opcode = function; /* command */ 311 dcb->intflg = NOINT; 312 dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */ 313 dcb->operrsta = 0; 314 dcb->devselect = (char)unit; 315 dcb->trailcnt = (char)0; 316 mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 317 mdcb->vddcstat = 0; 318 VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), type); 319 POLLTILLDONE(addr, dcb, time, type); 320 if (vdtimeout <= 0) { 321 printf(" during init\n"); 322 return (DCBCMP|ANYERR|HRDERR|OPABRT); 323 } 324 return (dcb->operrsta); 325 } 326 327 vdattach(vi) 328 register struct vba_device *vi; 329 { 330 register unit_tab *ui = &vdunit_info[vi->ui_unit]; 331 register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr]; 332 register struct buf *cq = &vi->ui_mi->um_tab; 333 register struct buf *uq = cq->b_forw; 334 register struct buf *start_queue = uq; 335 register fs_tab *fs = &ui->info; 336 337 ui->info = vdst[vi->ui_type]; 338 ui->sec_per_blk = DEV_BSIZE / ui->info.secsize; 339 ui->sec_per_cyl = ui->info.nsec * ui->info.ntrak; 340 ui->xfer_queue.b_dev = vi->ui_slave; 341 ci->unit_type[vi->ui_slave] = vi->ui_type; 342 /* load unit into controller's active unit list */ 343 if (uq == NULL) { 344 cq->b_forw = &ui->xfer_queue; 345 ui->xfer_queue.b_forw = &ui->xfer_queue; 346 ui->xfer_queue.b_back = &ui->xfer_queue; 347 } else { 348 while (uq->b_forw != start_queue) 349 uq = uq->b_forw; 350 ui->xfer_queue.b_forw = start_queue; 351 ui->xfer_queue.b_back = uq; 352 uq->b_forw = &ui->xfer_queue; 353 start_queue->b_back = &ui->xfer_queue; 354 } 355 /* 356 * (60 / rpm) / (number of sectors per track * (bytes per sector / 2)) 357 */ 358 dk_mspw[vi->ui_unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize); 359 } 360 361 /*ARGSUSED*/ 362 vddgo(um) 363 struct vba_ctlr *um; 364 { 365 366 } 367 368 vdstrategy(bp) 369 register struct buf *bp; 370 { 371 register int unit = VDUNIT(bp->b_dev); 372 register struct vba_device *vi = vddinfo[unit]; 373 register par_tab *par; 374 register unit_tab *ui; 375 register fs_tab *fs; 376 register int blks, bn, s; 377 378 if (bp->b_bcount == 0 || vi == 0 || vi->ui_alive == 0) 379 goto bad; 380 ui = &vdunit_info[unit]; 381 fs = &ui->info; 382 par = &fs->partition[FILSYS(bp->b_dev)]; 383 blks = (bp->b_bcount + DEV_BSIZE-1) >> DEV_BSHIFT; 384 if (bp->b_blkno + blks >= par->par_len) { 385 blks = par->par_len - bp->b_blkno; 386 if (blks <= 0) 387 goto bad; 388 bp->b_bcount = blks * DEV_BSIZE; 389 } 390 bn = bp->b_blkno + par->par_start; 391 bn *= ui->sec_per_blk; 392 bp->b_daddr = (bn / fs->nsec) % fs->ntrak; 393 bp->b_cylin = bn / ui->sec_per_cyl; 394 vbasetup(bp, ui->info.secsize); 395 s = spl7(); 396 if (ui->xfer_queue.av_forw == NULL) { 397 register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr]; 398 int slave = vi->ui_slave; 399 400 if (bp->b_cylin != ci->cur_cyl[slave] || 401 bp->b_daddr != ci->cur_trk[slave]) 402 ci->off_cylinder |= 1 << slave; 403 } 404 bp->b_daddr |= (bn % fs->nsec) << 8; 405 disksort(&ui->xfer_queue, bp); 406 if (!vddinfo[unit]->ui_mi->um_tab.b_active++) { 407 splx(s); 408 vdstart(vddinfo[unit]->ui_mi); 409 } else 410 splx(s); 411 return; 412 bad: 413 bp->b_flags |= B_ERROR, bp->b_error = ENXIO; 414 bp->b_resid = bp->b_bcount; 415 iodone(bp); 416 } 417 418 /* 419 * Start up a transfer on a drive. 420 */ 421 vdstart(ci) 422 register struct vba_ctlr *ci; 423 { 424 register struct buf *cq = &ci->um_tab; 425 register struct buf *uq = cq->b_forw; 426 427 /* search for next ready unit */ 428 cq->b_forw = cq->b_forw->b_forw; 429 uq = cq->b_forw; 430 do { 431 if (uq->av_forw != NULL) { 432 cq->b_forw = uq; 433 vdexecute(ci, uq); 434 return; 435 } 436 uq = uq->b_forw; 437 } while (uq != cq->b_forw); 438 } 439 440 /* 441 * Initiate seeks for all drives off-cylinder. 442 */ 443 vdload_seeks(ci, uq) 444 register ctlr_tab *ci; 445 register struct buf *uq; 446 { 447 register int unit, slave, nseeks; 448 register fmt_dcb *dcb; 449 register struct buf *bp; 450 register struct buf *start_queue = uq; 451 452 nseeks = 0; 453 do { 454 bp = uq->av_forw; 455 if (bp != NULL) { 456 unit = VDUNIT(bp->b_dev); 457 slave = vddinfo[unit]->ui_slave; 458 if (ci->off_cylinder & (1 << slave)) { 459 ci->off_cylinder &= ~(1 << slave); 460 if (ci->cur_cyl[slave] != bp->b_cylin) { 461 ci->cur_cyl[slave] = bp->b_cylin; 462 dk_seek[unit]++; 463 } 464 ci->cur_trk[slave] = bp->b_daddr&0xff; 465 dcb = &ci->seek_dcb[nseeks++]; 466 dcb->opcode = SEEK; 467 dcb->intflg = NOINT | INT_PBA; 468 dcb->operrsta = 0; 469 dcb->devselect = (char)slave; 470 dcb->trailcnt = (char)1; 471 dcb->trail.sktrail.skaddr.cylinder = 472 bp->b_cylin; 473 dcb->trail.sktrail.skaddr.track = 474 bp->b_daddr & 0xff; 475 dcb->trail.sktrail.skaddr.sector = 0; 476 } 477 } 478 uq = uq->b_forw; 479 } while (uq != start_queue && nseeks < 4); 480 return (nseeks); 481 } 482 483 extern vd_int_timeout(); 484 /* 485 * Execute the next command on the unit queue uq. 486 */ 487 vdexecute(controller_info, uq) 488 register struct vba_ctlr *controller_info; 489 register struct buf *uq; 490 { 491 register struct buf *bp = uq->av_forw; 492 register int ctlr = controller_info->um_ctlr; 493 register ctlr_tab *ci = &vdctlr_info[ctlr]; 494 register int unit = VDUNIT(bp->b_dev); 495 register int slave = vddinfo[unit]->ui_slave; 496 register fmt_mdcb *mdcb = &ci->ctlr_mdcb; 497 register fmt_dcb *dcb = &ci->ctlr_dcb; 498 499 /* 500 * If there are overlapped seeks to perform, shuffle 501 * them to the front of the queue and get them started 502 * before any data transfers (to get some parallelism). 503 */ 504 if ((ci->off_cylinder & ~(1<<slave)) && ci->overlap_seeks) { 505 register int i, nseeks; 506 507 /* setup seek requests in seek-q */ 508 nseeks = vdload_seeks(ci, uq); 509 /* place at the front of the master q */ 510 mdcb->firstdcb = (fmt_dcb *)PHYS(&ci->seek_dcb[0]); 511 /* shuffle any remaining seeks up in the seek-q */ 512 for (i = 1; i < nseeks; i++) 513 ci->seek_dcb[i-1].nxtdcb = 514 (fmt_dcb *)PHYS(&ci->seek_dcb[i]); 515 ci->seek_dcb[nseeks-1].nxtdcb = (fmt_dcb *)PHYS(dcb); 516 } else { 517 if (bp->b_cylin != ci->cur_cyl[slave]) { 518 ci->cur_cyl[slave] = bp->b_cylin; 519 dk_seek[unit]++; 520 } 521 ci->cur_trk[slave] = bp->b_daddr & 0xff; 522 ci->off_cylinder = 0; 523 mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 524 } 525 dcb->opcode = (bp->b_flags & B_READ) ? RD : WD; 526 dcb->intflg = INTDONE; 527 dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */ 528 dcb->operrsta = 0; 529 dcb->devselect = (char)slave; 530 dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long)); 531 dcb->trail.rwtrail.memadr = (char *) 532 vbastart(bp, ci->rawbuf, (long *)ci->map, ci->utl); 533 dcb->trail.rwtrail.wcount = (short)((bp->b_bcount+1) / sizeof (short)); 534 dcb->trail.rwtrail.disk.cylinder = bp->b_cylin; 535 dcb->trail.rwtrail.disk.track = bp->b_daddr & 0xff; 536 dcb->trail.rwtrail.disk.sector = bp->b_daddr >> 8; 537 mdcb->vddcstat = 0; 538 dk_wds[unit] += bp->b_bcount / 32; 539 ci->int_expected = 1; 540 timeout(vd_int_timeout, (caddr_t)ctlr, 20*60); 541 dk_busy |= 1 << unit; 542 #ifdef VDDCPERF 543 scope_out(1); 544 #endif 545 VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr), 546 (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 547 } 548 549 /* 550 * Watch for lost interrupts. 551 */ 552 vd_int_timeout(ctlr) 553 register int ctlr; 554 { 555 register ctlr_tab *ci = &vdctlr_info[ctlr]; 556 register fmt_dcb *dcb = &ci->ctlr_dcb; 557 558 uncache(&dcb->operrsta); 559 printf("vd%d: lost interupt, status %x", ctlr, dcb->operrsta); 560 if (ci->ctlr_type == SMD_ECTLR) { 561 uncache(&dcb->err_code); 562 printf(", error code %x", dcb->err_code); 563 } 564 printf("\n"); 565 if ((dcb->operrsta&DCBCMP) == 0) { 566 VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), ci->ctlr_type); 567 dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR; 568 } 569 vdintr(ctlr); 570 } 571 572 /* 573 * Handle a disk interrupt. 574 */ 575 vdintr(ctlr) 576 register int ctlr; 577 { 578 register ctlr_tab *ci; 579 register struct buf *cq, *uq, *bp; 580 register int slave, unit; 581 register fmt_mdcb *mdcb; 582 register fmt_dcb *dcb; 583 int code, s; 584 585 untimeout(vd_int_timeout, (caddr_t)ctlr); 586 #ifdef VDDCPERF 587 scope_out(2); 588 #endif 589 ci = &vdctlr_info[ctlr]; 590 if (!ci->int_expected) { 591 printf("vd%d: stray interrupt\n", ctlr); 592 return; 593 } 594 /* 595 * Take first request off controller's queue. 596 */ 597 cq = &vdminfo[ctlr]->um_tab; 598 uq = cq->b_forw; 599 bp = uq->av_forw; 600 unit = VDUNIT(bp->b_dev); 601 dk_busy &= ~(1 << unit); 602 dk_xfer[unit]++; 603 ci->int_expected = 0; 604 /* find associated control blocks */ 605 mdcb = &ci->ctlr_mdcb, uncache(&mdcb->intdcb); 606 dcb = &ci->ctlr_dcb, uncache(&dcb->operrsta); 607 if (ci->ctlr_type == SMD_ECTLR) 608 uncache(&dcb->err_code); 609 slave = uq->b_dev; 610 switch (code = vddecode_error(dcb)) { 611 612 case CTLR_ERROR: 613 case DRIVE_ERROR: 614 if (cq->b_errcnt >= 2) 615 vdhard_error(ci, bp, dcb); 616 if (code == CTLR_ERROR) 617 vdreset_ctlr((cdr *)vdminfo[ctlr]->um_addr, ctlr); 618 else 619 reset_drive((cdr *)vdminfo[ctlr]->um_addr, ctlr, 620 slave, 2); 621 if (cq->b_errcnt++ < 2) { /* retry error */ 622 cq->b_forw = uq->b_back; 623 vdstart(vdminfo[ctlr]); 624 return; 625 } 626 bp->b_resid = bp->b_bcount; 627 break; 628 629 case HARD_DATA_ERROR: 630 vdhard_error(ci, bp, dcb); 631 bp->b_resid = 0; 632 break; 633 634 case SOFT_DATA_ERROR: 635 vdsoft_error(ci, bp, dcb); 636 /* fall thru... */ 637 638 default: /* operation completed */ 639 bp->b_error = 0; 640 bp->b_resid = 0; 641 break; 642 } 643 vbadone(bp, ci->rawbuf, (long *)ci->map, ci->utl); 644 /* 645 * Take next request on this unit q, or, if none, 646 * the next request on the next active unit q. 647 */ 648 s = spl7(); 649 uq->av_forw = bp->av_forw; 650 if (uq->av_back != bp) { 651 register struct buf *next; 652 653 unit = VDUNIT(uq->av_forw->b_dev); 654 slave = vddinfo[unit]->ui_slave; 655 next = uq->av_forw; 656 if (next->b_cylin != ci->cur_cyl[slave] || 657 (next->b_daddr & 0xff) != ci->cur_trk[slave]) 658 ci->off_cylinder |= 1 << slave; 659 } else 660 uq->av_back = NULL; 661 splx(s); 662 /* reset controller state */ 663 cq->b_errcnt = 0; 664 cq->b_active--; 665 #ifdef VDDCPERF 666 scope_out(3); 667 #endif 668 if (bp->b_flags & B_ERROR) 669 bp->b_error = EIO; 670 iodone(bp); 671 vdstart(vdminfo[ctlr]); 672 } 673 674 /* 675 * Convert controller status to internal operation/error code. 676 */ 677 vddecode_error(dcb) 678 register fmt_dcb *dcb; 679 { 680 681 if (dcb->operrsta & HRDERR) { 682 if (dcb->operrsta & (HCRCERR | HCMPERR | UCDATERR | WPTERR | 683 DSEEKERR | NOTCYLERR |DRVNRDY | INVDADR)) 684 return (DRIVE_ERROR); 685 if (dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM)) 686 return (CTLR_ERROR); 687 return (HARD_DATA_ERROR); 688 } 689 if (dcb->operrsta & SFTERR) 690 return (SOFT_DATA_ERROR); 691 return (0); 692 } 693 694 /* 695 * Report a hard error. 696 */ 697 vdhard_error(ci, bp, dcb) 698 ctlr_tab *ci; 699 register struct buf *bp; 700 register fmt_dcb *dcb; 701 { 702 unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)]; 703 704 bp->b_flags |= B_ERROR; 705 harderr(bp, ui->info.type_name); 706 printf("status %x", dcb->operrsta); 707 if (ci->ctlr_type == SMD_ECTLR) 708 printf(" ecode %x", dcb->err_code); 709 printf("\n"); 710 } 711 712 /* 713 * Report a soft error. 714 */ 715 vdsoft_error(ci, bp, dcb) 716 ctlr_tab *ci; 717 register struct buf *bp; 718 register fmt_dcb *dcb; 719 { 720 unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)]; 721 722 printf("%s%d%c: soft error sn%d status %x", ui->info.type_name, 723 minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno, 724 dcb->operrsta); 725 if (ci->ctlr_type == SMD_ECTLR) 726 printf(" ecode %x", dcb->err_code); 727 printf("\n"); 728 } 729 730 /*ARGSUSED*/ 731 vdopen(dev, flag) 732 dev_t dev; 733 int flag; 734 { 735 register unit = VDUNIT(dev); 736 register struct vba_device *vi = vddinfo[unit]; 737 738 if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv) 739 return (ENXIO); 740 if (vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0) 741 return (ENXIO); 742 return (0); 743 } 744 745 vdread(dev, uio) 746 dev_t dev; 747 struct uio *uio; 748 { 749 register int unit = VDUNIT(dev); 750 register unit_tab *ui = &vdunit_info[unit]; 751 752 if (unit >= NFSD) 753 return (ENXIO); 754 return (physio(vdstrategy, &ui->raw_q_element, dev, B_READ, 755 minphys, uio)); 756 } 757 758 vdwrite(dev, uio) 759 dev_t dev; 760 struct uio *uio; 761 { 762 register int unit = VDUNIT(dev); 763 register unit_tab *ui = &vdunit_info[unit]; 764 765 if (unit >= NFSD) 766 return (ENXIO); 767 return (physio(vdstrategy, &ui->raw_q_element, dev, B_WRITE, 768 minphys, uio)); 769 } 770 771 /* 772 * Crash dump. 773 */ 774 vddump(dev) 775 dev_t dev; 776 { 777 register int unit = VDUNIT(dev); 778 register unit_tab *ui = &vdunit_info[unit]; 779 register fs_tab *fs = &ui->info; 780 register int ctlr = vddinfo[unit]->ui_ctlr; 781 register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr]; 782 register int filsys = FILSYS(dev); 783 register cdr *addr = (cdr *)(vba_vdctlr_info->um_addr); 784 register int cur_blk, blkcount, blocks; 785 caddr_t memaddr; 786 787 vdreset_ctlr(addr, ctlr); 788 blkcount = maxfree - 2; /* In 1k byte pages */ 789 if (dumplo + blkcount > fs->partition[filsys].par_len) { 790 blkcount = fs->partition[filsys].par_len - dumplo; 791 printf("vd%d: Dump truncated to %dMB\n", unit, blkcount/1024); 792 } 793 cur_blk = fs->partition[filsys].par_start + dumplo; 794 memaddr = 0; 795 while (blkcount > 0) { 796 blocks = MIN(blkcount, DUMPSIZE); 797 if (!vdwrite_block(addr, ctlr, unit, memaddr, cur_blk, blocks)) 798 return (EIO); 799 blkcount -= blocks; 800 memaddr += blocks * NBPG; 801 cur_blk += blocks; 802 } 803 return (0); 804 } 805 806 /* 807 * Write a block to disk during a crash dump. 808 */ 809 vdwrite_block(caddr, ctlr, unit, addr, block, blocks) 810 register cdr *caddr; 811 register int ctlr, unit; 812 register caddr_t addr; 813 register int block, blocks; 814 { 815 register fmt_mdcb *mdcb = &vdctlr_info[ctlr].ctlr_mdcb; 816 register fmt_dcb *dcb = &vdctlr_info[ctlr].ctlr_dcb; 817 register unit_tab *ui = &vdunit_info[unit]; 818 register fs_tab *fs = &ui->info; 819 820 block *= (int)ui->sec_per_blk; 821 blocks *= (int)ui->sec_per_blk; 822 mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 823 dcb->intflg = NOINT; 824 dcb->opcode = WD; 825 dcb->operrsta = 0; 826 dcb->devselect = (char)(vddinfo[unit])->ui_slave; 827 dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long)); 828 dcb->trail.rwtrail.memadr = addr; 829 dcb->trail.rwtrail.wcount = (short) 830 ((blocks * fs->secsize)/ sizeof (short)); 831 dcb->trail.rwtrail.disk.cylinder = (short)(block / ui->sec_per_cyl); 832 dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak); 833 dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec); 834 VDDC_ATTENTION(caddr, (fmt_mdcb *)(PHYS(mdcb)), 835 vdctlr_info[ctlr].ctlr_type); 836 POLLTILLDONE(caddr, dcb, 5, vdctlr_info[ctlr].ctlr_type); 837 if (vdtimeout <= 0) { 838 printf(" during dump\n"); 839 return (0); 840 } 841 if (dcb->operrsta & HRDERR) { 842 printf("vd%d: hard error, status %x\n", unit, dcb->operrsta); 843 return (0); 844 } 845 return (1); 846 } 847 848 vdsize(dev) 849 dev_t dev; 850 { 851 struct vba_device *vi = vddinfo[VDUNIT(dev)]; 852 853 if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv) 854 return (-1); 855 return (vdunit_info[VDUNIT(dev)].info.partition[FILSYS(dev)].par_len); 856 } 857 858 /* 859 * Perform a controller reset. 860 */ 861 vdreset_ctlr(addr, ctlr) 862 register cdr *addr; 863 register int ctlr; 864 { 865 register struct buf *cq = &vdminfo[ctlr]->um_tab; 866 register struct buf *uq = cq->b_forw; 867 register ctlr_tab *ci = &vdctlr_info[ctlr]; 868 869 VDDC_RESET(addr, ci->ctlr_type); 870 ci->ctlr_started = 0; 871 if (ci->ctlr_type == SMD_ECTLR) { 872 addr->cdr_csr = 0; 873 addr->mdcb_tcf = AM_ENPDA; 874 addr->dcb_tcf = AM_ENPDA; 875 addr->trail_tcf = AM_ENPDA; 876 addr->data_tcf = AM_ENPDA; 877 addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 878 CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 879 } 880 if (vdnotrailer(addr, ctlr, 0, INIT, 10) & HRDERR) { 881 printf("failed to init\n"); 882 return (0); 883 } 884 if (vdnotrailer(addr, ctlr, 0, DIAG, 10) & HRDERR) { 885 printf("diagnostic error\n"); 886 return (0); 887 } 888 /* reset all units attached to controller */ 889 uq = cq->b_forw; 890 do { 891 reset_drive(addr, ctlr, uq->b_dev, 0); 892 uq = uq->b_forw; 893 } while (uq != cq->b_forw); 894 return (1); 895 } 896 897 /* 898 * Perform a reset on a drive. 899 */ 900 reset_drive(addr, ctlr, slave, start) 901 register cdr *addr; 902 register int ctlr, slave, start; 903 { 904 register int type = vdctlr_info[ctlr].unit_type[slave]; 905 906 if (type == UNKNOWN) 907 return; 908 if (!vdconfigure_drive(addr, ctlr, slave, type, start)) 909 printf("vd%d: drive %d: couldn't reset\n", ctlr, slave); 910 } 911 912 #ifdef notdef 913 /* 914 * Dump the mdcb and DCB for diagnostic purposes. 915 */ 916 vdprintdcb(lp) 917 register long *lp; 918 { 919 register int i, dcb, tc; 920 921 for (dcb = 0; lp; lp = (long *)(*lp), dcb++) { 922 lp = (long *)((long)lp | 0xc0000000); 923 printf("\nDump of dcb%d@%x:", dcb, lp); 924 for (i = 0, tc = lp[3] & 0xff; i < tc+7; i++) 925 printf(" %lx", lp[i]); 926 printf("\n"); 927 } 928 DELAY(1750000); 929 } 930 #endif 931 #endif 932