* THIS HANDLES ONLY ONE DRIVE ON ONE CONTROLER, AS WE HAVE NO
* WAY TO TEST MULTIPLE TRANSPORTS.
#define DELAY(N) { register int d = N; while (--d > 0); }
int tmcntrlr(), tmslave(), tmdgo(), tmintr();
struct uba_minfo
*tmminfo
[NTM03
];
struct uba_dinfo
*tmdinfo
[NTM11
];
u_short tmstd
[] = { 0772520, 0 };
struct uba_driver tmdriver
=
{ tmcntrlr
, tmslave
, tmdgo
, 0, tmstd
, "mt", tmdinfo
, "tm", tmminfo
};
/* bits in minor device */
#define INF (daddr_t)1000000L
#define SSEEK 1 /* seeking */
#define SIO 2 /* doing seq i/o */
#define SCOM 3 /* sending control command */
#define LASTIOW 1 /* last op was a write */
#define WAITREW 2 /* someone is waiting for a rewind */
* Determine if there is a controller for
* a tm at address reg. Our goal is to make the
((struct device
*)reg
)->tmcs
= IENABLE
;
* If this is a tm03/tc11, it ought to have interrupted
* by now, if it isn't (ie: it is a ts04) then we just
* hope that it didn't interrupt, so autoconf will ignore it.
* Just in case, we will reference one
* of the more distant registers, and hope for a machine
* check, or similar disaster if this is a ts.
* Note: on an 11/780, badaddr will just generate
* a uba error for a ts; but our caller will notice that
* so we won't check for it.
if (badaddr(&((struct device
*)reg
)->tmrd
, 2))
* Due to a design flaw, we cannot ascertain if the tape
* exists or not unless it is on line - ie: unless a tape is
* mounted. This is too servere a restriction to bear.
* As we can only handle one tape, we might just as well insist
* that it be slave #0, and just assume that it exists.
* Something better will have to be done if you have two
* tapes on one controller, or two controllers
if (ui
->ui_slave
!= 0 || tmdinfo
[0])
register struct uba_dinfo
*ui
;
register struct tm_softc
*sc
= &tm_softc
[0];
tmminfo
[0]->um_tab
.b_flags
|= B_TAPE
;
if (unit
>=NTM11
|| sc
->sc_openf
|| (ui
= tmdinfo
[0]) == 0 || ui
->ui_alive
==0) {
u
.u_error
= ENXIO
; /* out of range or open */
if ((sc
->sc_erreg
&SELR
) == 0) {
tmwaitrws(dev
); /* wait for rewind complete */
while (sc
->sc_erreg
&SDWN
)
tmcommand(dev
, NOP
, 1); /* await settle down */
if ((sc
->sc_erreg
&TUR
)==0 ||
((flag
&(FREAD
|FWRITE
)) == FWRITE
&& (sc
->sc_erreg
&WRL
))) {
((struct device
*)ui
->ui_addr
)->tmcs
= DCLR
|GO
;
u
.u_error
= EIO
; /* offline or write protect */
uprintf("tape offline or protected\n");
sc
->sc_blkno
= (daddr_t
)0;
register struct device
*addr
=
(struct device
*)tmdinfo
[0]->ui_addr
;
register struct tm_softc
*sc
= &tm_softc
[0];
if ((addr
->tmer
&RWS
) == 0) {
spl0(); /* rewind complete */
sleep((caddr_t
)&sc
->sc_flags
, PRIBIO
);
register struct tm_softc
*sc
= &tm_softc
[0];
if (flag
== FWRITE
|| ((flag
&FWRITE
) && (sc
->sc_flags
&LASTIOW
))) {
if ((minor(dev
)&T_NOREWIND
) == 0)
tmcommand(dev
, com
, count
)
while (bp
->b_flags
&B_BUSY
) {
sleep((caddr_t
)bp
, PRIBIO
);
bp
->b_flags
= B_BUSY
|B_READ
;
if (bp
->b_flags
&B_WANTED
)
register struct buf
*tmi
;
p
= &tm_softc
[0].sc_nxrec
;
if (dbtofsb(bp
->b_blkno
) > *p
) {
bp
->b_error
= ENXIO
; /* past EOF */
} else if (dbtofsb(bp
->b_blkno
) == *p
&& bp
->b_flags
&B_READ
) {
bp
->b_resid
= bp
->b_bcount
;
} else if ((bp
->b_flags
&B_READ
) == 0)
*p
= dbtofsb(bp
->b_blkno
) + 1; /* write sets EOF */
tmi
= &tmminfo
[0]->um_tab
;
tmi
->b_actl
->av_forw
= bp
;
register struct uba_minfo
*um
= tmminfo
[0];
register struct uba_dinfo
*ui
;
register struct device
*addr
;
register struct tm_softc
*sc
= &tm_softc
[0];
if ((bp
= um
->um_tab
.b_actf
) == 0)
addr
= (struct device
*)ui
->ui_addr
;
sc
->sc_dsreg
= addr
->tmcs
;
sc
->sc_erreg
= addr
->tmer
;
sc
->sc_resid
= addr
->tmbc
;
sc
->sc_flags
&= ~LASTIOW
;
if (sc
->sc_openf
< 0 || (addr
->tmcs
&CUR
) == 0) {
/* sc->sc_openf = -1; ??? */
bp
->b_flags
|= B_ERROR
; /* hard error'ed or !SELR */
if ((minor(bp
->b_dev
) & T_1600BPI
) == 0)
if (bp
->b_command
== NOP
)
goto next
; /* just get status */
um
->um_tab
.b_active
= SCOM
;
if (bp
->b_command
== SFORW
|| bp
->b_command
== SREV
)
addr
->tmbc
= bp
->b_repcnt
;
if ((blkno
= sc
->sc_blkno
) == dbtofsb(bp
->b_blkno
)) {
addr
->tmbc
= -bp
->b_bcount
;
if ((bp
->b_flags
&B_READ
) == 0) {
um
->um_tab
.b_active
= SIO
;
um
->um_tab
.b_active
= SSEEK
;
if (blkno
< dbtofsb(bp
->b_blkno
)) {
addr
->tmbc
= blkno
- dbtofsb(bp
->b_blkno
);
addr
->tmbc
= dbtofsb(bp
->b_blkno
) - blkno
;
ubarelse(um
->um_ubanum
, &um
->um_ubinfo
);
um
->um_tab
.b_actf
= bp
->av_forw
;
register struct uba_minfo
*um
;
register struct device
*addr
= (struct device
*)um
->um_addr
;
printf("tmdgo %x %x\n", um
->um_ubinfo
, um
->um_cmd
);
addr
->tmba
= um
->um_ubinfo
;
addr
->tmcs
= um
->um_cmd
| ((um
->um_ubinfo
>> 12) & 0x30);
register struct uba_minfo
*um
= tmminfo
[0];
register struct device
*addr
= (struct device
*)tmdinfo
[0]->ui_addr
;
register struct tm_softc
*sc
= &tm_softc
[0];
printf("tmintr %x %x\n", um
->um_tab
.b_actf
, um
->um_tab
.b_active
);
if (sc
->sc_flags
&WAITREW
&& (addr
->tmer
&RWS
) == 0) {
sc
->sc_flags
&= ~WAITREW
;
wakeup((caddr_t
)&sc
->sc_flags
);
if ((bp
= um
->um_tab
.b_actf
) == NULL
)
sc
->sc_dsreg
= addr
->tmcs
;
sc
->sc_erreg
= addr
->tmer
;
sc
->sc_resid
= addr
->tmbc
;
if ((bp
->b_flags
& B_READ
) == 0)
state
= um
->um_tab
.b_active
;
; /* await settle down */
tmseteof(bp
); /* set blkno and nxrec */
addr
->tmbc
= -bp
->b_bcount
;
if ((bp
->b_flags
&B_READ
) && (addr
->tmer
&(HARD
|SOFT
)) == RLE
)
if ((addr
->tmer
&HARD
)==0 && state
==SIO
) {
if (++um
->um_tab
.b_errcnt
< 7) {
if((addr
->tmer
&SOFT
) == NXM
)
printf("TM UBA late error\n");
ubarelse(um
->um_ubanum
, &um
->um_ubinfo
);
} else if (sc
->sc_openf
>0 && bp
!= &rtmbuf
)
deverror(bp
, sc
->sc_erreg
, sc
->sc_dsreg
);
sc
->sc_blkno
-= bp
->b_repcnt
;
sc
->sc_blkno
+= bp
->b_repcnt
;
if (++bp
->b_repcnt
< 0) {
tmstart(); /* continue */
um
->um_tab
.b_actf
= bp
->av_forw
;
bp
->b_resid
= -addr
->tmbc
;
ubarelse(um
->um_ubanum
, &um
->um_ubinfo
);
sc
->sc_blkno
= dbtofsb(bp
->b_blkno
);
register struct device
*addr
=
(struct device
*)tmdinfo
[0]->ui_addr
;
register struct tm_softc
*sc
= &tm_softc
[0];
if (sc
->sc_blkno
> dbtofsb(bp
->b_blkno
)) {
sc
->sc_nxrec
= dbtofsb(bp
->b_blkno
) - addr
->tmbc
;
sc
->sc_blkno
= sc
->sc_nxrec
;
sc
->sc_blkno
= dbtofsb(bp
->b_blkno
) + addr
->tmbc
;
sc
->sc_nxrec
= sc
->sc_blkno
- 1;
sc
->sc_nxrec
= dbtofsb(bp
->b_blkno
);
physio(tmstrategy
, &rtmbuf
, dev
, B_READ
, minphys
);
physio(tmstrategy
, &rtmbuf
, dev
, B_WRITE
, minphys
);
register struct tm_softc
*sc
= &tm_softc
[0];
a
= dbtofsb(u
.u_offset
>> 9);
tmioctl(dev
, cmd
, addr
, flag
)
register struct tm_softc
*sc
= &tm_softc
[0];
/* we depend of the values and order of the MT codes here */
static tmops
[] = {WEOF
, SFORW
, SREV
, SFORW
, SREV
, REW
, OFFL
, NOP
};
case MTIOCTOP
: /* tape operation */
if (copyin((caddr_t
)addr
, (caddr_t
)&mtop
, sizeof(mtop
))) {
case MTWEOF
: case MTFSF
: case MTBSF
:
callcount
= mtop
.mt_count
;
case MTREW
: case MTOFFL
: case MTNOP
:
if (callcount
<= 0 || fcount
<= 0)
else while (--callcount
>= 0) {
tmcommand(dev
, tmops
[mtop
.mt_op
], fcount
);
if ((mtop
.mt_op
== MTFSR
|| mtop
.mt_op
== MTBSR
) &&
if ((ctmbuf
.b_flags
&B_ERROR
) ||
mtget
.mt_dsreg
= sc
->sc_dsreg
;
mtget
.mt_erreg
= sc
->sc_erreg
;
mtget
.mt_resid
= sc
->sc_resid
;
if (copyout((caddr_t
)&mtget
, addr
, sizeof(mtget
)))
register struct uba_dinfo
*ui
;
register struct uba_regs
*up
;
register struct device
*addr
;
#define phys(a,b) ((b)((int)(a)&0x7fffffff))
ui
= phys(tmdinfo
[0], struct uba_dinfo
*);
up
= phys(ui
->ui_hd
, struct uba_hd
*)->uh_physuba
;
addr
= (struct device
*)ui
->ui_physaddr
;
blk
= num
> DBSIZE
? DBSIZE
: num
;
tmdwrite(start
, blk
, addr
, up
);
tmdwrite(buf
, num
, addr
, up
)
register struct device
*addr
;
*(int *)io
++ = (buf
++ | (1<<UBA_DPSHIFT
) | UBA_MRV
);
addr
->tmbc
= -(num
*NBPG
);
register struct device
*addr
;