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