# /* * TM tape driver */ #include "../h/param.h" #include "../h/buf.h" #include "../h/dir.h" #include "../h/conf.h" #include "../h/file.h" #include "../h/user.h" struct device { int tmer; int tmcs; int tmbc; char *tmba; int tmdb; int tmrd; }; struct buf tmtab; struct buf ctmbuf; struct buf rtmbuf; char t_flags[8]; char t_openf[8]; daddr_t t_blkno[8]; daddr_t t_nxrec[8]; #define TMADDR ((struct device *)0172520) #define GO 01 #define RCOM 02 #define WCOM 04 #define WEOF 06 #define NOP 0100 #define SFORW 010 #define SREV 012 #define WIRG 014 #define REW 016 #define DENS 060000 /* 9-channel */ #define IENABLE 0100 #define CRDY 0200 #define GAPSD 010000 #define TUR 1 #define HARD 0102200 /* ILC, EOT, NXM */ #define RLE 0100 #define EOF 0040000 #define WL 04 #define SSEEK 1 #define SIO 2 #define SCOM 3 #define T_WRITTEN 1 tmopen(dev, flag) { register unit, ds; unit = minor(dev) & 0177; if (t_openf[unit]) { u.u_error = ENXIO; return; } t_blkno[unit] = 0; t_nxrec[unit] = 65535; t_flags[unit] = 0; tmtab.b_flags |= B_TAPE; ds = tcommand(dev, NOP); if ((ds&TUR)==0) { printf("mt%d off line\n",unit); u.u_error = ENXIO; } if (flag && ds&WL) { printf("mt%d needs write ring\n",unit); u.u_error = ENXIO; } if (u.u_error==0) t_openf[unit]++; } tmclose(dev, flag) dev_t dev; int flag; { if ( flag == FWRITE || ((flag&FWRITE) && (t_flags[minor(dev)&0177]&T_WRITTEN))) { tcommand(dev, WEOF); tcommand(dev, WEOF); tcommand(dev, SREV); } if ((minor(dev)&0200) == 0) tcommand(dev, REW); t_openf[minor(dev)&077] = 0; } tcommand(dev, com) { register struct buf *bp; bp = &ctmbuf; spl5(); while (bp->b_flags&B_BUSY) { bp->b_flags |= B_WANTED; sleep((caddr_t)bp, PRIBIO); } bp->b_flags = B_BUSY|B_READ; spl0(); bp->b_dev = dev; bp->b_resid = com; bp->b_blkno = 0; tmstrategy(bp); iowait(bp); if (bp->b_flags&B_WANTED) wakeup((caddr_t)bp); bp->b_flags = 0; return(bp->b_resid); } tmstrategy(bp) register struct buf *bp; { register daddr_t *p; if(bp->b_flags&B_PHYS) mapalloc(bp); if (bp != &ctmbuf) { p = &t_nxrec[minor(bp->b_dev)&0177]; if (*p <= bp->b_blkno) { if (*p < bp->b_blkno) { bp->b_flags |= B_ERROR; iodone(bp); return; } if (bp->b_flags&B_READ) { clrbuf(bp); bp->b_resid = 0; iodone(bp); return; } } if ((bp->b_flags&B_READ) == 0) { t_flags[minor(bp->b_dev)&0177] |= T_WRITTEN; *p = bp->b_blkno+1; } } bp->av_forw = 0; spl5(); if (tmtab.b_actf == NULL) tmtab.b_actf = bp; else tmtab.b_actl->av_forw = bp; tmtab.b_actl = bp; if (tmtab.b_active == NULL) tmstart(); spl0(); } tmstart() { register struct buf *bp; register int com; int unit; register daddr_t *blkno; loop: if ((bp = tmtab.b_actf) == 0) return; unit = minor(bp->b_dev)&0177; blkno = &t_blkno[unit]; if (t_openf[unit] < 0 || (TMADDR->tmcs & CRDY) == NULL) { bp->b_flags |= B_ERROR; goto next; } if (bp == &ctmbuf) { if (bp->b_resid == NOP) { bp->b_resid = TMADDR->tmer; goto next; } tmtab.b_active = SCOM; TMADDR->tmcs = DENS|bp->b_resid|GO| (unit<<8) | IENABLE; return; } com = (unit<<8) | ((bp->b_xmem & 03) << 4) | IENABLE|DENS; if (*blkno != bp->b_blkno) { tmtab.b_active = SSEEK; if (*blkno < bp->b_blkno) { com |= SFORW|GO; TMADDR->tmbc = *blkno - bp->b_blkno; } else { if (bp->b_blkno == 0) com |= REW|GO; else { com |= SREV|GO; TMADDR->tmbc = bp->b_blkno - *blkno; } } TMADDR->tmcs = com; return; } tmtab.b_active = SIO; TMADDR->tmbc = -bp->b_bcount; TMADDR->tmba = bp->b_un.b_addr; TMADDR->tmcs = com | ((bp->b_flags&B_READ)? RCOM|GO: ((tmtab.b_errcnt)? WIRG|GO: WCOM|GO)); return; next: tmtab.b_actf = bp->av_forw; iodone(bp); goto loop; } tmintr() { register struct buf *bp; register int unit; int state; if ((bp = tmtab.b_actf) == NULL) return; unit = minor(bp->b_dev)&0177; state = tmtab.b_active; tmtab.b_active = 0; if (TMADDR->tmcs < 0) { /* error bit */ while(TMADDR->tmrd & GAPSD) ; /* wait for gap shutdown */ if (TMADDR->tmer&EOF) { t_nxrec[unit] = bp->b_blkno; state = SCOM; TMADDR->tmbc = -bp->b_bcount; goto out; } if ((TMADDR->tmer&HARD) == 0 && TMADDR->tmer&RLE) { state = SIO; goto out; } if ((TMADDR->tmer&(HARD|EOF)) == NULL && state==SIO) { if (++tmtab.b_errcnt < 2) { t_blkno[unit]++; tmtab.b_active = 0; tmstart(); return; } } else if (t_openf[unit]>0 && bp!=&rtmbuf && (TMADDR->tmer&EOF)==0 ) { t_openf[unit] = -1; deverror(bp, TMADDR->tmer, 0); } bp->b_flags |= B_ERROR; state = SIO; } out: switch ( state ) { case SIO: t_blkno[unit] += (bp->b_bcount>>BSHIFT); case SCOM: tmtab.b_errcnt = 0; tmtab.b_actf = bp->av_forw; bp->b_resid = -TMADDR->tmbc; iodone(bp); break; case SSEEK: t_blkno[unit] = bp->b_blkno; break; default: return; } tmstart(); } tmread(dev) { tmphys(dev); physio(tmstrategy, &rtmbuf, dev, B_READ); } tmwrite(dev) { tmphys(dev); physio(tmstrategy, &rtmbuf, dev, B_WRITE); } tmphys(dev) { register unit; daddr_t a; unit = minor(dev) & 0177; if(unit < 8) { a = u.u_offset >> 9; t_blkno[unit] = a; t_nxrec[unit] = a+1; } }