1*30370Skarels /* vd.c 1.13 87/01/11 */ 224004Ssam 329564Ssam #include "dk.h" 424004Ssam #if NVD > 0 524004Ssam /* 629564Ssam * VDDC - Versabus SMD/SMDE driver. 725675Ssam */ 825877Ssam #ifdef VDDCPERF 925877Ssam #define DOSCOPE 1025877Ssam #endif 1125877Ssam 1225675Ssam #include "param.h" 1325675Ssam #include "buf.h" 1425675Ssam #include "cmap.h" 1525675Ssam #include "conf.h" 1625675Ssam #include "dir.h" 1729564Ssam #include "dkstat.h" 1825675Ssam #include "map.h" 1925675Ssam #include "systm.h" 2025675Ssam #include "user.h" 2125675Ssam #include "vmmac.h" 2225675Ssam #include "proc.h" 2325675Ssam #include "uio.h" 24*30370Skarels #include "syslog.h" 25*30370Skarels #include "kernel.h" 2624004Ssam 2729951Skarels #include "../tahoe/cpu.h" 2829951Skarels #include "../tahoe/mtpr.h" 2929951Skarels #include "../tahoe/pte.h" 3029951Skarels 3125675Ssam #include "../tahoevba/vbavar.h" 3225675Ssam #define VDGENDATA 3325928Ssam #include "../tahoevba/vdreg.h" 3425675Ssam #undef VDGENDATA 3525877Ssam #include "../tahoevba/scope.h" 3624004Ssam 3725925Ssam #define VDMAXIO (MAXBPTE*NBPG) 3825675Ssam #define DUMPSIZE 64 /* controller limit */ 3924004Ssam 4024004Ssam #define VDUNIT(x) (minor(x) >> 3) 4125675Ssam #define FILSYS(x) (minor(x) & 0x07) 4225675Ssam #define PHYS(x) (vtoph((struct proc *)0, (unsigned)(x))) 4324004Ssam 4425675Ssam #define CTLR_ERROR 1 4525675Ssam #define DRIVE_ERROR 2 4625675Ssam #define HARD_DATA_ERROR 3 4725675Ssam #define SOFT_DATA_ERROR 4 4829921Skarels #define WRITE_PROTECT 5 4924004Ssam 5025675Ssam #define b_cylin b_resid 5125675Ssam #define b_daddr b_error 5224004Ssam 5324004Ssam struct vba_ctlr *vdminfo[NVD]; 5429564Ssam struct vba_device *vddinfo[NDK]; 5525675Ssam int vdprobe(), vdslave(), vdattach(), vddgo(); 5625675Ssam struct vba_driver vddriver = 5729564Ssam { vdprobe, vdslave, vdattach, vddgo, vddcaddr, "dk", 5825675Ssam vddinfo, "vd", vdminfo }; 5924004Ssam 6024004Ssam /* 6125675Ssam * Per-drive state. 6225675Ssam */ 6325675Ssam typedef struct { 6425675Ssam struct buf raw_q_element; 6525675Ssam short sec_per_blk; 6625675Ssam short sec_per_cyl; 6725675Ssam char status; 6825675Ssam struct buf xfer_queue; 6925675Ssam int drive_type; 7025675Ssam fs_tab info; 7125675Ssam } unit_tab; 7224004Ssam 7324004Ssam /* 7425675Ssam * Per-controller state. 7525675Ssam */ 7625675Ssam typedef struct { 7725675Ssam char ctlr_type; /* controller type */ 7825925Ssam struct pte *map; /* i/o page map */ 7925925Ssam caddr_t utl; /* mapped i/o space */ 8025675Ssam u_int cur_slave:8; /* last active unit number */ 8129921Skarels u_int int_expected:1; /* expect an interrupt */ 8225675Ssam u_int ctlr_started:1; /* start command was issued */ 8325675Ssam u_int overlap_seeks:1;/* should overlap seeks */ 8425925Ssam u_int initdone:1; /* controller initialization completed */ 8525675Ssam u_int off_cylinder:16;/* off cylinder bit map */ 8625675Ssam u_int unit_type[16]; /* slave types */ 8725675Ssam u_int cur_cyl[16]; /* cylinder last selected */ 8825675Ssam long cur_trk[16]; /* track last selected */ 8925675Ssam fmt_mdcb ctlr_mdcb; /* controller mdcb */ 9025675Ssam fmt_dcb ctlr_dcb; /* r/w dcb */ 9125675Ssam fmt_dcb seek_dcb[4]; /* dcbs for overlapped seeks */ 9225950Ssam caddr_t rawbuf; /* buffer for raw+swap i/o */ 9325675Ssam } ctlr_tab; 9424004Ssam 9525925Ssam ctlr_tab vdctlr_info[NVD]; 9629564Ssam unit_tab vdunit_info[NDK]; 9724004Ssam 9824004Ssam /* 9925675Ssam * See if the controller is really there; if so, initialize it. 10025675Ssam */ 10125857Ssam vdprobe(reg, vm) 10225857Ssam caddr_t reg; 10325857Ssam struct vba_ctlr *vm; 10425675Ssam { 10525857Ssam register br, cvec; /* must be r12, r11 */ 10625925Ssam register cdr *addr = (cdr *)reg; 10725925Ssam register ctlr_tab *ci; 10825925Ssam int i; 10925857Ssam 110*30370Skarels #ifdef lint 111*30370Skarels br = 0; cvec = br; br = cvec; 112*30370Skarels vdintr(0); 113*30370Skarels #endif 11425857Ssam if (badaddr((caddr_t)reg, 2)) 11525675Ssam return (0); 11625925Ssam ci = &vdctlr_info[vm->um_ctlr]; 11725925Ssam addr->cdr_reset = 0xffffffff; 11825675Ssam DELAY(1000000); 11925925Ssam if (addr->cdr_reset != (unsigned)0xffffffff) { 12025925Ssam ci->ctlr_type = SMDCTLR; 12125925Ssam ci->overlap_seeks = 0; 12225675Ssam DELAY(1000000); 12325675Ssam } else { 12425925Ssam ci->overlap_seeks = 1; 12525925Ssam ci->ctlr_type = SMD_ECTLR; 12625925Ssam addr->cdr_reserved = 0x0; 12725675Ssam DELAY(3000000); 12825925Ssam addr->cdr_csr = 0; 12925925Ssam addr->mdcb_tcf = AM_ENPDA; 13025925Ssam addr->dcb_tcf = AM_ENPDA; 13125925Ssam addr->trail_tcf = AM_ENPDA; 13225925Ssam addr->data_tcf = AM_ENPDA; 13329921Skarels addr->cdr_ccf = CCF_SEN | CCF_DER | CCF_STS | 13429921Skarels XMD_32BIT | BSZ_16WRD | 13525925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 13625675Ssam } 13725925Ssam /* 13825950Ssam * Allocate page tables and i/o buffer. 13925925Ssam */ 14025925Ssam vbmapalloc(btoc(VDMAXIO)+1, &ci->map, &ci->utl); 14125950Ssam ci->rawbuf = calloc(VDMAXIO); 14225925Ssam /* 14325925Ssam * Initialize all the drives to be of an unknown type. 14425925Ssam */ 14525925Ssam for (i = 0; i < 15; i++) 14625925Ssam ci->unit_type[i] = UNKNOWN; 14725857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 14825925Ssam return (sizeof (*addr)); 14925675Ssam } 15024004Ssam 15124004Ssam /* 15225675Ssam * See if a drive is really there 15325675Ssam * Try to reset/configure the drive, then test its status. 15425675Ssam */ 15525675Ssam vdslave(vi, addr) 15625675Ssam register struct vba_device *vi; 15725675Ssam register cdr *addr; 15825675Ssam { 15925675Ssam register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr]; 16025675Ssam register unit_tab *ui = &vdunit_info[vi->ui_unit]; 16125675Ssam register fmt_mdcb *mdcb = &ci->ctlr_mdcb; 16225675Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 16325675Ssam register int type; 16424004Ssam 16525925Ssam if (!ci->initdone) { 16625925Ssam printf("vd%d: %s controller\n", vi->ui_ctlr, 167*30370Skarels ci->ctlr_type == SMDCTLR ? "VDDC" : "SMDE"); 16825925Ssam if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, INIT, 10) & 16925925Ssam HRDERR) { 17025925Ssam printf("vd%d: init error\n", vi->ui_ctlr); 17125675Ssam return (0); 17225675Ssam } 17325925Ssam if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, DIAG, 10) & 17425925Ssam HRDERR) { 17525925Ssam printf("vd%d: diagnostic error\n", vi->ui_ctlr); 17625675Ssam return (0); 17725675Ssam } 17825925Ssam ci->initdone = 1; 17925675Ssam } 18025675Ssam /* 18125675Ssam * Seek on all drive types starting from the largest one. 18225675Ssam * a successful seek to the last sector/cylinder/track verifies 18325675Ssam * the drive type connected to this port. 18425675Ssam */ 18525675Ssam for (type = 0; type < nvddrv; type++) { 18625675Ssam /* XXX */ 18725675Ssam if (ci->ctlr_type == SMDCTLR && vdst[type].nsec != 32) 18825675Ssam continue; 18925675Ssam /* XXX */ 190*30370Skarels if (!vdconfigure_drive(addr, vi->ui_ctlr, vi->ui_slave, type)) 19125675Ssam return (0); 19225675Ssam dcb->opcode = (short)RD; 19325675Ssam dcb->intflg = NOINT; 19425675Ssam dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */ 19525675Ssam dcb->operrsta = 0; 19625675Ssam dcb->devselect = (char)(vi->ui_slave); 19725675Ssam dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long)); 19825675Ssam dcb->trail.rwtrail.memadr = (char *)PHYS(ci->rawbuf); 19925675Ssam dcb->trail.rwtrail.wcount = vdst[type].secsize/sizeof(short); 20025675Ssam dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2; 20125675Ssam dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1; 20225675Ssam dcb->trail.rwtrail.disk.sector = vdst[type].nsec - 1; 20325675Ssam mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 20425675Ssam mdcb->vddcstat = 0; 20525675Ssam VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 20625925Ssam if (!vdpoll(ci, addr, 60)) 20725675Ssam printf(" during probe\n"); 20825675Ssam if ((dcb->operrsta&HRDERR) == 0) 20925675Ssam break; 21025675Ssam } 21125675Ssam if (type >= nvddrv) { 21225675Ssam /* 21325675Ssam * If reached here, a drive which is not defined in the 21429921Skarels * 'vdst' tables is connected. Cannot set its type. 21525675Ssam */ 21629564Ssam printf("dk%d: unknown drive type\n", vi->ui_unit); 21725675Ssam return (0); 21825675Ssam } 21925675Ssam ui->drive_type = type; 22025675Ssam ui->info = vdst[type]; 22125675Ssam ui->sec_per_blk = DEV_BSIZE / ui->info.secsize; 22225675Ssam vi->ui_type = type; 22325675Ssam vi->ui_dk = 1; 22425675Ssam return (1); 22524004Ssam } 22624004Ssam 227*30370Skarels vdconfigure_drive(addr, ctlr, slave, type) 22825675Ssam register cdr *addr; 229*30370Skarels int ctlr, slave, type; 23024004Ssam { 23125675Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 23225675Ssam 23325675Ssam ci->ctlr_dcb.opcode = RSTCFG; /* command */ 23425675Ssam ci->ctlr_dcb.intflg = NOINT; 23525675Ssam ci->ctlr_dcb.nxtdcb = (fmt_dcb *)0; /* end of chain */ 23625675Ssam ci->ctlr_dcb.operrsta = 0; 23725675Ssam ci->ctlr_dcb.devselect = (char)slave; 23825675Ssam ci->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl; 23925675Ssam ci->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak; 24025675Ssam if (ci->ctlr_type == SMD_ECTLR) { 24129921Skarels ci->ctlr_dcb.trailcnt = (char)5; 24225675Ssam ci->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec; 24325675Ssam ci->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip; 24429921Skarels ci->ctlr_dcb.trail.rstrail.recovery = 0x18f; 24525675Ssam } else 24625675Ssam ci->ctlr_dcb.trailcnt = (char)2; 24725675Ssam ci->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&ci->ctlr_dcb)); 24825675Ssam ci->ctlr_mdcb.vddcstat = 0; 24925675Ssam VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(&ci->ctlr_mdcb)), ci->ctlr_type); 25025925Ssam if (!vdpoll(ci, addr, 5)) { 25125675Ssam printf(" during config\n"); 25225675Ssam return (0); 25325675Ssam } 25425675Ssam if (ci->ctlr_dcb.operrsta & HRDERR) { 255*30370Skarels if (ci->ctlr_type == SMD_ECTLR && 256*30370Skarels (addr->cdr_status[slave] & STA_US) == 0) /* not selected */ 257*30370Skarels return (0); 25825675Ssam if ((ci->ctlr_dcb.operrsta & (NOTCYLERR|DRVNRDY)) == 0) 25925675Ssam printf("vd%d: drive %d: config error\n", ctlr, slave); 260*30370Skarels else if (vdctlr_info[ctlr].ctlr_started == 0) 261*30370Skarels return (vdstart_drives(addr, ctlr) && 262*30370Skarels vdconfigure_drive(addr, ctlr, slave, type)); 26325675Ssam return (0); 26425675Ssam } 26525675Ssam return (1); 26624004Ssam } 26724004Ssam 268*30370Skarels vdstart_drives(addr, ctlr) 26925675Ssam cdr *addr; 270*30370Skarels register int ctlr; 27124004Ssam { 27225675Ssam int error = 0; 27324004Ssam 274*30370Skarels if (vdctlr_info[ctlr].ctlr_started == 0) { 275*30370Skarels printf("vd%d: starting drives, wait ... ", ctlr); 276*30370Skarels vdctlr_info[ctlr].ctlr_started = 1; 277*30370Skarels error = (vdnotrailer(addr, ctlr, 0, VDSTART, 10) & HRDERR); 278*30370Skarels DELAY(62000000); 279*30370Skarels printf("\n"); 28024004Ssam } 28125675Ssam return (error == 0); 28225675Ssam } 28324004Ssam 284*30370Skarels vdnotrailer(addr, ctlr, unit, function, t) 28525675Ssam register cdr *addr; 286*30370Skarels int ctlr, unit, function, t; 28724004Ssam { 28825925Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 28925925Ssam fmt_mdcb *mdcb = &ci->ctlr_mdcb; 29025925Ssam fmt_dcb *dcb = &ci->ctlr_dcb; 29124004Ssam 29225675Ssam dcb->opcode = function; /* command */ 29324004Ssam dcb->intflg = NOINT; 29425675Ssam dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */ 29525675Ssam dcb->operrsta = 0; 29625675Ssam dcb->devselect = (char)unit; 29724004Ssam dcb->trailcnt = (char)0; 29825675Ssam mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 29924004Ssam mdcb->vddcstat = 0; 30025925Ssam VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 301*30370Skarels if (!vdpoll(ci, addr, t)) { 30225675Ssam printf(" during init\n"); 30325675Ssam return (DCBCMP|ANYERR|HRDERR|OPABRT); 30424004Ssam } 30525675Ssam return (dcb->operrsta); 30625675Ssam } 30724004Ssam 30825675Ssam vdattach(vi) 30925675Ssam register struct vba_device *vi; 31025675Ssam { 31125675Ssam register unit_tab *ui = &vdunit_info[vi->ui_unit]; 31225675Ssam register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr]; 31325675Ssam register struct buf *cq = &vi->ui_mi->um_tab; 31425675Ssam register struct buf *uq = cq->b_forw; 31525675Ssam register struct buf *start_queue = uq; 31625675Ssam register fs_tab *fs = &ui->info; 31725675Ssam 31825675Ssam ui->info = vdst[vi->ui_type]; 31925675Ssam ui->sec_per_blk = DEV_BSIZE / ui->info.secsize; 32025675Ssam ui->sec_per_cyl = ui->info.nsec * ui->info.ntrak; 32125675Ssam ui->xfer_queue.b_dev = vi->ui_slave; 32225675Ssam ci->unit_type[vi->ui_slave] = vi->ui_type; 32325675Ssam /* load unit into controller's active unit list */ 32425675Ssam if (uq == NULL) { 32525675Ssam cq->b_forw = &ui->xfer_queue; 32625675Ssam ui->xfer_queue.b_forw = &ui->xfer_queue; 32725675Ssam ui->xfer_queue.b_back = &ui->xfer_queue; 32825675Ssam } else { 32925675Ssam while (uq->b_forw != start_queue) 33025675Ssam uq = uq->b_forw; 33125675Ssam ui->xfer_queue.b_forw = start_queue; 33225675Ssam ui->xfer_queue.b_back = uq; 33325675Ssam uq->b_forw = &ui->xfer_queue; 33425675Ssam start_queue->b_back = &ui->xfer_queue; 33525675Ssam } 336*30370Skarels printf(": %s <ntrak %d, ncyl %d, nsec %d>", 337*30370Skarels fs->type_name, ui->info.ntrak, ui->info.ncyl, ui->info.nsec); 33824004Ssam /* 33925675Ssam * (60 / rpm) / (number of sectors per track * (bytes per sector / 2)) 34024004Ssam */ 34125675Ssam dk_mspw[vi->ui_unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize); 34224004Ssam } 34324004Ssam 34425675Ssam /*ARGSUSED*/ 34525675Ssam vddgo(um) 34625675Ssam struct vba_ctlr *um; 34724004Ssam { 34824004Ssam 34924004Ssam } 35024004Ssam 35124004Ssam vdstrategy(bp) 35225675Ssam register struct buf *bp; 35324004Ssam { 35425675Ssam register int unit = VDUNIT(bp->b_dev); 35525675Ssam register struct vba_device *vi = vddinfo[unit]; 35625675Ssam register par_tab *par; 35725675Ssam register unit_tab *ui; 35825675Ssam register fs_tab *fs; 35925675Ssam register int blks, bn, s; 36024004Ssam 36129954Skarels if (bp->b_bcount == 0 || vi == 0 || vi->ui_alive == 0) { 36229954Skarels bp->b_error = ENXIO; 36325675Ssam goto bad; 36429954Skarels } 36525675Ssam ui = &vdunit_info[unit]; 36625675Ssam fs = &ui->info; 36725675Ssam par = &fs->partition[FILSYS(bp->b_dev)]; 36825675Ssam blks = (bp->b_bcount + DEV_BSIZE-1) >> DEV_BSHIFT; 36929954Skarels if ((unsigned) bp->b_blkno + blks > par->par_len) { 37029954Skarels if (bp->b_blkno == par->par_len) { 37129954Skarels bp->b_resid = bp->b_bcount; 37229954Skarels goto done; 37329954Skarels } 37425675Ssam blks = par->par_len - bp->b_blkno; 37529954Skarels if (blks <= 0) { 37629954Skarels bp->b_error = EINVAL; 37725675Ssam goto bad; 37829954Skarels } 37925675Ssam bp->b_bcount = blks * DEV_BSIZE; 38025675Ssam } 38125675Ssam bn = bp->b_blkno + par->par_start; 38225675Ssam bn *= ui->sec_per_blk; 38325675Ssam bp->b_daddr = (bn / fs->nsec) % fs->ntrak; 38425675Ssam bp->b_cylin = bn / ui->sec_per_cyl; 38525675Ssam vbasetup(bp, ui->info.secsize); 38625675Ssam s = spl7(); 38725675Ssam if (ui->xfer_queue.av_forw == NULL) { 38825675Ssam register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr]; 38925675Ssam int slave = vi->ui_slave; 39024004Ssam 39125675Ssam if (bp->b_cylin != ci->cur_cyl[slave] || 39225675Ssam bp->b_daddr != ci->cur_trk[slave]) 39325675Ssam ci->off_cylinder |= 1 << slave; 39424004Ssam } 39525675Ssam bp->b_daddr |= (bn % fs->nsec) << 8; 39625675Ssam disksort(&ui->xfer_queue, bp); 39725675Ssam if (!vddinfo[unit]->ui_mi->um_tab.b_active++) { 39825675Ssam splx(s); 39925675Ssam vdstart(vddinfo[unit]->ui_mi); 40025675Ssam } else 40125675Ssam splx(s); 40224004Ssam return; 40325675Ssam bad: 40429954Skarels bp->b_flags |= B_ERROR; 40529954Skarels done: 40624004Ssam iodone(bp); 40724004Ssam } 40824004Ssam 40924004Ssam /* 41024004Ssam * Start up a transfer on a drive. 41124004Ssam */ 41225675Ssam vdstart(ci) 41325675Ssam register struct vba_ctlr *ci; 41424004Ssam { 41525675Ssam register struct buf *cq = &ci->um_tab; 41625675Ssam register struct buf *uq = cq->b_forw; 41724004Ssam 41825675Ssam /* search for next ready unit */ 41925675Ssam cq->b_forw = cq->b_forw->b_forw; 42025675Ssam uq = cq->b_forw; 42125675Ssam do { 42225675Ssam if (uq->av_forw != NULL) { 42325675Ssam cq->b_forw = uq; 42425675Ssam vdexecute(ci, uq); 42525675Ssam return; 42625675Ssam } 42725675Ssam uq = uq->b_forw; 42825675Ssam } while (uq != cq->b_forw); 42925675Ssam } 43025675Ssam 43125675Ssam /* 43225675Ssam * Initiate seeks for all drives off-cylinder. 43325675Ssam */ 43425675Ssam vdload_seeks(ci, uq) 43525675Ssam register ctlr_tab *ci; 43625675Ssam register struct buf *uq; 43725675Ssam { 43825675Ssam register int unit, slave, nseeks; 43925675Ssam register fmt_dcb *dcb; 44025675Ssam register struct buf *bp; 44125675Ssam register struct buf *start_queue = uq; 44225675Ssam 44325675Ssam nseeks = 0; 44425675Ssam do { 44525675Ssam bp = uq->av_forw; 44625675Ssam if (bp != NULL) { 44725675Ssam unit = VDUNIT(bp->b_dev); 44825675Ssam slave = vddinfo[unit]->ui_slave; 44925675Ssam if (ci->off_cylinder & (1 << slave)) { 45025675Ssam ci->off_cylinder &= ~(1 << slave); 45125675Ssam if (ci->cur_cyl[slave] != bp->b_cylin) { 45225675Ssam ci->cur_cyl[slave] = bp->b_cylin; 45325675Ssam dk_seek[unit]++; 45425675Ssam } 45525675Ssam ci->cur_trk[slave] = bp->b_daddr&0xff; 45625675Ssam dcb = &ci->seek_dcb[nseeks++]; 45725675Ssam dcb->opcode = SEEK; 45825675Ssam dcb->intflg = NOINT | INT_PBA; 45925675Ssam dcb->operrsta = 0; 46025675Ssam dcb->devselect = (char)slave; 46125675Ssam dcb->trailcnt = (char)1; 46225675Ssam dcb->trail.sktrail.skaddr.cylinder = 46325675Ssam bp->b_cylin; 46425675Ssam dcb->trail.sktrail.skaddr.track = 46525675Ssam bp->b_daddr & 0xff; 46625675Ssam dcb->trail.sktrail.skaddr.sector = 0; 46725675Ssam } 46825675Ssam } 46925675Ssam uq = uq->b_forw; 47025675Ssam } while (uq != start_queue && nseeks < 4); 47125675Ssam return (nseeks); 47225675Ssam } 47325675Ssam 47425675Ssam extern vd_int_timeout(); 47525675Ssam /* 47625675Ssam * Execute the next command on the unit queue uq. 47725675Ssam */ 47825675Ssam vdexecute(controller_info, uq) 47925675Ssam register struct vba_ctlr *controller_info; 48025675Ssam register struct buf *uq; 48125675Ssam { 48225675Ssam register struct buf *bp = uq->av_forw; 48325675Ssam register int ctlr = controller_info->um_ctlr; 48425675Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 48525675Ssam register int unit = VDUNIT(bp->b_dev); 48625675Ssam register int slave = vddinfo[unit]->ui_slave; 48725675Ssam register fmt_mdcb *mdcb = &ci->ctlr_mdcb; 48825675Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 48925675Ssam 49024004Ssam /* 49125675Ssam * If there are overlapped seeks to perform, shuffle 49225675Ssam * them to the front of the queue and get them started 49325675Ssam * before any data transfers (to get some parallelism). 49424004Ssam */ 49525675Ssam if ((ci->off_cylinder & ~(1<<slave)) && ci->overlap_seeks) { 49625675Ssam register int i, nseeks; 49725675Ssam 49825675Ssam /* setup seek requests in seek-q */ 49925675Ssam nseeks = vdload_seeks(ci, uq); 50025675Ssam /* place at the front of the master q */ 50125675Ssam mdcb->firstdcb = (fmt_dcb *)PHYS(&ci->seek_dcb[0]); 50225675Ssam /* shuffle any remaining seeks up in the seek-q */ 50325675Ssam for (i = 1; i < nseeks; i++) 50425675Ssam ci->seek_dcb[i-1].nxtdcb = 50525675Ssam (fmt_dcb *)PHYS(&ci->seek_dcb[i]); 50625675Ssam ci->seek_dcb[nseeks-1].nxtdcb = (fmt_dcb *)PHYS(dcb); 50725675Ssam } else { 50825675Ssam if (bp->b_cylin != ci->cur_cyl[slave]) { 50925675Ssam ci->cur_cyl[slave] = bp->b_cylin; 51025675Ssam dk_seek[unit]++; 51125675Ssam } 51225675Ssam ci->cur_trk[slave] = bp->b_daddr & 0xff; 51325675Ssam ci->off_cylinder = 0; 51425675Ssam mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 51524004Ssam } 51624004Ssam dcb->opcode = (bp->b_flags & B_READ) ? RD : WD; 51725675Ssam dcb->intflg = INTDONE; 51825675Ssam dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */ 51924004Ssam dcb->operrsta = 0; 52025675Ssam dcb->devselect = (char)slave; 52125675Ssam dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long)); 52225675Ssam dcb->trail.rwtrail.memadr = (char *) 52325675Ssam vbastart(bp, ci->rawbuf, (long *)ci->map, ci->utl); 52425675Ssam dcb->trail.rwtrail.wcount = (short)((bp->b_bcount+1) / sizeof (short)); 52525675Ssam dcb->trail.rwtrail.disk.cylinder = bp->b_cylin; 52625675Ssam dcb->trail.rwtrail.disk.track = bp->b_daddr & 0xff; 52725675Ssam dcb->trail.rwtrail.disk.sector = bp->b_daddr >> 8; 52825675Ssam mdcb->vddcstat = 0; 52925675Ssam dk_wds[unit] += bp->b_bcount / 32; 53025675Ssam ci->int_expected = 1; 531*30370Skarels timeout(vd_int_timeout, (caddr_t)ctlr, 20*hz); 53225675Ssam dk_busy |= 1 << unit; 53325675Ssam scope_out(1); 53425675Ssam VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr), 53525675Ssam (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 53625675Ssam } 53724004Ssam 53824004Ssam /* 53925675Ssam * Watch for lost interrupts. 54025675Ssam */ 54125675Ssam vd_int_timeout(ctlr) 54225675Ssam register int ctlr; 54325675Ssam { 54425675Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 54525675Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 54624004Ssam 54725675Ssam uncache(&dcb->operrsta); 54829921Skarels printf("vd%d: lost interrupt, status %b", ctlr, dcb->operrsta, ERRBITS); 54925675Ssam if (ci->ctlr_type == SMD_ECTLR) { 55025675Ssam uncache(&dcb->err_code); 55125675Ssam printf(", error code %x", dcb->err_code); 55224004Ssam } 55325675Ssam printf("\n"); 55425675Ssam if ((dcb->operrsta&DCBCMP) == 0) { 55525675Ssam VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), ci->ctlr_type); 55625675Ssam dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR; 55725675Ssam } 55825675Ssam vdintr(ctlr); 55924004Ssam } 56024004Ssam 56124004Ssam /* 56224004Ssam * Handle a disk interrupt. 56324004Ssam */ 56425675Ssam vdintr(ctlr) 56525675Ssam register int ctlr; 56624004Ssam { 56725675Ssam register ctlr_tab *ci; 56825675Ssam register struct buf *cq, *uq, *bp; 56925675Ssam register int slave, unit; 57025675Ssam register fmt_mdcb *mdcb; 57125675Ssam register fmt_dcb *dcb; 57225675Ssam int code, s; 57324004Ssam 57425675Ssam untimeout(vd_int_timeout, (caddr_t)ctlr); 57524004Ssam scope_out(2); 57625675Ssam ci = &vdctlr_info[ctlr]; 57725675Ssam if (!ci->int_expected) { 57825675Ssam printf("vd%d: stray interrupt\n", ctlr); 57924004Ssam return; 58024004Ssam } 58125675Ssam /* 58225675Ssam * Take first request off controller's queue. 58325675Ssam */ 58425675Ssam cq = &vdminfo[ctlr]->um_tab; 58525675Ssam uq = cq->b_forw; 58625675Ssam bp = uq->av_forw; 58724004Ssam unit = VDUNIT(bp->b_dev); 58825675Ssam dk_busy &= ~(1 << unit); 58925675Ssam dk_xfer[unit]++; 59025675Ssam ci->int_expected = 0; 59125675Ssam /* find associated control blocks */ 59225675Ssam mdcb = &ci->ctlr_mdcb, uncache(&mdcb->intdcb); 59325675Ssam dcb = &ci->ctlr_dcb, uncache(&dcb->operrsta); 59425675Ssam if (ci->ctlr_type == SMD_ECTLR) 59525675Ssam uncache(&dcb->err_code); 59625675Ssam slave = uq->b_dev; 59725675Ssam switch (code = vddecode_error(dcb)) { 59824004Ssam 59925675Ssam case CTLR_ERROR: 60025675Ssam case DRIVE_ERROR: 60125675Ssam if (code == CTLR_ERROR) 60225675Ssam vdreset_ctlr((cdr *)vdminfo[ctlr]->um_addr, ctlr); 603*30370Skarels else if (reset_drive((cdr *)vdminfo[ctlr]->um_addr, 604*30370Skarels ctlr, slave) == 0) 605*30370Skarels vddinfo[unit]->ui_alive = 0; 606*30370Skarels /* 607*30370Skarels * Retry transfer once, unless reset failed. 608*30370Skarels */ 609*30370Skarels if (vddinfo[unit]->ui_alive && cq->b_errcnt++ < 2) { 61025675Ssam cq->b_forw = uq->b_back; 61125675Ssam vdstart(vdminfo[ctlr]); 61225675Ssam return; 61325675Ssam } 614*30370Skarels vdhard_error(ci, bp, dcb); 61525675Ssam break; 61625675Ssam 61725675Ssam case HARD_DATA_ERROR: 61829921Skarels case WRITE_PROTECT: 619*30370Skarels default: /* shouldn't happen */ 62025675Ssam vdhard_error(ci, bp, dcb); 62125675Ssam bp->b_resid = 0; 62225675Ssam break; 62325675Ssam 62425675Ssam case SOFT_DATA_ERROR: 62525675Ssam vdsoft_error(ci, bp, dcb); 62625675Ssam /* fall thru... */ 62725675Ssam 628*30370Skarels case 0: /* operation completed */ 62925675Ssam bp->b_error = 0; 63025675Ssam bp->b_resid = 0; 63125675Ssam break; 63224004Ssam } 63325675Ssam vbadone(bp, ci->rawbuf, (long *)ci->map, ci->utl); 63425675Ssam /* 63525675Ssam * Take next request on this unit q, or, if none, 63625675Ssam * the next request on the next active unit q. 63725675Ssam */ 63825675Ssam s = spl7(); 63925675Ssam uq->av_forw = bp->av_forw; 64025675Ssam if (uq->av_back != bp) { 64125675Ssam register struct buf *next; 64224004Ssam 64325675Ssam unit = VDUNIT(uq->av_forw->b_dev); 64425675Ssam slave = vddinfo[unit]->ui_slave; 64525675Ssam next = uq->av_forw; 64625675Ssam if (next->b_cylin != ci->cur_cyl[slave] || 64725675Ssam (next->b_daddr & 0xff) != ci->cur_trk[slave]) 64825675Ssam ci->off_cylinder |= 1 << slave; 64925675Ssam } else 65025675Ssam uq->av_back = NULL; 65125675Ssam splx(s); 65225675Ssam /* reset controller state */ 65325675Ssam cq->b_errcnt = 0; 65425675Ssam cq->b_active--; 65524004Ssam scope_out(3); 65625675Ssam if (bp->b_flags & B_ERROR) 65725675Ssam bp->b_error = EIO; 65824004Ssam iodone(bp); 65925675Ssam vdstart(vdminfo[ctlr]); 66024004Ssam } 66124004Ssam 66225675Ssam /* 66325675Ssam * Convert controller status to internal operation/error code. 66425675Ssam */ 66525675Ssam vddecode_error(dcb) 66625675Ssam register fmt_dcb *dcb; 66725675Ssam { 66824004Ssam 66925675Ssam if (dcb->operrsta & HRDERR) { 67029921Skarels if (dcb->operrsta & WPTERR) 67129921Skarels return (WRITE_PROTECT); 672*30370Skarels /* this looks wrong... 67329921Skarels if (dcb->operrsta & (HCRCERR | HCMPERR | UCDATERR | 674*30370Skarels DSEEKERR | NOTCYLERR | DRVNRDY | INVDADR)) 675*30370Skarels */ 676*30370Skarels if (dcb->operrsta & (DSEEKERR | NOTCYLERR | DRVNRDY | INVDADR)) 67725675Ssam return (DRIVE_ERROR); 67825675Ssam if (dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM)) 67925675Ssam return (CTLR_ERROR); 68025675Ssam return (HARD_DATA_ERROR); 68125675Ssam } 68225675Ssam if (dcb->operrsta & SFTERR) 68325675Ssam return (SOFT_DATA_ERROR); 68425675Ssam return (0); 68525675Ssam } 68625675Ssam 68725675Ssam /* 68825675Ssam * Report a hard error. 68925675Ssam */ 69025675Ssam vdhard_error(ci, bp, dcb) 69125675Ssam ctlr_tab *ci; 69225675Ssam register struct buf *bp; 69325675Ssam register fmt_dcb *dcb; 69425675Ssam { 69525675Ssam 69625675Ssam bp->b_flags |= B_ERROR; 697*30370Skarels /* NEED TO ADJUST b_blkno to failed sector */ 698*30370Skarels harderr(bp, "dk"); 69929921Skarels if (dcb->operrsta & WPTERR) 70029921Skarels printf("write protected"); 70129921Skarels else { 702*30370Skarels printf("status %x (%b)", dcb->operrsta, 703*30370Skarels dcb->operrsta & ~(DSERLY|DSLATE|TOPLUS|TOMNUS|DCBUSC|DCBCMP), 704*30370Skarels ERRBITS); 70529921Skarels if (ci->ctlr_type == SMD_ECTLR) 70629921Skarels printf(" ecode %x", dcb->err_code); 70729921Skarels } 70825675Ssam printf("\n"); 70925675Ssam } 71025675Ssam 71125675Ssam /* 71225675Ssam * Report a soft error. 71325675Ssam */ 71425675Ssam vdsoft_error(ci, bp, dcb) 71525675Ssam ctlr_tab *ci; 71625675Ssam register struct buf *bp; 71725675Ssam register fmt_dcb *dcb; 71825675Ssam { 719*30370Skarels int unit = VDUNIT(bp->b_dev); 720*30370Skarels char part = 'a' + FILSYS(bp->b_dev); 72125675Ssam 722*30370Skarels if (dcb->operrsta == (DCBCMP | CPDCRT | SFTERR | ANYERR)) 723*30370Skarels log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n", 724*30370Skarels unit, part, bp->b_blkno); 725*30370Skarels else 726*30370Skarels log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n", 727*30370Skarels unit, part, bp->b_blkno, dcb->operrsta, ERRBITS, 728*30370Skarels ci->ctlr_type == SMD_ECTLR ? dcb->err_code : 0); 72925675Ssam } 73025675Ssam 73125675Ssam /*ARGSUSED*/ 73225675Ssam vdopen(dev, flag) 73325675Ssam dev_t dev; 73425675Ssam int flag; 73525675Ssam { 73625675Ssam register unit = VDUNIT(dev); 73725675Ssam register struct vba_device *vi = vddinfo[unit]; 73825675Ssam 73925675Ssam if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv) 74025675Ssam return (ENXIO); 741*30370Skarels if (vi->ui_alive == 0) { 742*30370Skarels if (vdconfigure_drive((cdr *)vdminfo[vi->ui_ctlr]->um_addr, 743*30370Skarels vi->ui_ctlr, vi->ui_slave, vi->ui_type)) 744*30370Skarels vi->ui_alive = 1; 745*30370Skarels else 746*30370Skarels return (ENXIO); 747*30370Skarels } 74825675Ssam if (vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0) 74925675Ssam return (ENXIO); 75025675Ssam return (0); 75125675Ssam } 75225675Ssam 75324004Ssam vdread(dev, uio) 75425675Ssam dev_t dev; 75525675Ssam struct uio *uio; 75624004Ssam { 75724004Ssam register int unit = VDUNIT(dev); 75825675Ssam register unit_tab *ui = &vdunit_info[unit]; 75924004Ssam 76029564Ssam if (unit >= NDK) 76125675Ssam return (ENXIO); 76225675Ssam return (physio(vdstrategy, &ui->raw_q_element, dev, B_READ, 76325675Ssam minphys, uio)); 76424004Ssam } 76524004Ssam 76624004Ssam vdwrite(dev, uio) 76725675Ssam dev_t dev; 76825675Ssam struct uio *uio; 76924004Ssam { 77024004Ssam register int unit = VDUNIT(dev); 77125675Ssam register unit_tab *ui = &vdunit_info[unit]; 77224004Ssam 77329564Ssam if (unit >= NDK) 77425675Ssam return (ENXIO); 77525675Ssam return (physio(vdstrategy, &ui->raw_q_element, dev, B_WRITE, 77625675Ssam minphys, uio)); 77724004Ssam } 77824004Ssam 77924004Ssam /* 78025675Ssam * Crash dump. 78124004Ssam */ 78225675Ssam vddump(dev) 78325675Ssam dev_t dev; 78424004Ssam { 78525675Ssam register int unit = VDUNIT(dev); 78625675Ssam register unit_tab *ui = &vdunit_info[unit]; 78725675Ssam register fs_tab *fs = &ui->info; 78825675Ssam register int ctlr = vddinfo[unit]->ui_ctlr; 78925675Ssam register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr]; 79025675Ssam register int filsys = FILSYS(dev); 79125675Ssam register cdr *addr = (cdr *)(vba_vdctlr_info->um_addr); 79225675Ssam register int cur_blk, blkcount, blocks; 79325675Ssam caddr_t memaddr; 79424004Ssam 79525675Ssam vdreset_ctlr(addr, ctlr); 79624004Ssam blkcount = maxfree - 2; /* In 1k byte pages */ 79725675Ssam if (dumplo + blkcount > fs->partition[filsys].par_len) { 79825675Ssam blkcount = fs->partition[filsys].par_len - dumplo; 799*30370Skarels printf("truncated to %dMB ", blkcount/1024); 80025675Ssam } 80125675Ssam cur_blk = fs->partition[filsys].par_start + dumplo; 80225675Ssam memaddr = 0; 80324004Ssam while (blkcount > 0) { 80425675Ssam blocks = MIN(blkcount, DUMPSIZE); 80525675Ssam if (!vdwrite_block(addr, ctlr, unit, memaddr, cur_blk, blocks)) 80625675Ssam return (EIO); 80725675Ssam blkcount -= blocks; 80825675Ssam memaddr += blocks * NBPG; 80925675Ssam cur_blk += blocks; 81024004Ssam } 81125675Ssam return (0); 81224004Ssam } 81324004Ssam 81425675Ssam /* 81525675Ssam * Write a block to disk during a crash dump. 81625675Ssam */ 81725675Ssam vdwrite_block(caddr, ctlr, unit, addr, block, blocks) 81825675Ssam register cdr *caddr; 81925675Ssam register int ctlr, unit; 82025675Ssam register caddr_t addr; 82125675Ssam register int block, blocks; 82224004Ssam { 82325925Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 82425925Ssam register fmt_mdcb *mdcb = &ci->ctlr_mdcb; 82525925Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 82625675Ssam register unit_tab *ui = &vdunit_info[unit]; 82725675Ssam register fs_tab *fs = &ui->info; 82824004Ssam 82925675Ssam block *= (int)ui->sec_per_blk; 83025675Ssam blocks *= (int)ui->sec_per_blk; 83125675Ssam mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 83225675Ssam dcb->intflg = NOINT; 83325675Ssam dcb->opcode = WD; 83425675Ssam dcb->operrsta = 0; 83525675Ssam dcb->devselect = (char)(vddinfo[unit])->ui_slave; 83625675Ssam dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long)); 83725675Ssam dcb->trail.rwtrail.memadr = addr; 83825675Ssam dcb->trail.rwtrail.wcount = (short) 83925675Ssam ((blocks * fs->secsize)/ sizeof (short)); 84025675Ssam dcb->trail.rwtrail.disk.cylinder = (short)(block / ui->sec_per_cyl); 84125675Ssam dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak); 84225675Ssam dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec); 84325925Ssam VDDC_ATTENTION(caddr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 84425925Ssam if (!vdpoll(ci, caddr, 5)) { 84525675Ssam printf(" during dump\n"); 84625675Ssam return (0); 84725675Ssam } 84825675Ssam if (dcb->operrsta & HRDERR) { 84929921Skarels printf("dk%d: hard error, status=%b\n", unit, 85029921Skarels dcb->operrsta, ERRBITS); 85125675Ssam return (0); 85225675Ssam } 85325675Ssam return (1); 85424004Ssam } 85524004Ssam 85624004Ssam vdsize(dev) 85725675Ssam dev_t dev; 85824004Ssam { 85925675Ssam struct vba_device *vi = vddinfo[VDUNIT(dev)]; 86024004Ssam 86125675Ssam if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv) 86225675Ssam return (-1); 86325675Ssam return (vdunit_info[VDUNIT(dev)].info.partition[FILSYS(dev)].par_len); 86424004Ssam } 86524004Ssam 86625675Ssam /* 86725675Ssam * Perform a controller reset. 86825675Ssam */ 86925675Ssam vdreset_ctlr(addr, ctlr) 87025675Ssam register cdr *addr; 87125675Ssam register int ctlr; 87224004Ssam { 87325675Ssam register struct buf *cq = &vdminfo[ctlr]->um_tab; 87425675Ssam register struct buf *uq = cq->b_forw; 87525675Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 87625675Ssam 87725675Ssam VDDC_RESET(addr, ci->ctlr_type); 87825675Ssam ci->ctlr_started = 0; 87925675Ssam if (ci->ctlr_type == SMD_ECTLR) { 88025675Ssam addr->cdr_csr = 0; 88125675Ssam addr->mdcb_tcf = AM_ENPDA; 88225675Ssam addr->dcb_tcf = AM_ENPDA; 88325675Ssam addr->trail_tcf = AM_ENPDA; 88425675Ssam addr->data_tcf = AM_ENPDA; 88525675Ssam addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 88625675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 88725675Ssam } 88825675Ssam if (vdnotrailer(addr, ctlr, 0, INIT, 10) & HRDERR) { 88925675Ssam printf("failed to init\n"); 890*30370Skarels return; 89125675Ssam } 89225675Ssam if (vdnotrailer(addr, ctlr, 0, DIAG, 10) & HRDERR) { 89325675Ssam printf("diagnostic error\n"); 894*30370Skarels return; 89525675Ssam } 89625675Ssam /* reset all units attached to controller */ 89725675Ssam uq = cq->b_forw; 89825675Ssam do { 899*30370Skarels (void) reset_drive(addr, ctlr, uq->b_dev); 90025675Ssam uq = uq->b_forw; 90125675Ssam } while (uq != cq->b_forw); 90225675Ssam } 90324004Ssam 90425675Ssam /* 90525675Ssam * Perform a reset on a drive. 90625675Ssam */ 907*30370Skarels reset_drive(addr, ctlr, slave) 908*30370Skarels cdr *addr; 909*30370Skarels int ctlr, slave; 91025675Ssam { 911*30370Skarels int type = vdctlr_info[ctlr].unit_type[slave]; 91225675Ssam 91325675Ssam if (type == UNKNOWN) 914*30370Skarels return (0); 915*30370Skarels if (!vdconfigure_drive(addr, ctlr, slave, type)) { 91625675Ssam printf("vd%d: drive %d: couldn't reset\n", ctlr, slave); 917*30370Skarels return (0); 918*30370Skarels } 919*30370Skarels return (1); 92025675Ssam } 92125675Ssam 92225925Ssam /* 92325925Ssam * Poll controller until operation completes 92425925Ssam * or timeout expires. 92525925Ssam */ 92625925Ssam vdpoll(ci, addr, t) 92725925Ssam register ctlr_tab *ci; 92825925Ssam register cdr *addr; 92925925Ssam register int t; 93025925Ssam { 93125925Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 93225925Ssam 93325925Ssam t *= 1000; 934*30370Skarels for (;;) { 93525925Ssam uncache(&dcb->operrsta); 936*30370Skarels if (dcb->operrsta & (DCBCMP|DCBABT)) 937*30370Skarels break; 93825925Ssam if (--t <= 0) { 93925925Ssam printf("vd%d: controller timeout", ci-vdctlr_info); 94025925Ssam VDDC_ABORT(addr, ci->ctlr_type); 94125925Ssam DELAY(30000); 94225925Ssam uncache(&dcb->operrsta); 94325925Ssam return (0); 94425925Ssam } 945*30370Skarels DELAY(1000); 94625925Ssam } 94725925Ssam if (ci->ctlr_type == SMD_ECTLR) { 948*30370Skarels for (;;) { 949*30370Skarels uncache(&addr->cdr_csr); 950*30370Skarels if ((addr->cdr_csr & CS_GO) == 0) 951*30370Skarels break; 95225925Ssam DELAY(50); 95325925Ssam } 95425925Ssam DELAY(300); 95525925Ssam } 95625925Ssam DELAY(200); 95725925Ssam uncache(&dcb->operrsta); 95825925Ssam return (1); 95925925Ssam } 96025925Ssam 96125675Ssam #ifdef notdef 96225675Ssam /* 96325675Ssam * Dump the mdcb and DCB for diagnostic purposes. 96425675Ssam */ 96525675Ssam vdprintdcb(lp) 96625675Ssam register long *lp; 96725675Ssam { 96825675Ssam register int i, dcb, tc; 96925675Ssam 97025675Ssam for (dcb = 0; lp; lp = (long *)(*lp), dcb++) { 97125675Ssam lp = (long *)((long)lp | 0xc0000000); 97225675Ssam printf("\nDump of dcb%d@%x:", dcb, lp); 97325675Ssam for (i = 0, tc = lp[3] & 0xff; i < tc+7; i++) 97425675Ssam printf(" %lx", lp[i]); 97525675Ssam printf("\n"); 97624004Ssam } 97725675Ssam DELAY(1750000); 97824004Ssam } 97924004Ssam #endif 98025675Ssam #endif 981