/* * RP disk driver */ #include "../h/param.h" #include "../h/systm.h" #include "../h/buf.h" #include "../h/dir.h" #include "../h/conf.h" #include "../h/user.h" struct device { int rpds; int rper; union { int w; char c; } rpcs; int rpwc; char *rpba; int rpca; int rpda; }; #define RPADDR ((struct device *) 0176710) #define NRP 2 /* char rp_tr 0; */ /* tells iostat RP03 xfer rate */ struct { daddr_t nblocks; int cyloff; } rp_sizes[] = { 9600, 0, /* cyl 0- 47, root file system */ 8000, 48, /* cyl 48- 87, swap area */ 7400, 88, /* cyl 88-124, /sys (system sources) */ 55000, 125, /* cyl 125-399, /usr (users + sources) */ 80000, 0, /* cyl 0-399, users- all of RP03 pack */ 0, 0, 0, 0, 0, 0, }; char rp_opn; struct buf rptab; struct buf rrpbuf; #define GO 01 #define RESET 0 #define HSEEK 014 #define IENABLE 0100 #define READY 0200 #define RCOM 4 #define WCOM 2 #define SUFU 01000 #define SUSU 02000 #define SUSI 04000 #define HNF 010000 /* * Use av_back to save track+sector, * b_resid for cylinder. */ #define trksec av_back #define cylin b_resid /* * Monitoring device number * and iostat structure. */ struct ios rp_ios[NRP]; #define DK_N 4 #define DK_T 8 /* RP03 transfer rate indicator */ rpstrategy(bp) register struct buf *bp; { register struct buf *dp; register int unit; long sz; if(bp->b_flags&B_PHYS) mapalloc(bp); unit = minor(bp->b_dev); sz = bp->b_bcount; sz = (sz+511)>>9; if (unit >= (NRP<<3) || bp->b_blkno+sz >= rp_sizes[unit&07].nblocks) { bp->b_flags |= B_ERROR; iodone(bp); return; } bp->av_forw = NULL; unit >>= 3; if(rp_opn == 0) { rp_opn++; spl6(); dk_iop[DK_N] = &rp_ios[0]; dk_nd[DK_N] = NRP; } spl5(); dp = & rptab; if (dp->b_actf == NULL) dp->b_actf = bp; else dp->b_actl->av_forw = bp; dp->b_actl = bp; if (dp->b_active == NULL) rpstart(); spl0(); } rpstart() { register struct buf *bp; register int unit; int com,cn,tn,sn,dn; daddr_t bn; if ((bp = rptab.b_actf) == NULL) return; rptab.b_active++; unit = minor(bp->b_dev); dn = unit>>3; bn = bp->b_blkno; cn = bn/(20*10) + rp_sizes[unit&07].cyloff; sn = bn%(20*10); tn = sn/10; sn = sn%10; RPADDR->rpcs.w = (dn<<8); RPADDR->rpda = (tn<<8) | sn; RPADDR->rpca = cn; RPADDR->rpba = bp->b_un.b_addr; RPADDR->rpwc = -(bp->b_bcount>>1); com = ((bp->b_xmem&3)<<4) | IENABLE | GO; if (bp->b_flags & B_READ) com |= RCOM; else com |= WCOM; RPADDR->rpcs.w |= com; rp_ios[dn].dk_tr = DK_T; rp_ios[dn].dk_busy++; /* drive active */ rp_ios[dn].dk_numb++; /* count number of xfer's */ unit = bp->b_bcount>>6; rp_ios[dn].dk_wds += unit; /* count words xfer'd */ } rpintr() { register struct buf *bp; register int ctr; if (rptab.b_active == NULL) return; bp = rptab.b_actf; ctr = (bp->b_dev >> 3) & 7; rp_ios[ctr].dk_busy = 0; /* drive no longer active */ rptab.b_active = NULL; if (RPADDR->rpcs.w < 0) { /* error bit */ deverror(bp, RPADDR->rper, RPADDR->rpds); if(RPADDR->rpds & (SUFU|SUSI|HNF)) { RPADDR->rpcs.c = HSEEK|GO; ctr = 0; while ((RPADDR->rpds&SUSU) && --ctr) ; } RPADDR->rpcs.w = RESET|GO; ctr = 0; while ((RPADDR->rpcs.w&READY) == 0 && --ctr) ; if (++rptab.b_errcnt <= 10) { rpstart(); return; } bp->b_flags |= B_ERROR; } rptab.b_errcnt = 0; rptab.b_actf = bp->av_forw; bp->b_resid = 0; iodone(bp); rpstart(); } rpread(dev) { physio(rpstrategy, &rrpbuf, dev, B_READ); } rpwrite(dev) { physio(rpstrategy, &rrpbuf, dev, B_WRITE); }