/*#define HOWFAR*/ #define INTSON /* defined for an interrupting disk */ /* * Corvus Disk System */ #include "sys/param.h" #include "sys/config.h" #include "sys/mmu.h" #include "sys/types.h" #include "sys/sysmacros.h" #include "sys/dir.h" #include "sys/signal.h" #include "sys/user.h" #include "sys/errno.h" #include "sys/utsname.h" #include "sys/buf.h" #include "sys/elog.h" #include "sys/erec.h" #include "sys/iobuf.h" #include "sys/systm.h" #include "sys/var.h" #include "sys/altblk.h" #include "sys/diskformat.h" #include "setjmp.h" #include "sys/cops.h" #include "sys/pport.h" #include "sys/d_profile.h" #include "sys/cv.h" #include "sys/swapsz.h" #ifdef notdef /* defined in d_profile.h */ #define logical(x) (minor(x) & 7) /* eight logicals per phys */ #define interleave(x) (minor(x) & 0x8) /* interleave bit for swapping */ #define physical(x) ((minor(x) & 0xF0) >> 4)/* 10 physical devs */ #endif #define cv_addr(d) (prodata[d].pd_da) #define cvwait(a) while(((a)->d_irb & ST_BUSY) == 0) /* * the total space on the corvus h series is: * 306 cylinders are there but corvus reserves 2 * 304 cylinders * 20 sectors per track * 6 heads = * 36480 * * The first 100 blocks are reserved for the boot program and * are inaccessible via unix. */ #define MAXBOOT 100 struct cv_sizes { daddr_t sz_offset; daddr_t sz_size; } cv_sizes[] = { CVNSWAP+101, 32420, /* a: root filesystem */ 101, CVNSWAP, /* b: swap area (3959 blocks) */ 0, 0, /* c: unused */ 0, 0, /* d: unused */ 0, 0, /* e: unused */ 0, 0, /* f: unused */ 0, 0, /* g: unused */ 101, 1000000 /* h: filesystem using entire disk */ }; struct iostat cvstat[NPPDEVS]; struct iobuf cvtab = tabinit(CV2,cvstat); /* active buffer header */ struct buf cvrbuf; /* * cvopen - check for existence of controller */ cvopen(dev) register dev; { register punit; register struct device_d *devp; int cvint(); extern char slot[]; punit = physical(dev); if (punit) { /* for expansion slot check slot number and type */ if (!PPOK(punit) || (slot[PPSLOT(punit)] != PR0)) { u.u_error = ENXIO; return 1; } } devp = pro_da[punit]; u.u_error = 0; if (iocheck(&devp->d_ifr)) { /* board there ? */ if (cv_addr(punit) != devp) { /* not already setup */ if (setppint((cv_addr(punit) = devp),cvint)) goto fail; if (cvinit(&prodata[punit])) { freeppin(devp); goto fail; } } } else { fail: u.u_error = ENXIO; cv_addr(punit) = (struct device_d *)0; return 1; } return 0; } /* * cvinit - initialize drive first time */ cvinit(p) register struct prodata *p; { register struct device_d *devp = p->pd_da; register char irb; register char zero = 0; int pl; pl = spl6(); if (devp == PPADDR) { devp->d_ddrb &= 0x5C; /* port B bits: 0,1,5,7 to in, 2,3,4,6 to out */ devp->d_pcr = 0x6B; /* set controller CA2 pulse mode strobe */ devp->d_ddra = zero; /* set port A bits to input **/ devp->d_irb |= CMD|DRW; /* set command = false set direction = in */ devp->d_ddrb |= 0x7C; devp->d_irb &= ~DEN; /* set enable = true */ } else { devp->d_pcr = 0x6B; /* set controller CA2 pulse mode strobe */ devp->d_ddra = zero; /* set port A bits to input **/ devp->d_irb = CMD|DRW; /* set command = false set direction = in */ devp->d_ddrb = 0x7C; } #ifdef INTSON devp->d_ier = FIRQ|FCA1; irb = devp->d_irb; #ifdef lint pl = irb; #endif lint p->pd_state = SCMD; #endif INTSON splx(pl); return 0; } cvstrategy(bp) register struct buf *bp; { register punit, lunit, bn; punit = physical(bp->b_dev); lunit = logical(bp->b_dev); bn = bp->b_blkno + cv_sizes[lunit].sz_offset; if (bp->b_blkno < 0 || bn <= MAXBOOT) { #ifdef HOWFAR prdev("cvstrategy: illegal blkno", bp->b_dev); printf("blkno=%d bcount=%d\n", bp->b_blkno, bp->b_bcount); #endif HOWFAR bp->b_flags |= B_ERROR; iodone(bp); return; } cvstat[punit].io_ops++; #ifdef INTSON bp->b_resid = bn; /* resid for disksort */ SPL6(); disksort(&cvtab, bp); #else INTSON bp->av_forw = (struct buf *)NULL; /* last of all bufs */ if (cvtab.b_actf == NULL) cvtab.b_actf = bp; /* empty - put on front */ else cvtab.b_actl->av_forw = bp; /* else put at end */ cvtab.b_actl = bp; #endif INTSON if (cvtab.b_active == 0) cvstart(); #ifdef INTSON SPL0(); #else INTSON while (cvtab.b_active) cvint(); #endif INTSON return; } cvstart() { register struct buf *bp; register lunit, offset, bn; register struct device_d *addr; loop: if ((bp = cvtab.b_actf) == (struct buf *)NULL) return; if (cvtab.b_active == 0) { bp->b_resid = bp->b_bcount; cvtab.b_active = 1; } lunit = logical(bp->b_dev); blkacty |= (1<b_bcount - bp->b_resid; bn = bp->b_blkno + btod(offset); /* logical block number */ if (bp->b_resid < BSIZE || bn >= cv_sizes[lunit].sz_size) { next: #ifdef HOWFAR if (bp->b_resid != 0) printf("Unix cvstart: blkno=%d resid=%d bn=%d\n", bp->b_blkno, bp->b_resid, bn); #endif HOWFAR blkacty &= ~(1<b_dev)); addr->d_ifr = addr->d_ifr; /* reset intr */ cvtab.b_actf = bp->av_forw; iodone(bp); goto loop; } if (cvrw(minor(bp->b_dev), bn + cv_sizes[lunit].sz_offset, BSIZE, bp->b_flags&B_READ, bp->b_un.b_addr + offset) < 0) { bp->b_flags |= B_ERROR; logberr(&cvtab, 1); /* log fatal error */ goto next; } return; } caddr_t cv_buf; int cv_count; cvrw(dev, blkno, n, flag, buff) register dev; register daddr_t blkno; register n, flag; register caddr_t buff; { register punit; register struct device_d *addr; punit=physical(dev); cv_buf = buff; cv_count = n; if (cvop(punit, 4, flag==B_READ ? N_R512 : N_W512, (blkno>>16 & 0xf)+1, blkno & 0xff, blkno>>8 & 0xff) < 0) goto bad; if (flag == B_WRITE && cvw(punit, buff, n) < 0) goto bad; addr = cv_addr(punit); addr->d_ddra = 0x00; /* data direction port A bits to input */ addr->d_irb |= 0x08; /* bidirectional driver to input */ return 0; bad: #ifdef HOWFAR printf("cvrw: %s error unit=%d blkno=%d n=%d buf=0x%x\n", flag==B_READ?"read":"write", punit, blkno, n, buff); #endif HOWFAR return -1; } /* VARARGS3 */ cvop(unit, na, a) { #ifdef INTSON register s; #endif INTSON register int *ap; register struct device_d *addr = cv_addr(unit); addr->d_ddra = 0xff; /* port A to output */ addr->d_irb &= ~0x08; /* bidirectional driver to output */ ap = &a; if (na-- > 0) { #ifdef INTSON s = spl7(); #endif INTSON cvwait(addr); addr->d_ira = *ap++; #ifdef INTSON splx(s); #endif INTSON } for (; na > 0; na--, ap++) { cvwait(addr); addr->d_ira = *ap; } return 0; } cvint(punit) int punit; { register struct device_d *addr; register struct buf *bp; register char status; (void) spl6(); addr = cv_addr(punit); if (cvtab.b_active == 0) { #ifdef HOWFAR printf("cvint: b_active == 0\n"); #endif HOWFAR if (addr == PPADDR) addr->d_ifr = addr->d_ifr; /* reset intr */ return; } if ((bp = cvtab.b_actf) == (struct buf *)NULL) { #ifdef HOWFAR printf("cvint: b_actf == NULL\n"); #endif HOWFAR if (addr == PPADDR) addr->d_ifr = addr->d_ifr; /* reset intr */ return; } cvwait(addr); if (addr == PPADDR) addr->d_ifr = addr->d_ifr; /* reset intr */ if (status = addr->d_ira) { err: printf("%s error: /dev/c%d%c blkno=%d\n", bp->b_flags&B_READ?"read":"write", punit, 'a'+logical(bp->b_dev), bp->b_blkno); cvlog(status); cv_count = 0; if (++cvtab.b_errcnt > NRETRY) { bp->b_flags |= B_ERROR; logberr(&cvtab, 1); /* log fatal error */ blkacty &= ~(1<av_forw; cvtab.b_active = 0; iodone(bp); } } else if (bp->b_flags&B_READ) if (cvr(punit, (char *)cv_buf, cv_count) < 0) goto err; /* * because a single buffer can take several io operations, * we leave it to cvstart() to figure out when it's done */ bp->b_resid -= cv_count; cvstart(); } cvlog(status) register status; { register struct buf *bp; register struct device_d *addr; register bn, punit, lunit; struct deverreg cvreg[2]; bp = cvtab.b_actf; punit = physical(bp->b_dev); lunit = logical(bp->b_dev); cvtab.io_stp = &cvstat[lunit]; addr = cv_addr(punit); cvreg[0].draddr = (long)&(addr->d_ira); cvreg[0].drvalue = status; cvreg[0].drname = "cv status"; cvreg[0].drbits = "Corvus disk status code"; cvreg[1].draddr = (long)0; cvreg[1].drvalue = cv_count; cvreg[1].drname = "count"; cvreg[1].drbits = "byte count of transfer"; bn = bp->b_blkno + btod(bp->b_bcount - bp->b_resid) + cv_sizes[lunit].sz_offset; fmtberr(&cvtab, (unsigned)punit, (unsigned)0, /* cylinder */ (unsigned)0, /* track */ (unsigned)bn, /* sector */ (long)(sizeof(cvreg)/sizeof(cvreg[0])), /* regcnt */ &cvreg[0],&cvreg[1]); } cvw(unit, buff, n) register char *buff; register n; { register char *ira; register struct device_d *addr = cv_addr(unit); ira = &(addr->d_ira); cvwait(addr); for ( ; n > 0; n--) { if ((addr->d_irb & ST_HTOC) == 0) break; *ira = *buff++; } for (;;) { cvwait(addr); if ((addr->d_irb & ST_HTOC) == 0) break; *ira = 0; } cv_count -= n; if (n > 0) { #ifdef HOWFAR printf("cvw: %d bytes short\n", n); #endif HOWFAR cvlog(0); return -1; } return 0; } cvr(unit, buff, n) register char *buff; register n; { register char *ira; register struct device_d *addr = cv_addr(unit); cvwait(addr); ira = &(addr->d_ira); for ( ; n > 0; n--) { if (addr->d_irb & ST_HTOC) break; *buff++ = *ira; } cv_count -= n; if (n > 0) { #ifdef HOWFAR printf("cvr: %d bytes short\n", n); #endif HOWFAR return -1; } for (;;) { cvwait(addr); if (addr->d_irb & ST_HTOC) break; n = *ira; } return 0; } /******** #ifdef INTSON #else INTSON /* wait for controller to host direction or timeout */ /* cvctoh(a) register struct device_d *a; { register i; for (i = 20; i-- > 0;); i = 100000; do while (--i > 0 && ((a->d_irb&ST_BUSY) == 0)); while (i > 0 && (a->d_irb & ST_HTOC)); if (i <= 0) { printf("cvctoh: timeout\n"); return -1; } return 0; } #endif INTSON ********/ cvread(dev) dev_t dev; { physio(cvstrategy, &cvrbuf, dev, B_READ); } cvwrite(dev) dev_t dev; { physio(cvstrategy, &cvrbuf, dev, B_WRITE); } cvprint(dev, str) char *str; { printf("%s on cv drive %d, slice %d\n", str, (dev>>4)&0xF, dev&7); }