1*29564Ssam /* vd.c 1.9 86/07/16 */ 224004Ssam 3*29564Ssam #include "dk.h" 424004Ssam #if NVD > 0 524004Ssam /* 6*29564Ssam * VDDC - Versabus SMD/SMDE driver. 725675Ssam */ 825877Ssam #ifdef VDDCPERF 925877Ssam #define DOSCOPE 1025877Ssam #endif 1125877Ssam 1225675Ssam #include "../tahoe/mtpr.h" 1325675Ssam #include "../tahoe/pte.h" 1424004Ssam 1525675Ssam #include "param.h" 1625675Ssam #include "buf.h" 1725675Ssam #include "cmap.h" 1825675Ssam #include "conf.h" 1925675Ssam #include "dir.h" 20*29564Ssam #include "dkstat.h" 2125675Ssam #include "map.h" 2225675Ssam #include "systm.h" 2325675Ssam #include "user.h" 2425675Ssam #include "vmmac.h" 2525675Ssam #include "proc.h" 2625675Ssam #include "uio.h" 2724004Ssam 2825675Ssam #include "../tahoevba/vbavar.h" 2925675Ssam #define VDGENDATA 3025928Ssam #include "../tahoevba/vdreg.h" 3125675Ssam #undef VDGENDATA 3225877Ssam #include "../tahoevba/scope.h" 3324004Ssam 3425925Ssam #define VDMAXIO (MAXBPTE*NBPG) 3525675Ssam #define DUMPSIZE 64 /* controller limit */ 3624004Ssam 3724004Ssam #define VDUNIT(x) (minor(x) >> 3) 3825675Ssam #define FILSYS(x) (minor(x) & 0x07) 3925675Ssam #define PHYS(x) (vtoph((struct proc *)0, (unsigned)(x))) 4024004Ssam 4125675Ssam #define CTLR_ERROR 1 4225675Ssam #define DRIVE_ERROR 2 4325675Ssam #define HARD_DATA_ERROR 3 4425675Ssam #define SOFT_DATA_ERROR 4 4524004Ssam 4625675Ssam #define b_cylin b_resid 4725675Ssam #define b_daddr b_error 4824004Ssam 4924004Ssam struct vba_ctlr *vdminfo[NVD]; 50*29564Ssam struct vba_device *vddinfo[NDK]; 5125675Ssam int vdprobe(), vdslave(), vdattach(), vddgo(); 5225675Ssam struct vba_driver vddriver = 53*29564Ssam { vdprobe, vdslave, vdattach, vddgo, vddcaddr, "dk", 5425675Ssam vddinfo, "vd", vdminfo }; 5524004Ssam 5624004Ssam /* 5725675Ssam * Per-drive state. 5825675Ssam */ 5925675Ssam typedef struct { 6025675Ssam struct buf raw_q_element; 6125675Ssam short sec_per_blk; 6225675Ssam short sec_per_cyl; 6325675Ssam char status; 6425675Ssam struct buf xfer_queue; 6525675Ssam int drive_type; 6625675Ssam fs_tab info; 6725675Ssam } unit_tab; 6824004Ssam 6924004Ssam /* 7025675Ssam * Per-controller state. 7125675Ssam */ 7225675Ssam typedef struct { 7325675Ssam char ctlr_type; /* controller type */ 7425925Ssam struct pte *map; /* i/o page map */ 7525925Ssam caddr_t utl; /* mapped i/o space */ 7625675Ssam u_int cur_slave:8; /* last active unit number */ 7725675Ssam u_int int_expected:1; /* expect an interupt */ 7825675Ssam u_int ctlr_started:1; /* start command was issued */ 7925675Ssam u_int overlap_seeks:1;/* should overlap seeks */ 8025925Ssam u_int initdone:1; /* controller initialization completed */ 8125675Ssam u_int off_cylinder:16;/* off cylinder bit map */ 8225675Ssam u_int unit_type[16]; /* slave types */ 8325675Ssam u_int cur_cyl[16]; /* cylinder last selected */ 8425675Ssam long cur_trk[16]; /* track last selected */ 8525675Ssam fmt_mdcb ctlr_mdcb; /* controller mdcb */ 8625675Ssam fmt_dcb ctlr_dcb; /* r/w dcb */ 8725675Ssam fmt_dcb seek_dcb[4]; /* dcbs for overlapped seeks */ 8825950Ssam caddr_t rawbuf; /* buffer for raw+swap i/o */ 8925675Ssam } ctlr_tab; 9024004Ssam 9125925Ssam ctlr_tab vdctlr_info[NVD]; 92*29564Ssam unit_tab vdunit_info[NDK]; 9324004Ssam 9424004Ssam /* 9525675Ssam * See if the controller is really there; if so, initialize it. 9625675Ssam */ 9725857Ssam vdprobe(reg, vm) 9825857Ssam caddr_t reg; 9925857Ssam struct vba_ctlr *vm; 10025675Ssam { 10125857Ssam register br, cvec; /* must be r12, r11 */ 10225925Ssam register cdr *addr = (cdr *)reg; 10325925Ssam register ctlr_tab *ci; 10425925Ssam int i; 10525857Ssam 10625857Ssam if (badaddr((caddr_t)reg, 2)) 10725675Ssam return (0); 10825925Ssam ci = &vdctlr_info[vm->um_ctlr]; 10925925Ssam addr->cdr_reset = 0xffffffff; 11025675Ssam DELAY(1000000); 11125925Ssam if (addr->cdr_reset != (unsigned)0xffffffff) { 11225925Ssam ci->ctlr_type = SMDCTLR; 11325925Ssam ci->overlap_seeks = 0; 11425675Ssam DELAY(1000000); 11525675Ssam } else { 11625925Ssam ci->overlap_seeks = 1; 11725925Ssam ci->ctlr_type = SMD_ECTLR; 11825925Ssam addr->cdr_reserved = 0x0; 11925675Ssam DELAY(3000000); 12025925Ssam addr->cdr_csr = 0; 12125925Ssam addr->mdcb_tcf = AM_ENPDA; 12225925Ssam addr->dcb_tcf = AM_ENPDA; 12325925Ssam addr->trail_tcf = AM_ENPDA; 12425925Ssam addr->data_tcf = AM_ENPDA; 12525925Ssam addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 12625925Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 12725675Ssam } 12825925Ssam /* 12925950Ssam * Allocate page tables and i/o buffer. 13025925Ssam */ 13125925Ssam vbmapalloc(btoc(VDMAXIO)+1, &ci->map, &ci->utl); 13225950Ssam ci->rawbuf = calloc(VDMAXIO); 13325925Ssam /* 13425925Ssam * Initialize all the drives to be of an unknown type. 13525925Ssam */ 13625925Ssam for (i = 0; i < 15; i++) 13725925Ssam ci->unit_type[i] = UNKNOWN; 13825857Ssam br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ 13925925Ssam return (sizeof (*addr)); 14025675Ssam } 14124004Ssam 14224004Ssam /* 14325675Ssam * See if a drive is really there 14425675Ssam * Try to reset/configure the drive, then test its status. 14525675Ssam */ 14625675Ssam vdslave(vi, addr) 14725675Ssam register struct vba_device *vi; 14825675Ssam register cdr *addr; 14925675Ssam { 15025675Ssam register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr]; 15125675Ssam register unit_tab *ui = &vdunit_info[vi->ui_unit]; 15225675Ssam register fmt_mdcb *mdcb = &ci->ctlr_mdcb; 15325675Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 15425675Ssam register int type; 15524004Ssam 15625925Ssam if (!ci->initdone) { 15725925Ssam printf("vd%d: %s controller\n", vi->ui_ctlr, 158*29564Ssam ci->ctlr_type == SMDCTLR ? "smd" : "smde"); 15925925Ssam if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, INIT, 10) & 16025925Ssam HRDERR) { 16125925Ssam printf("vd%d: init error\n", vi->ui_ctlr); 16225675Ssam return (0); 16325675Ssam } 16425925Ssam if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, DIAG, 10) & 16525925Ssam HRDERR) { 16625925Ssam printf("vd%d: diagnostic error\n", vi->ui_ctlr); 16725675Ssam return (0); 16825675Ssam } 16925925Ssam ci->initdone = 1; 17025675Ssam } 17125675Ssam /* 17225675Ssam * Seek on all drive types starting from the largest one. 17325675Ssam * a successful seek to the last sector/cylinder/track verifies 17425675Ssam * the drive type connected to this port. 17525675Ssam */ 17625675Ssam for (type = 0; type < nvddrv; type++) { 17725675Ssam /* XXX */ 17825675Ssam if (ci->ctlr_type == SMDCTLR && vdst[type].nsec != 32) 17925675Ssam continue; 18025675Ssam /* XXX */ 18125675Ssam if (!vdconfigure_drive(addr, vi->ui_ctlr, vi->ui_slave, type,0)) 18225675Ssam return (0); 18325675Ssam dcb->opcode = (short)RD; 18425675Ssam dcb->intflg = NOINT; 18525675Ssam dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */ 18625675Ssam dcb->operrsta = 0; 18725675Ssam dcb->devselect = (char)(vi->ui_slave); 18825675Ssam dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long)); 18925675Ssam dcb->trail.rwtrail.memadr = (char *)PHYS(ci->rawbuf); 19025675Ssam dcb->trail.rwtrail.wcount = vdst[type].secsize/sizeof(short); 19125675Ssam dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2; 19225675Ssam dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1; 19325675Ssam dcb->trail.rwtrail.disk.sector = vdst[type].nsec - 1; 19425675Ssam mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 19525675Ssam mdcb->vddcstat = 0; 19625675Ssam VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 19725925Ssam if (!vdpoll(ci, addr, 60)) 19825675Ssam printf(" during probe\n"); 19925675Ssam if ((dcb->operrsta&HRDERR) == 0) 20025675Ssam break; 20125675Ssam } 20225675Ssam if (type >= nvddrv) { 20325675Ssam /* 20425675Ssam * If reached here, a drive which is not defined in the 20525675Ssam * 'vdst' tables is connected. Cannot set it's type. 20625675Ssam */ 207*29564Ssam printf("dk%d: unknown drive type\n", vi->ui_unit); 20825675Ssam return (0); 20925675Ssam } 21025675Ssam ui->drive_type = type; 21125675Ssam ui->info = vdst[type]; 21225675Ssam ui->sec_per_blk = DEV_BSIZE / ui->info.secsize; 21325675Ssam vi->ui_type = type; 21425675Ssam vi->ui_dk = 1; 21525675Ssam return (1); 21624004Ssam } 21724004Ssam 21825675Ssam vdconfigure_drive(addr, ctlr, slave, type, pass) 21925675Ssam register cdr *addr; 22025675Ssam int ctlr, slave, type, pass; 22124004Ssam { 22225675Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 22325675Ssam 22425675Ssam ci->ctlr_dcb.opcode = RSTCFG; /* command */ 22525675Ssam ci->ctlr_dcb.intflg = NOINT; 22625675Ssam ci->ctlr_dcb.nxtdcb = (fmt_dcb *)0; /* end of chain */ 22725675Ssam ci->ctlr_dcb.operrsta = 0; 22825675Ssam ci->ctlr_dcb.devselect = (char)slave; 22925675Ssam ci->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl; 23025675Ssam ci->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak; 23125675Ssam if (ci->ctlr_type == SMD_ECTLR) { 23225675Ssam ci->ctlr_dcb.trailcnt = (char)4; 23325675Ssam ci->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec; 23425675Ssam ci->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip; 23525675Ssam } else 23625675Ssam ci->ctlr_dcb.trailcnt = (char)2; 23725675Ssam ci->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&ci->ctlr_dcb)); 23825675Ssam ci->ctlr_mdcb.vddcstat = 0; 23925675Ssam VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(&ci->ctlr_mdcb)), ci->ctlr_type); 24025925Ssam if (!vdpoll(ci, addr, 5)) { 24125675Ssam printf(" during config\n"); 24225675Ssam return (0); 24325675Ssam } 24425675Ssam if (ci->ctlr_dcb.operrsta & HRDERR) { 24525675Ssam if ((ci->ctlr_dcb.operrsta & (NOTCYLERR|DRVNRDY)) == 0) 24625675Ssam printf("vd%d: drive %d: config error\n", ctlr, slave); 24725675Ssam else if (pass == 0) { 24825675Ssam vdstart_drive(addr, ctlr, slave); 24925675Ssam return (vdconfigure_drive(addr, ctlr, slave, type, 1)); 25025675Ssam } else if (pass == 2) 25125675Ssam return (vdconfigure_drive(addr, ctlr, slave, type, 3)); 25225675Ssam return (0); 25325675Ssam } 25425675Ssam return (1); 25524004Ssam } 25624004Ssam 25725675Ssam vdstart_drive(addr, ctlr, slave) 25825675Ssam cdr *addr; 25925675Ssam register int ctlr, slave; 26024004Ssam { 26125675Ssam int error = 0; 26224004Ssam 26325675Ssam printf("vd%d: starting drive %d, wait...", ctlr, slave); 26425675Ssam if (vdctlr_info[ctlr].ctlr_started) { 26525675Ssam printf("DELAY(5500000)..."); 26625675Ssam DELAY(5500000); 26725675Ssam goto done; 26824004Ssam } 26925675Ssam vdctlr_info[ctlr].ctlr_started = 1; 27025675Ssam error = vdnotrailer(addr, ctlr, 0, VDSTART, (slave*6)+62) & HRDERR; 27125675Ssam if (!error) { 27225675Ssam printf("DELAY(%d)...", (slave * 5500000) + 62000000); 27325675Ssam DELAY((slave * 5500000) + 62000000); 27424004Ssam } 27525675Ssam done: 27625675Ssam printf("\n"); 27725675Ssam return (error == 0); 27825675Ssam } 27924004Ssam 28025675Ssam vdnotrailer(addr, ctlr, unit, function, time) 28125675Ssam register cdr *addr; 28225675Ssam int ctlr, unit, function, time; 28324004Ssam { 28425925Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 28525925Ssam fmt_mdcb *mdcb = &ci->ctlr_mdcb; 28625925Ssam fmt_dcb *dcb = &ci->ctlr_dcb; 28724004Ssam 28825675Ssam dcb->opcode = function; /* command */ 28924004Ssam dcb->intflg = NOINT; 29025675Ssam dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */ 29125675Ssam dcb->operrsta = 0; 29225675Ssam dcb->devselect = (char)unit; 29324004Ssam dcb->trailcnt = (char)0; 29425675Ssam mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 29524004Ssam mdcb->vddcstat = 0; 29625925Ssam VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 29725925Ssam if (!vdpoll(ci, addr, time)) { 29825675Ssam printf(" during init\n"); 29925675Ssam return (DCBCMP|ANYERR|HRDERR|OPABRT); 30024004Ssam } 30125675Ssam return (dcb->operrsta); 30225675Ssam } 30324004Ssam 30425675Ssam vdattach(vi) 30525675Ssam register struct vba_device *vi; 30625675Ssam { 30725675Ssam register unit_tab *ui = &vdunit_info[vi->ui_unit]; 30825675Ssam register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr]; 30925675Ssam register struct buf *cq = &vi->ui_mi->um_tab; 31025675Ssam register struct buf *uq = cq->b_forw; 31125675Ssam register struct buf *start_queue = uq; 31225675Ssam register fs_tab *fs = &ui->info; 31325675Ssam 31425675Ssam ui->info = vdst[vi->ui_type]; 31525675Ssam ui->sec_per_blk = DEV_BSIZE / ui->info.secsize; 31625675Ssam ui->sec_per_cyl = ui->info.nsec * ui->info.ntrak; 31725675Ssam ui->xfer_queue.b_dev = vi->ui_slave; 31825675Ssam ci->unit_type[vi->ui_slave] = vi->ui_type; 31925675Ssam /* load unit into controller's active unit list */ 32025675Ssam if (uq == NULL) { 32125675Ssam cq->b_forw = &ui->xfer_queue; 32225675Ssam ui->xfer_queue.b_forw = &ui->xfer_queue; 32325675Ssam ui->xfer_queue.b_back = &ui->xfer_queue; 32425675Ssam } else { 32525675Ssam while (uq->b_forw != start_queue) 32625675Ssam uq = uq->b_forw; 32725675Ssam ui->xfer_queue.b_forw = start_queue; 32825675Ssam ui->xfer_queue.b_back = uq; 32925675Ssam uq->b_forw = &ui->xfer_queue; 33025675Ssam start_queue->b_back = &ui->xfer_queue; 33125675Ssam } 332*29564Ssam printf("dk%d: %s\n", vi->ui_unit, fs->type_name); 33324004Ssam /* 33425675Ssam * (60 / rpm) / (number of sectors per track * (bytes per sector / 2)) 33524004Ssam */ 33625675Ssam dk_mspw[vi->ui_unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize); 33724004Ssam } 33824004Ssam 33925675Ssam /*ARGSUSED*/ 34025675Ssam vddgo(um) 34125675Ssam struct vba_ctlr *um; 34224004Ssam { 34324004Ssam 34424004Ssam } 34524004Ssam 34624004Ssam vdstrategy(bp) 34725675Ssam register struct buf *bp; 34824004Ssam { 34925675Ssam register int unit = VDUNIT(bp->b_dev); 35025675Ssam register struct vba_device *vi = vddinfo[unit]; 35125675Ssam register par_tab *par; 35225675Ssam register unit_tab *ui; 35325675Ssam register fs_tab *fs; 35425675Ssam register int blks, bn, s; 35524004Ssam 35625675Ssam if (bp->b_bcount == 0 || vi == 0 || vi->ui_alive == 0) 35725675Ssam goto bad; 35825675Ssam ui = &vdunit_info[unit]; 35925675Ssam fs = &ui->info; 36025675Ssam par = &fs->partition[FILSYS(bp->b_dev)]; 36125675Ssam blks = (bp->b_bcount + DEV_BSIZE-1) >> DEV_BSHIFT; 36225675Ssam if (bp->b_blkno + blks >= par->par_len) { 36325675Ssam blks = par->par_len - bp->b_blkno; 36425675Ssam if (blks <= 0) 36525675Ssam goto bad; 36625675Ssam bp->b_bcount = blks * DEV_BSIZE; 36725675Ssam } 36825675Ssam bn = bp->b_blkno + par->par_start; 36925675Ssam bn *= ui->sec_per_blk; 37025675Ssam bp->b_daddr = (bn / fs->nsec) % fs->ntrak; 37125675Ssam bp->b_cylin = bn / ui->sec_per_cyl; 37225675Ssam vbasetup(bp, ui->info.secsize); 37325675Ssam s = spl7(); 37425675Ssam if (ui->xfer_queue.av_forw == NULL) { 37525675Ssam register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr]; 37625675Ssam int slave = vi->ui_slave; 37724004Ssam 37825675Ssam if (bp->b_cylin != ci->cur_cyl[slave] || 37925675Ssam bp->b_daddr != ci->cur_trk[slave]) 38025675Ssam ci->off_cylinder |= 1 << slave; 38124004Ssam } 38225675Ssam bp->b_daddr |= (bn % fs->nsec) << 8; 38325675Ssam disksort(&ui->xfer_queue, bp); 38425675Ssam if (!vddinfo[unit]->ui_mi->um_tab.b_active++) { 38525675Ssam splx(s); 38625675Ssam vdstart(vddinfo[unit]->ui_mi); 38725675Ssam } else 38825675Ssam splx(s); 38924004Ssam return; 39025675Ssam bad: 39125675Ssam bp->b_flags |= B_ERROR, bp->b_error = ENXIO; 39225675Ssam bp->b_resid = bp->b_bcount; 39324004Ssam iodone(bp); 39424004Ssam } 39524004Ssam 39624004Ssam /* 39724004Ssam * Start up a transfer on a drive. 39824004Ssam */ 39925675Ssam vdstart(ci) 40025675Ssam register struct vba_ctlr *ci; 40124004Ssam { 40225675Ssam register struct buf *cq = &ci->um_tab; 40325675Ssam register struct buf *uq = cq->b_forw; 40424004Ssam 40525675Ssam /* search for next ready unit */ 40625675Ssam cq->b_forw = cq->b_forw->b_forw; 40725675Ssam uq = cq->b_forw; 40825675Ssam do { 40925675Ssam if (uq->av_forw != NULL) { 41025675Ssam cq->b_forw = uq; 41125675Ssam vdexecute(ci, uq); 41225675Ssam return; 41325675Ssam } 41425675Ssam uq = uq->b_forw; 41525675Ssam } while (uq != cq->b_forw); 41625675Ssam } 41725675Ssam 41825675Ssam /* 41925675Ssam * Initiate seeks for all drives off-cylinder. 42025675Ssam */ 42125675Ssam vdload_seeks(ci, uq) 42225675Ssam register ctlr_tab *ci; 42325675Ssam register struct buf *uq; 42425675Ssam { 42525675Ssam register int unit, slave, nseeks; 42625675Ssam register fmt_dcb *dcb; 42725675Ssam register struct buf *bp; 42825675Ssam register struct buf *start_queue = uq; 42925675Ssam 43025675Ssam nseeks = 0; 43125675Ssam do { 43225675Ssam bp = uq->av_forw; 43325675Ssam if (bp != NULL) { 43425675Ssam unit = VDUNIT(bp->b_dev); 43525675Ssam slave = vddinfo[unit]->ui_slave; 43625675Ssam if (ci->off_cylinder & (1 << slave)) { 43725675Ssam ci->off_cylinder &= ~(1 << slave); 43825675Ssam if (ci->cur_cyl[slave] != bp->b_cylin) { 43925675Ssam ci->cur_cyl[slave] = bp->b_cylin; 44025675Ssam dk_seek[unit]++; 44125675Ssam } 44225675Ssam ci->cur_trk[slave] = bp->b_daddr&0xff; 44325675Ssam dcb = &ci->seek_dcb[nseeks++]; 44425675Ssam dcb->opcode = SEEK; 44525675Ssam dcb->intflg = NOINT | INT_PBA; 44625675Ssam dcb->operrsta = 0; 44725675Ssam dcb->devselect = (char)slave; 44825675Ssam dcb->trailcnt = (char)1; 44925675Ssam dcb->trail.sktrail.skaddr.cylinder = 45025675Ssam bp->b_cylin; 45125675Ssam dcb->trail.sktrail.skaddr.track = 45225675Ssam bp->b_daddr & 0xff; 45325675Ssam dcb->trail.sktrail.skaddr.sector = 0; 45425675Ssam } 45525675Ssam } 45625675Ssam uq = uq->b_forw; 45725675Ssam } while (uq != start_queue && nseeks < 4); 45825675Ssam return (nseeks); 45925675Ssam } 46025675Ssam 46125675Ssam extern vd_int_timeout(); 46225675Ssam /* 46325675Ssam * Execute the next command on the unit queue uq. 46425675Ssam */ 46525675Ssam vdexecute(controller_info, uq) 46625675Ssam register struct vba_ctlr *controller_info; 46725675Ssam register struct buf *uq; 46825675Ssam { 46925675Ssam register struct buf *bp = uq->av_forw; 47025675Ssam register int ctlr = controller_info->um_ctlr; 47125675Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 47225675Ssam register int unit = VDUNIT(bp->b_dev); 47325675Ssam register int slave = vddinfo[unit]->ui_slave; 47425675Ssam register fmt_mdcb *mdcb = &ci->ctlr_mdcb; 47525675Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 47625675Ssam 47724004Ssam /* 47825675Ssam * If there are overlapped seeks to perform, shuffle 47925675Ssam * them to the front of the queue and get them started 48025675Ssam * before any data transfers (to get some parallelism). 48124004Ssam */ 48225675Ssam if ((ci->off_cylinder & ~(1<<slave)) && ci->overlap_seeks) { 48325675Ssam register int i, nseeks; 48425675Ssam 48525675Ssam /* setup seek requests in seek-q */ 48625675Ssam nseeks = vdload_seeks(ci, uq); 48725675Ssam /* place at the front of the master q */ 48825675Ssam mdcb->firstdcb = (fmt_dcb *)PHYS(&ci->seek_dcb[0]); 48925675Ssam /* shuffle any remaining seeks up in the seek-q */ 49025675Ssam for (i = 1; i < nseeks; i++) 49125675Ssam ci->seek_dcb[i-1].nxtdcb = 49225675Ssam (fmt_dcb *)PHYS(&ci->seek_dcb[i]); 49325675Ssam ci->seek_dcb[nseeks-1].nxtdcb = (fmt_dcb *)PHYS(dcb); 49425675Ssam } else { 49525675Ssam if (bp->b_cylin != ci->cur_cyl[slave]) { 49625675Ssam ci->cur_cyl[slave] = bp->b_cylin; 49725675Ssam dk_seek[unit]++; 49825675Ssam } 49925675Ssam ci->cur_trk[slave] = bp->b_daddr & 0xff; 50025675Ssam ci->off_cylinder = 0; 50125675Ssam mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 50224004Ssam } 50324004Ssam dcb->opcode = (bp->b_flags & B_READ) ? RD : WD; 50425675Ssam dcb->intflg = INTDONE; 50525675Ssam dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */ 50624004Ssam dcb->operrsta = 0; 50725675Ssam dcb->devselect = (char)slave; 50825675Ssam dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long)); 50925675Ssam dcb->trail.rwtrail.memadr = (char *) 51025675Ssam vbastart(bp, ci->rawbuf, (long *)ci->map, ci->utl); 51125675Ssam dcb->trail.rwtrail.wcount = (short)((bp->b_bcount+1) / sizeof (short)); 51225675Ssam dcb->trail.rwtrail.disk.cylinder = bp->b_cylin; 51325675Ssam dcb->trail.rwtrail.disk.track = bp->b_daddr & 0xff; 51425675Ssam dcb->trail.rwtrail.disk.sector = bp->b_daddr >> 8; 51525675Ssam mdcb->vddcstat = 0; 51625675Ssam dk_wds[unit] += bp->b_bcount / 32; 51725675Ssam ci->int_expected = 1; 51825675Ssam timeout(vd_int_timeout, (caddr_t)ctlr, 20*60); 51925675Ssam dk_busy |= 1 << unit; 52025675Ssam scope_out(1); 52125675Ssam VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr), 52225675Ssam (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 52325675Ssam } 52424004Ssam 52524004Ssam /* 52625675Ssam * Watch for lost interrupts. 52725675Ssam */ 52825675Ssam vd_int_timeout(ctlr) 52925675Ssam register int ctlr; 53025675Ssam { 53125675Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 53225675Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 53324004Ssam 53425675Ssam uncache(&dcb->operrsta); 53525675Ssam printf("vd%d: lost interupt, status %x", ctlr, dcb->operrsta); 53625675Ssam if (ci->ctlr_type == SMD_ECTLR) { 53725675Ssam uncache(&dcb->err_code); 53825675Ssam printf(", error code %x", dcb->err_code); 53924004Ssam } 54025675Ssam printf("\n"); 54125675Ssam if ((dcb->operrsta&DCBCMP) == 0) { 54225675Ssam VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), ci->ctlr_type); 54325675Ssam dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR; 54425675Ssam } 54525675Ssam vdintr(ctlr); 54624004Ssam } 54724004Ssam 54824004Ssam /* 54924004Ssam * Handle a disk interrupt. 55024004Ssam */ 55125675Ssam vdintr(ctlr) 55225675Ssam register int ctlr; 55324004Ssam { 55425675Ssam register ctlr_tab *ci; 55525675Ssam register struct buf *cq, *uq, *bp; 55625675Ssam register int slave, unit; 55725675Ssam register fmt_mdcb *mdcb; 55825675Ssam register fmt_dcb *dcb; 55925675Ssam int code, s; 56024004Ssam 56125675Ssam untimeout(vd_int_timeout, (caddr_t)ctlr); 56224004Ssam scope_out(2); 56325675Ssam ci = &vdctlr_info[ctlr]; 56425675Ssam if (!ci->int_expected) { 56525675Ssam printf("vd%d: stray interrupt\n", ctlr); 56624004Ssam return; 56724004Ssam } 56825675Ssam /* 56925675Ssam * Take first request off controller's queue. 57025675Ssam */ 57125675Ssam cq = &vdminfo[ctlr]->um_tab; 57225675Ssam uq = cq->b_forw; 57325675Ssam bp = uq->av_forw; 57424004Ssam unit = VDUNIT(bp->b_dev); 57525675Ssam dk_busy &= ~(1 << unit); 57625675Ssam dk_xfer[unit]++; 57725675Ssam ci->int_expected = 0; 57825675Ssam /* find associated control blocks */ 57925675Ssam mdcb = &ci->ctlr_mdcb, uncache(&mdcb->intdcb); 58025675Ssam dcb = &ci->ctlr_dcb, uncache(&dcb->operrsta); 58125675Ssam if (ci->ctlr_type == SMD_ECTLR) 58225675Ssam uncache(&dcb->err_code); 58325675Ssam slave = uq->b_dev; 58425675Ssam switch (code = vddecode_error(dcb)) { 58524004Ssam 58625675Ssam case CTLR_ERROR: 58725675Ssam case DRIVE_ERROR: 58825675Ssam if (cq->b_errcnt >= 2) 58925675Ssam vdhard_error(ci, bp, dcb); 59025675Ssam if (code == CTLR_ERROR) 59125675Ssam vdreset_ctlr((cdr *)vdminfo[ctlr]->um_addr, ctlr); 59225675Ssam else 59325675Ssam reset_drive((cdr *)vdminfo[ctlr]->um_addr, ctlr, 59425675Ssam slave, 2); 59525675Ssam if (cq->b_errcnt++ < 2) { /* retry error */ 59625675Ssam cq->b_forw = uq->b_back; 59725675Ssam vdstart(vdminfo[ctlr]); 59825675Ssam return; 59925675Ssam } 60025675Ssam bp->b_resid = bp->b_bcount; 60125675Ssam break; 60225675Ssam 60325675Ssam case HARD_DATA_ERROR: 60425675Ssam vdhard_error(ci, bp, dcb); 60525675Ssam bp->b_resid = 0; 60625675Ssam break; 60725675Ssam 60825675Ssam case SOFT_DATA_ERROR: 60925675Ssam vdsoft_error(ci, bp, dcb); 61025675Ssam /* fall thru... */ 61125675Ssam 61225675Ssam default: /* operation completed */ 61325675Ssam bp->b_error = 0; 61425675Ssam bp->b_resid = 0; 61525675Ssam break; 61624004Ssam } 61725675Ssam vbadone(bp, ci->rawbuf, (long *)ci->map, ci->utl); 61825675Ssam /* 61925675Ssam * Take next request on this unit q, or, if none, 62025675Ssam * the next request on the next active unit q. 62125675Ssam */ 62225675Ssam s = spl7(); 62325675Ssam uq->av_forw = bp->av_forw; 62425675Ssam if (uq->av_back != bp) { 62525675Ssam register struct buf *next; 62624004Ssam 62725675Ssam unit = VDUNIT(uq->av_forw->b_dev); 62825675Ssam slave = vddinfo[unit]->ui_slave; 62925675Ssam next = uq->av_forw; 63025675Ssam if (next->b_cylin != ci->cur_cyl[slave] || 63125675Ssam (next->b_daddr & 0xff) != ci->cur_trk[slave]) 63225675Ssam ci->off_cylinder |= 1 << slave; 63325675Ssam } else 63425675Ssam uq->av_back = NULL; 63525675Ssam splx(s); 63625675Ssam /* reset controller state */ 63725675Ssam cq->b_errcnt = 0; 63825675Ssam cq->b_active--; 63924004Ssam scope_out(3); 64025675Ssam if (bp->b_flags & B_ERROR) 64125675Ssam bp->b_error = EIO; 64224004Ssam iodone(bp); 64325675Ssam vdstart(vdminfo[ctlr]); 64424004Ssam } 64524004Ssam 64625675Ssam /* 64725675Ssam * Convert controller status to internal operation/error code. 64825675Ssam */ 64925675Ssam vddecode_error(dcb) 65025675Ssam register fmt_dcb *dcb; 65125675Ssam { 65224004Ssam 65325675Ssam if (dcb->operrsta & HRDERR) { 65425675Ssam if (dcb->operrsta & (HCRCERR | HCMPERR | UCDATERR | WPTERR | 65525675Ssam DSEEKERR | NOTCYLERR |DRVNRDY | INVDADR)) 65625675Ssam return (DRIVE_ERROR); 65725675Ssam if (dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM)) 65825675Ssam return (CTLR_ERROR); 65925675Ssam return (HARD_DATA_ERROR); 66025675Ssam } 66125675Ssam if (dcb->operrsta & SFTERR) 66225675Ssam return (SOFT_DATA_ERROR); 66325675Ssam return (0); 66425675Ssam } 66525675Ssam 66625675Ssam /* 66725675Ssam * Report a hard error. 66825675Ssam */ 66925675Ssam vdhard_error(ci, bp, dcb) 67025675Ssam ctlr_tab *ci; 67125675Ssam register struct buf *bp; 67225675Ssam register fmt_dcb *dcb; 67325675Ssam { 67425675Ssam unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)]; 67525675Ssam 67625675Ssam bp->b_flags |= B_ERROR; 67725675Ssam harderr(bp, ui->info.type_name); 67825675Ssam printf("status %x", dcb->operrsta); 67925675Ssam if (ci->ctlr_type == SMD_ECTLR) 68025675Ssam printf(" ecode %x", dcb->err_code); 68125675Ssam printf("\n"); 68225675Ssam } 68325675Ssam 68425675Ssam /* 68525675Ssam * Report a soft error. 68625675Ssam */ 68725675Ssam vdsoft_error(ci, bp, dcb) 68825675Ssam ctlr_tab *ci; 68925675Ssam register struct buf *bp; 69025675Ssam register fmt_dcb *dcb; 69125675Ssam { 69225675Ssam unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)]; 69325675Ssam 69425675Ssam printf("%s%d%c: soft error sn%d status %x", ui->info.type_name, 69525857Ssam minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno, 69625675Ssam dcb->operrsta); 69725675Ssam if (ci->ctlr_type == SMD_ECTLR) 69825675Ssam printf(" ecode %x", dcb->err_code); 69925675Ssam printf("\n"); 70025675Ssam } 70125675Ssam 70225675Ssam /*ARGSUSED*/ 70325675Ssam vdopen(dev, flag) 70425675Ssam dev_t dev; 70525675Ssam int flag; 70625675Ssam { 70725675Ssam register unit = VDUNIT(dev); 70825675Ssam register struct vba_device *vi = vddinfo[unit]; 70925675Ssam 71025675Ssam if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv) 71125675Ssam return (ENXIO); 71225675Ssam if (vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0) 71325675Ssam return (ENXIO); 71425675Ssam return (0); 71525675Ssam } 71625675Ssam 71724004Ssam vdread(dev, uio) 71825675Ssam dev_t dev; 71925675Ssam struct uio *uio; 72024004Ssam { 72124004Ssam register int unit = VDUNIT(dev); 72225675Ssam register unit_tab *ui = &vdunit_info[unit]; 72324004Ssam 724*29564Ssam if (unit >= NDK) 72525675Ssam return (ENXIO); 72625675Ssam return (physio(vdstrategy, &ui->raw_q_element, dev, B_READ, 72725675Ssam minphys, uio)); 72824004Ssam } 72924004Ssam 73024004Ssam vdwrite(dev, uio) 73125675Ssam dev_t dev; 73225675Ssam struct uio *uio; 73324004Ssam { 73424004Ssam register int unit = VDUNIT(dev); 73525675Ssam register unit_tab *ui = &vdunit_info[unit]; 73624004Ssam 737*29564Ssam if (unit >= NDK) 73825675Ssam return (ENXIO); 73925675Ssam return (physio(vdstrategy, &ui->raw_q_element, dev, B_WRITE, 74025675Ssam minphys, uio)); 74124004Ssam } 74224004Ssam 74324004Ssam /* 74425675Ssam * Crash dump. 74524004Ssam */ 74625675Ssam vddump(dev) 74725675Ssam dev_t dev; 74824004Ssam { 74925675Ssam register int unit = VDUNIT(dev); 75025675Ssam register unit_tab *ui = &vdunit_info[unit]; 75125675Ssam register fs_tab *fs = &ui->info; 75225675Ssam register int ctlr = vddinfo[unit]->ui_ctlr; 75325675Ssam register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr]; 75425675Ssam register int filsys = FILSYS(dev); 75525675Ssam register cdr *addr = (cdr *)(vba_vdctlr_info->um_addr); 75625675Ssam register int cur_blk, blkcount, blocks; 75725675Ssam caddr_t memaddr; 75824004Ssam 75925675Ssam vdreset_ctlr(addr, ctlr); 76024004Ssam blkcount = maxfree - 2; /* In 1k byte pages */ 76125675Ssam if (dumplo + blkcount > fs->partition[filsys].par_len) { 76225675Ssam blkcount = fs->partition[filsys].par_len - dumplo; 76325675Ssam printf("vd%d: Dump truncated to %dMB\n", unit, blkcount/1024); 76425675Ssam } 76525675Ssam cur_blk = fs->partition[filsys].par_start + dumplo; 76625675Ssam memaddr = 0; 76724004Ssam while (blkcount > 0) { 76825675Ssam blocks = MIN(blkcount, DUMPSIZE); 76925675Ssam if (!vdwrite_block(addr, ctlr, unit, memaddr, cur_blk, blocks)) 77025675Ssam return (EIO); 77125675Ssam blkcount -= blocks; 77225675Ssam memaddr += blocks * NBPG; 77325675Ssam cur_blk += blocks; 77424004Ssam } 77525675Ssam return (0); 77624004Ssam } 77724004Ssam 77825675Ssam /* 77925675Ssam * Write a block to disk during a crash dump. 78025675Ssam */ 78125675Ssam vdwrite_block(caddr, ctlr, unit, addr, block, blocks) 78225675Ssam register cdr *caddr; 78325675Ssam register int ctlr, unit; 78425675Ssam register caddr_t addr; 78525675Ssam register int block, blocks; 78624004Ssam { 78725925Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 78825925Ssam register fmt_mdcb *mdcb = &ci->ctlr_mdcb; 78925925Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 79025675Ssam register unit_tab *ui = &vdunit_info[unit]; 79125675Ssam register fs_tab *fs = &ui->info; 79224004Ssam 79325675Ssam block *= (int)ui->sec_per_blk; 79425675Ssam blocks *= (int)ui->sec_per_blk; 79525675Ssam mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb)); 79625675Ssam dcb->intflg = NOINT; 79725675Ssam dcb->opcode = WD; 79825675Ssam dcb->operrsta = 0; 79925675Ssam dcb->devselect = (char)(vddinfo[unit])->ui_slave; 80025675Ssam dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long)); 80125675Ssam dcb->trail.rwtrail.memadr = addr; 80225675Ssam dcb->trail.rwtrail.wcount = (short) 80325675Ssam ((blocks * fs->secsize)/ sizeof (short)); 80425675Ssam dcb->trail.rwtrail.disk.cylinder = (short)(block / ui->sec_per_cyl); 80525675Ssam dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak); 80625675Ssam dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec); 80725925Ssam VDDC_ATTENTION(caddr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type); 80825925Ssam if (!vdpoll(ci, caddr, 5)) { 80925675Ssam printf(" during dump\n"); 81025675Ssam return (0); 81125675Ssam } 81225675Ssam if (dcb->operrsta & HRDERR) { 81325675Ssam printf("vd%d: hard error, status %x\n", unit, dcb->operrsta); 81425675Ssam return (0); 81525675Ssam } 81625675Ssam return (1); 81724004Ssam } 81824004Ssam 81924004Ssam vdsize(dev) 82025675Ssam dev_t dev; 82124004Ssam { 82225675Ssam struct vba_device *vi = vddinfo[VDUNIT(dev)]; 82324004Ssam 82425675Ssam if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv) 82525675Ssam return (-1); 82625675Ssam return (vdunit_info[VDUNIT(dev)].info.partition[FILSYS(dev)].par_len); 82724004Ssam } 82824004Ssam 82925675Ssam /* 83025675Ssam * Perform a controller reset. 83125675Ssam */ 83225675Ssam vdreset_ctlr(addr, ctlr) 83325675Ssam register cdr *addr; 83425675Ssam register int ctlr; 83524004Ssam { 83625675Ssam register struct buf *cq = &vdminfo[ctlr]->um_tab; 83725675Ssam register struct buf *uq = cq->b_forw; 83825675Ssam register ctlr_tab *ci = &vdctlr_info[ctlr]; 83925675Ssam 84025675Ssam VDDC_RESET(addr, ci->ctlr_type); 84125675Ssam ci->ctlr_started = 0; 84225675Ssam if (ci->ctlr_type == SMD_ECTLR) { 84325675Ssam addr->cdr_csr = 0; 84425675Ssam addr->mdcb_tcf = AM_ENPDA; 84525675Ssam addr->dcb_tcf = AM_ENPDA; 84625675Ssam addr->trail_tcf = AM_ENPDA; 84725675Ssam addr->data_tcf = AM_ENPDA; 84825675Ssam addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD | 84925675Ssam CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; 85025675Ssam } 85125675Ssam if (vdnotrailer(addr, ctlr, 0, INIT, 10) & HRDERR) { 85225675Ssam printf("failed to init\n"); 85325675Ssam return (0); 85425675Ssam } 85525675Ssam if (vdnotrailer(addr, ctlr, 0, DIAG, 10) & HRDERR) { 85625675Ssam printf("diagnostic error\n"); 85725675Ssam return (0); 85825675Ssam } 85925675Ssam /* reset all units attached to controller */ 86025675Ssam uq = cq->b_forw; 86125675Ssam do { 86225675Ssam reset_drive(addr, ctlr, uq->b_dev, 0); 86325675Ssam uq = uq->b_forw; 86425675Ssam } while (uq != cq->b_forw); 86525675Ssam return (1); 86625675Ssam } 86724004Ssam 86825675Ssam /* 86925675Ssam * Perform a reset on a drive. 87025675Ssam */ 87125675Ssam reset_drive(addr, ctlr, slave, start) 87225675Ssam register cdr *addr; 87325675Ssam register int ctlr, slave, start; 87425675Ssam { 87525675Ssam register int type = vdctlr_info[ctlr].unit_type[slave]; 87625675Ssam 87725675Ssam if (type == UNKNOWN) 87825675Ssam return; 87925675Ssam if (!vdconfigure_drive(addr, ctlr, slave, type, start)) 88025675Ssam printf("vd%d: drive %d: couldn't reset\n", ctlr, slave); 88125675Ssam } 88225675Ssam 88325925Ssam /* 88425925Ssam * Poll controller until operation completes 88525925Ssam * or timeout expires. 88625925Ssam */ 88725925Ssam vdpoll(ci, addr, t) 88825925Ssam register ctlr_tab *ci; 88925925Ssam register cdr *addr; 89025925Ssam register int t; 89125925Ssam { 89225925Ssam register fmt_dcb *dcb = &ci->ctlr_dcb; 89325925Ssam 89425925Ssam t *= 1000; 89525925Ssam uncache(&dcb->operrsta); 89625925Ssam while ((dcb->operrsta&(DCBCMP|DCBABT)) == 0) { 89725925Ssam DELAY(1000); 89825925Ssam uncache(&dcb->operrsta); 89925925Ssam if (--t <= 0) { 90025925Ssam printf("vd%d: controller timeout", ci-vdctlr_info); 90125925Ssam VDDC_ABORT(addr, ci->ctlr_type); 90225925Ssam DELAY(30000); 90325925Ssam uncache(&dcb->operrsta); 90425925Ssam return (0); 90525925Ssam } 90625925Ssam } 90725925Ssam if (ci->ctlr_type == SMD_ECTLR) { 90825925Ssam uncache(&addr->cdr_csr); 90925925Ssam while (addr->cdr_csr&CS_GO) { 91025925Ssam DELAY(50); 91125925Ssam uncache(&addr->cdr_csr); 91225925Ssam } 91325925Ssam DELAY(300); 91425925Ssam } 91525925Ssam DELAY(200); 91625925Ssam uncache(&dcb->operrsta); 91725925Ssam return (1); 91825925Ssam } 91925925Ssam 92025675Ssam #ifdef notdef 92125675Ssam /* 92225675Ssam * Dump the mdcb and DCB for diagnostic purposes. 92325675Ssam */ 92425675Ssam vdprintdcb(lp) 92525675Ssam register long *lp; 92625675Ssam { 92725675Ssam register int i, dcb, tc; 92825675Ssam 92925675Ssam for (dcb = 0; lp; lp = (long *)(*lp), dcb++) { 93025675Ssam lp = (long *)((long)lp | 0xc0000000); 93125675Ssam printf("\nDump of dcb%d@%x:", dcb, lp); 93225675Ssam for (i = 0, tc = lp[3] & 0xff; i < tc+7; i++) 93325675Ssam printf(" %lx", lp[i]); 93425675Ssam printf("\n"); 93524004Ssam } 93625675Ssam DELAY(1750000); 93724004Ssam } 93824004Ssam #endif 93925675Ssam #endif 940