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