xref: /csrg-svn/sys/pmax/dev/tz.c (revision 52130)
1*52130Smckusick /*
2*52130Smckusick  * Copyright (c) 1992 Regents of the University of California.
3*52130Smckusick  * All rights reserved.
4*52130Smckusick  *
5*52130Smckusick  * This code is derived from software contributed to Berkeley by
6*52130Smckusick  * Ralph Campbell.
7*52130Smckusick  *
8*52130Smckusick  * %sccs.include.redist.c%
9*52130Smckusick  *
10*52130Smckusick  *	@(#)tz.c	7.1 (Berkeley) 01/07/92
11*52130Smckusick  *
12*52130Smckusick  * from: $Header: /sprite/src/kernel/dev/RCS/devSCSITape.c,
13*52130Smckusick  *	v 8.14 89/07/31 17:26:13 mendel Exp $ SPRITE (Berkeley)
14*52130Smckusick  */
15*52130Smckusick 
16*52130Smckusick /*
17*52130Smckusick  * SCSI CCS (Command Command Set) tape driver.
18*52130Smckusick  */
19*52130Smckusick #include "tz.h"
20*52130Smckusick #if NTZ > 0
21*52130Smckusick 
22*52130Smckusick #include "param.h"
23*52130Smckusick #include "systm.h"
24*52130Smckusick #include "buf.h"
25*52130Smckusick #include "errno.h"
26*52130Smckusick #include "file.h"
27*52130Smckusick #include "ioctl.h"
28*52130Smckusick #include "mtio.h"
29*52130Smckusick #include "syslog.h"
30*52130Smckusick 
31*52130Smckusick #include "device.h"
32*52130Smckusick #include "scsi.h"
33*52130Smckusick 
34*52130Smckusick int	tzprobe();
35*52130Smckusick void	tzstart(), tzdone();
36*52130Smckusick 
37*52130Smckusick struct	driver tzdriver = {
38*52130Smckusick 	"tz", tzprobe, tzstart, tzdone,
39*52130Smckusick };
40*52130Smckusick 
41*52130Smckusick struct	tz_softc {
42*52130Smckusick 	struct	scsi_device *sc_sd;	/* physical unit info */
43*52130Smckusick 	int	sc_flags;		/* see below */
44*52130Smckusick 	struct	buf sc_tab;		/* queue of pending operations */
45*52130Smckusick 	struct	buf sc_buf;		/* buf for doing I/O */
46*52130Smckusick 	struct	buf sc_errbuf;		/* buf for doing REQUEST_SENSE */
47*52130Smckusick 	struct	ScsiCmd sc_cmd;		/* command for controller */
48*52130Smckusick 	ScsiGroup0Cmd sc_rwcmd;		/* SCSI cmd for read/write */
49*52130Smckusick 	struct	scsi_fmt_cdb sc_cdb;	/* SCSI cmd if not read/write */
50*52130Smckusick 	struct	scsi_fmt_sense sc_sense;	/* sense data from last cmd */
51*52130Smckusick } tz_softc[NTZ];
52*52130Smckusick 
53*52130Smckusick /* sc_flags values */
54*52130Smckusick #define	TZF_ALIVE		0x01	/* drive found and ready */
55*52130Smckusick #define	TZF_SENSEINPROGRESS	0x02	/* REQUEST_SENSE command in progress */
56*52130Smckusick #define	TZF_ALTCMD		0x04	/* alternate command in progress */
57*52130Smckusick #define	TZF_WRITTEN		0x08	/* tape has been written to */
58*52130Smckusick #define	TZF_OPEN		0x10	/* device is open */
59*52130Smckusick #define	TZF_WAIT		0x20	/* waiting for sc_tab to drain */
60*52130Smckusick 
61*52130Smckusick /* bits in minor device */
62*52130Smckusick #define	tzunit(x)	(minor(x) >> 1)	/* tz%d unit number */
63*52130Smckusick #define TZ_NOREWIND	0x1		/* don't rewind on close */
64*52130Smckusick 
65*52130Smckusick #define	INF	(daddr_t)1000000L	/* a block number that won't exist */
66*52130Smckusick 
67*52130Smckusick #ifdef DEBUG
68*52130Smckusick int	tzdebug = 1;
69*52130Smckusick #endif
70*52130Smckusick 
71*52130Smckusick /*
72*52130Smckusick  * Test to see if device is present.
73*52130Smckusick  * Return true if found and initialized ok.
74*52130Smckusick  */
75*52130Smckusick tzprobe(sd)
76*52130Smckusick 	struct scsi_device *sd;
77*52130Smckusick {
78*52130Smckusick 	register struct tz_softc *sc = &tz_softc[sd->sd_unit];
79*52130Smckusick 	register int i;
80*52130Smckusick 	ScsiInquiryData inqbuf;
81*52130Smckusick 	ScsiClass7Sense *sp;
82*52130Smckusick 
83*52130Smckusick 	printf("tzprobe()\n"); /* XXX */
84*52130Smckusick 	/* init some parameters that don't change */
85*52130Smckusick 	sc->sc_sd = sd;
86*52130Smckusick 	sc->sc_cmd.sd = sd;
87*52130Smckusick 	sc->sc_cmd.unit = sd->sd_unit;
88*52130Smckusick 	sc->sc_rwcmd.unitNumber = sd->sd_slave;
89*52130Smckusick /*	sc->sc_rwcmd.highAddr = 1;	/* count in blocks */
90*52130Smckusick 
91*52130Smckusick 	/* try to find out what type of device this is */
92*52130Smckusick 	sc->sc_flags = TZF_ALTCMD;	/* force use of sc_cdb */
93*52130Smckusick 	sc->sc_cdb.len = sizeof(ScsiGroup0Cmd);
94*52130Smckusick 	scsiGroup0Cmd(SCSI_INQUIRY, sd->sd_slave, 0, sizeof(inqbuf),
95*52130Smckusick 		(ScsiGroup0Cmd *)sc->sc_cdb.cdb);
96*52130Smckusick 	sc->sc_buf.b_flags = B_BUSY | B_READ;
97*52130Smckusick 	sc->sc_buf.b_bcount = sizeof(inqbuf);
98*52130Smckusick 	sc->sc_buf.b_un.b_addr = (caddr_t)&inqbuf;
99*52130Smckusick 	sc->sc_buf.av_forw = (struct buf *)0;
100*52130Smckusick 	sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf;
101*52130Smckusick 	tzstart(sd->sd_unit);
102*52130Smckusick 	if (biowait(&sc->sc_buf) ||
103*52130Smckusick 	    (i = sizeof(inqbuf) - sc->sc_buf.b_resid) < 5)
104*52130Smckusick 		goto bad;
105*52130Smckusick 	if (inqbuf.type != SCSI_TAPE_TYPE)
106*52130Smckusick 		goto bad;
107*52130Smckusick 
108*52130Smckusick 	/* check for device ready to clear UNIT_ATTN */
109*52130Smckusick 	sc->sc_cdb.len = sizeof(ScsiGroup0Cmd);
110*52130Smckusick 	scsiGroup0Cmd(SCSI_TEST_UNIT_READY, sd->sd_slave, 0, 0,
111*52130Smckusick 		(ScsiGroup0Cmd *)sc->sc_cdb.cdb);
112*52130Smckusick 	sc->sc_buf.b_flags = B_BUSY | B_READ;
113*52130Smckusick 	sc->sc_buf.b_bcount = 0;
114*52130Smckusick 	sc->sc_buf.b_un.b_addr = (caddr_t)0;
115*52130Smckusick 	sc->sc_buf.av_forw = (struct buf *)0;
116*52130Smckusick 	sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf;
117*52130Smckusick 	tzstart(sd->sd_unit);
118*52130Smckusick 	(void) biowait(&sc->sc_buf);
119*52130Smckusick 
120*52130Smckusick 	sc->sc_flags = TZF_ALIVE;
121*52130Smckusick 	sc->sc_buf.b_flags = 0;
122*52130Smckusick 	printf("tz%d at %s%d drive %d slave %d\n", sd->sd_unit,
123*52130Smckusick 		sd->sd_cdriver->d_name, sd->sd_ctlr, sd->sd_drive,
124*52130Smckusick 		sd->sd_slave);
125*52130Smckusick 	return (1);
126*52130Smckusick 
127*52130Smckusick bad:
128*52130Smckusick 	/* doesn't exist or not a CCS device */
129*52130Smckusick 	sc->sc_flags = 0;
130*52130Smckusick 	sc->sc_buf.b_flags = 0;
131*52130Smckusick 	return (0);
132*52130Smckusick }
133*52130Smckusick 
134*52130Smckusick /*
135*52130Smckusick  * Perform a special tape command on a SCSI Tape drive.
136*52130Smckusick  */
137*52130Smckusick tzcommand(dev, command, code, count)
138*52130Smckusick 	dev_t dev;
139*52130Smckusick 	int command;
140*52130Smckusick 	int code;
141*52130Smckusick 	int count;
142*52130Smckusick {
143*52130Smckusick 	register struct tz_softc *sc = &tz_softc[tzunit(dev)];
144*52130Smckusick 	int s, error;
145*52130Smckusick 
146*52130Smckusick 	s = splbio();
147*52130Smckusick 	while (sc->sc_tab.b_actf) {
148*52130Smckusick 		sc->sc_flags |= TZF_WAIT;
149*52130Smckusick 		sleep(&sc->sc_flags, PZERO);
150*52130Smckusick 	}
151*52130Smckusick 	sc->sc_flags |= TZF_ALTCMD;	/* force use of sc_cdb */
152*52130Smckusick 	sc->sc_cdb.len = sizeof(ScsiGroup0Cmd);
153*52130Smckusick 	scsiGroup0Cmd(command, sc->sc_sd->sd_slave,
154*52130Smckusick 		(code << 16) | ((count >> 8) & 0xFFFF), count & 0xFF,
155*52130Smckusick 		(ScsiGroup0Cmd *)sc->sc_cdb.cdb);
156*52130Smckusick 	sc->sc_buf.b_flags = B_BUSY | B_READ;
157*52130Smckusick 	sc->sc_buf.b_bcount = 0;
158*52130Smckusick 	sc->sc_buf.b_un.b_addr = (caddr_t)0;
159*52130Smckusick 	sc->sc_buf.av_forw = (struct buf *)0;
160*52130Smckusick 	sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf;
161*52130Smckusick 	tzstart(sc->sc_sd->sd_unit);
162*52130Smckusick 	error = biowait(&sc->sc_buf);
163*52130Smckusick 	sc->sc_flags &= ~TZF_ALTCMD;	/* force use of sc_cdb */
164*52130Smckusick 	sc->sc_buf.b_flags = 0;
165*52130Smckusick 	splx(s);
166*52130Smckusick 	return (error);
167*52130Smckusick }
168*52130Smckusick 
169*52130Smckusick void
170*52130Smckusick tzstart(unit)
171*52130Smckusick 	int unit;
172*52130Smckusick {
173*52130Smckusick 	register struct tz_softc *sc = &tz_softc[unit];
174*52130Smckusick 	register struct buf *bp = sc->sc_tab.b_actf;
175*52130Smckusick 	register int n;
176*52130Smckusick 	extern int sii_debug; /* XXX */
177*52130Smckusick 
178*52130Smckusick 	sc->sc_cmd.buf = bp->b_un.b_addr;
179*52130Smckusick 	sc->sc_cmd.buflen = bp->b_bcount;
180*52130Smckusick 
181*52130Smckusick 	if (sc->sc_flags & (TZF_SENSEINPROGRESS | TZF_ALTCMD)) {
182*52130Smckusick 		sc->sc_cmd.dataToDevice = !(bp->b_flags & B_READ);
183*52130Smckusick 		sc->sc_cmd.cmd = sc->sc_cdb.cdb;
184*52130Smckusick 		sc->sc_cmd.cmdlen = sc->sc_cdb.len;
185*52130Smckusick 	} else {
186*52130Smckusick 		if (bp->b_flags & B_READ) {
187*52130Smckusick 			sc->sc_cmd.dataToDevice = 0;
188*52130Smckusick 			sc->sc_rwcmd.command = SCSI_READ;
189*52130Smckusick 		} else {
190*52130Smckusick 			sc->sc_cmd.dataToDevice = 1;
191*52130Smckusick 			sc->sc_rwcmd.command = SCSI_WRITE;
192*52130Smckusick 		}
193*52130Smckusick 		sc->sc_cmd.cmd = (u_char *)&sc->sc_rwcmd;
194*52130Smckusick 		sc->sc_cmd.cmdlen = sizeof(sc->sc_rwcmd);
195*52130Smckusick 		n = howmany(bp->b_bcount, 512);
196*52130Smckusick 		sc->sc_rwcmd.midAddr = n >> 16;
197*52130Smckusick 		sc->sc_rwcmd.lowAddr = n >> 8;
198*52130Smckusick 		sc->sc_rwcmd.blockCount = n;
199*52130Smckusick 		if ((bp->b_bcount & (512 - 1)) != 0)
200*52130Smckusick 			printf("tz%d: partial block xfer -- %x bytes\n",
201*52130Smckusick 				unit, bp->b_bcount);
202*52130Smckusick 	}
203*52130Smckusick 
204*52130Smckusick 	printf("tzstart(%d) flags %x, addr %x sz %d\n", unit,
205*52130Smckusick 		sc->sc_flags, sc->sc_cmd.buf, sc->sc_cmd.buflen); /* XXX */
206*52130Smckusick 	/* tell controller to start this command */
207*52130Smckusick 	if (sc->sc_cmd.cmd[0] == SCSI_READ)
208*52130Smckusick 		sii_debug = 5; /* XXX */
209*52130Smckusick 	(*sc->sc_sd->sd_cdriver->d_start)(&sc->sc_cmd);
210*52130Smckusick }
211*52130Smckusick 
212*52130Smckusick /*
213*52130Smckusick  * This is called by the controller driver when the command is done.
214*52130Smckusick  */
215*52130Smckusick void
216*52130Smckusick tzdone(unit, error, resid, status)
217*52130Smckusick 	int unit;
218*52130Smckusick 	int error;		/* error number from errno.h */
219*52130Smckusick 	int resid;		/* amount not transfered */
220*52130Smckusick 	int status;		/* SCSI status byte */
221*52130Smckusick {
222*52130Smckusick 	register struct tz_softc *sc = &tz_softc[unit];
223*52130Smckusick 	register struct buf *bp = sc->sc_tab.b_actf;
224*52130Smckusick 	extern int cold;
225*52130Smckusick 	extern int sii_debug; /* XXX */
226*52130Smckusick 
227*52130Smckusick 	printf("tzdone(%d, %d, %d, %x) %x flags %x\n", unit, error, resid,
228*52130Smckusick 		status, sc, sc->sc_flags); /* XXX */
229*52130Smckusick 	if (bp == NULL) {
230*52130Smckusick 		printf("tz%d: bp == NULL\n", unit);
231*52130Smckusick 		return;
232*52130Smckusick 	}
233*52130Smckusick 	if (sc->sc_flags & TZF_SENSEINPROGRESS) {
234*52130Smckusick 		sc->sc_flags &= ~TZF_SENSEINPROGRESS;
235*52130Smckusick 		sc->sc_tab.b_actf = bp = bp->b_actf;	/* remove sc_errbuf */
236*52130Smckusick 		if (bp == 0) {
237*52130Smckusick 			sii_DumpLog();
238*52130Smckusick 			panic("tzdone"); /* XXX */
239*52130Smckusick 		}
240*52130Smckusick 
241*52130Smckusick 		if (error || (status & SCSI_STATUS_CHECKCOND)) {
242*52130Smckusick #ifdef DEBUG
243*52130Smckusick 			if (tzdebug)
244*52130Smckusick 				printf("tz%d: error reading sense data: error %d scsi status 0x%x\n",
245*52130Smckusick 					unit, error, status);
246*52130Smckusick #endif
247*52130Smckusick 			/*
248*52130Smckusick 			 * We got an error during the REQUEST_SENSE,
249*52130Smckusick 			 * fill in no sense for data.
250*52130Smckusick 			 */
251*52130Smckusick 			sc->sc_sense.sense[0] = 0x70;
252*52130Smckusick 			sc->sc_sense.sense[2] = SCSI_CLASS7_NO_SENSE;
253*52130Smckusick 		} else if (!cold
254*52130Smckusick #ifdef DEBUG
255*52130Smckusick 			|| tzdebug
256*52130Smckusick #endif
257*52130Smckusick 		) {
258*52130Smckusick 			printf("tz%d: ", unit);
259*52130Smckusick 			scsiPrintSense((ScsiClass7Sense *)sc->sc_sense.sense,
260*52130Smckusick 				sizeof(sc->sc_sense.sense) - resid);
261*52130Smckusick 		}
262*52130Smckusick 	} else if (error || (status & SCSI_STATUS_CHECKCOND)) {
263*52130Smckusick #ifdef DEBUG
264*52130Smckusick 		if (tzdebug)
265*52130Smckusick 			printf("tz%d: error %d scsi status 0x%x\n",
266*52130Smckusick 				unit, error, status);
267*52130Smckusick #endif
268*52130Smckusick 		/* save error info */
269*52130Smckusick 		sc->sc_sense.status = status;
270*52130Smckusick 		bp->b_flags |= B_ERROR;
271*52130Smckusick 		bp->b_error = error;
272*52130Smckusick 		bp->b_resid = resid;
273*52130Smckusick 
274*52130Smckusick 		if (status & SCSI_STATUS_CHECKCOND) {
275*52130Smckusick 			/*
276*52130Smckusick 			 * Start a REQUEST_SENSE command.
277*52130Smckusick 			 * Since we are called at interrupt time, we can't
278*52130Smckusick 			 * wait for the command to finish; that's why we use
279*52130Smckusick 			 * the sc_flags field.
280*52130Smckusick 			 */
281*52130Smckusick 			sc->sc_flags |= TZF_SENSEINPROGRESS;
282*52130Smckusick 			sc->sc_cdb.len = sizeof(ScsiGroup0Cmd);
283*52130Smckusick 			scsiGroup0Cmd(SCSI_REQUEST_SENSE, sc->sc_sd->sd_slave,
284*52130Smckusick 				0, sizeof(sc->sc_sense.sense),
285*52130Smckusick 				(ScsiGroup0Cmd *)sc->sc_cdb.cdb);
286*52130Smckusick 			sc->sc_errbuf.b_flags = B_BUSY | B_READ;
287*52130Smckusick 			sc->sc_errbuf.b_bcount = sizeof(sc->sc_sense.sense);
288*52130Smckusick 			sc->sc_errbuf.b_un.b_addr = (caddr_t)sc->sc_sense.sense;
289*52130Smckusick 			sc->sc_errbuf.av_forw = bp;
290*52130Smckusick 			sc->sc_tab.b_actf = &sc->sc_errbuf;
291*52130Smckusick 			tzstart(unit);
292*52130Smckusick 			return;
293*52130Smckusick 		}
294*52130Smckusick 	} else {
295*52130Smckusick 		sc->sc_sense.status = status;
296*52130Smckusick 		bp->b_resid = resid;
297*52130Smckusick 	}
298*52130Smckusick 
299*52130Smckusick 	sc->sc_tab.b_actf = bp->b_actf;
300*52130Smckusick 	biodone(bp);
301*52130Smckusick 	if (sc->sc_tab.b_actf)
302*52130Smckusick 		tzstart(unit);
303*52130Smckusick 	else {
304*52130Smckusick 		sii_debug = 1; /* XXX */
305*52130Smckusick 		sc->sc_tab.b_active = 0;
306*52130Smckusick 		if (sc->sc_flags & TZF_WAIT) {
307*52130Smckusick 			sc->sc_flags &= ~TZF_WAIT;
308*52130Smckusick 			wakeup(&sc->sc_flags);
309*52130Smckusick 		}
310*52130Smckusick 	}
311*52130Smckusick }
312*52130Smckusick 
313*52130Smckusick tzopen(dev, flags)
314*52130Smckusick 	dev_t dev;
315*52130Smckusick 	int flags;
316*52130Smckusick {
317*52130Smckusick 	register int unit = tzunit(dev);
318*52130Smckusick 	register struct tz_softc *sc = &tz_softc[unit];
319*52130Smckusick 	int error;
320*52130Smckusick 
321*52130Smckusick 	if (unit >= NTZ)
322*52130Smckusick 		return (ENXIO);
323*52130Smckusick 	if (!(sc->sc_flags & TZF_ALIVE)) {
324*52130Smckusick 		/* check again, tape may have been turned off at boot time */
325*52130Smckusick 		if (!tzprobe(sc->sc_sd))
326*52130Smckusick 			return (ENXIO);
327*52130Smckusick 	}
328*52130Smckusick 	if (sc->sc_flags & TZF_OPEN)
329*52130Smckusick 		return (EBUSY);
330*52130Smckusick 
331*52130Smckusick 	/* clear UNIT_ATTENTION */
332*52130Smckusick 	error = tzcommand(dev, SCSI_TEST_UNIT_READY, 0, 0);
333*52130Smckusick 	if (error) {
334*52130Smckusick 		ScsiClass7Sense *sp = (ScsiClass7Sense *)sc->sc_sense.sense;
335*52130Smckusick 
336*52130Smckusick 		/* return error if last error was not UNIT_ATTENTION */
337*52130Smckusick 		if (!(sc->sc_sense.status & SCSI_STATUS_CHECKCOND) ||
338*52130Smckusick 		    sp->error7 != 0x70 || sp->key != SCSI_CLASS7_UNIT_ATTN)
339*52130Smckusick 			return (error);
340*52130Smckusick 	}
341*52130Smckusick 
342*52130Smckusick #ifdef notdef
343*52130Smckusick 	if ((flag&FWRITE) && (sc->sc_dsreg&HTDS_WRL)) {
344*52130Smckusick 		sc->sc_openf = 0;
345*52130Smckusick 		uprintf("tu%d: no write ring\n", tuunit);
346*52130Smckusick 		return (EIO);
347*52130Smckusick 	}
348*52130Smckusick 	sc->sc_ctty = (caddr_t)(u.u_procp->p_flag & SCTTY ?
349*52130Smckusick 			u.u_procp->p_session->s_ttyp : 0);
350*52130Smckusick #endif
351*52130Smckusick 	sc->sc_flags = TZF_ALIVE | TZF_OPEN;
352*52130Smckusick 	return (0);
353*52130Smckusick }
354*52130Smckusick 
355*52130Smckusick tzclose(dev, flag)
356*52130Smckusick 	dev_t dev;
357*52130Smckusick 	int flag;
358*52130Smckusick {
359*52130Smckusick 	register struct tz_softc *sc = &tz_softc[tzunit(dev)];
360*52130Smckusick 
361*52130Smckusick 	if (!(sc->sc_flags & TZF_OPEN))
362*52130Smckusick 		return (0);
363*52130Smckusick 	if (flag == FWRITE ||
364*52130Smckusick 	    ((flag & FWRITE) && (sc->sc_flags & TZF_WRITTEN))) {
365*52130Smckusick 		(void) tzcommand(dev, SCSI_WRITE_EOF, 0, 1);
366*52130Smckusick 	}
367*52130Smckusick 	if ((minor(dev) & TZ_NOREWIND) == 0)
368*52130Smckusick 		(void) tzcommand(dev, SCSI_REWIND, 0, 0);
369*52130Smckusick 	sc->sc_flags &= ~(TZF_OPEN | TZF_WRITTEN);
370*52130Smckusick 	return (0);
371*52130Smckusick }
372*52130Smckusick 
373*52130Smckusick tzioctl(dev, cmd, data, flag)
374*52130Smckusick 	dev_t dev;
375*52130Smckusick 	int cmd;
376*52130Smckusick 	caddr_t data;
377*52130Smckusick 	int flag;
378*52130Smckusick {
379*52130Smckusick 	register struct tz_softc *sc = &tz_softc[tzunit(dev)];
380*52130Smckusick 	register struct buf *bp = &sc->sc_buf;
381*52130Smckusick 	struct mtop *mtop;
382*52130Smckusick 	struct mtget *mtget;
383*52130Smckusick 	int code, count;
384*52130Smckusick 	static tzops[] = {
385*52130Smckusick 		SCSI_WRITE_EOF, SCSI_SPACE, SCSI_SPACE, SCSI_SPACE, SCSI_SPACE,
386*52130Smckusick 		SCSI_REWIND, SCSI_REWIND, SCSI_TEST_UNIT_READY
387*52130Smckusick 	};
388*52130Smckusick 
389*52130Smckusick 	switch (cmd) {
390*52130Smckusick 
391*52130Smckusick 	case MTIOCTOP:	/* tape operation */
392*52130Smckusick 		mtop = (struct mtop *)data;
393*52130Smckusick 		if ((unsigned)mtop->mt_op < MTREW && mtop->mt_count <= 0)
394*52130Smckusick 			return (EINVAL);
395*52130Smckusick 		switch (mtop->mt_op) {
396*52130Smckusick 
397*52130Smckusick 		case MTWEOF:
398*52130Smckusick 			code = 0;
399*52130Smckusick 			count = mtop->mt_count;
400*52130Smckusick 			break;
401*52130Smckusick 
402*52130Smckusick 		case MTFSF:
403*52130Smckusick 			code = 1;
404*52130Smckusick 			count = mtop->mt_count;
405*52130Smckusick 			break;
406*52130Smckusick 
407*52130Smckusick 		case MTBSF:
408*52130Smckusick 			code = 1;
409*52130Smckusick 			count = -mtop->mt_count;
410*52130Smckusick 			break;
411*52130Smckusick 
412*52130Smckusick 		case MTFSR:
413*52130Smckusick 			code = 0;
414*52130Smckusick 			break;
415*52130Smckusick 
416*52130Smckusick 		case MTBSR:
417*52130Smckusick 			code = 0;
418*52130Smckusick 			count = -mtop->mt_count;
419*52130Smckusick 			break;
420*52130Smckusick 
421*52130Smckusick 		case MTREW:
422*52130Smckusick 		case MTOFFL:
423*52130Smckusick 		case MTNOP:
424*52130Smckusick 			code = 0;
425*52130Smckusick 			count = 0;
426*52130Smckusick 			break;
427*52130Smckusick 
428*52130Smckusick 		default:
429*52130Smckusick 			return (EINVAL);
430*52130Smckusick 		}
431*52130Smckusick 		return (tzcommand(dev, tzops[mtop->mt_op], code, count));
432*52130Smckusick 
433*52130Smckusick 	case MTIOCGET:
434*52130Smckusick 		mtget = (struct mtget *)data;
435*52130Smckusick 		mtget->mt_dsreg = 0;
436*52130Smckusick 		mtget->mt_erreg = sc->sc_sense.status;
437*52130Smckusick 		mtget->mt_resid = 0;
438*52130Smckusick 		mtget->mt_type = 0;
439*52130Smckusick 		break;
440*52130Smckusick 
441*52130Smckusick 	default:
442*52130Smckusick 		return (EINVAL);
443*52130Smckusick 	}
444*52130Smckusick 	return (0);
445*52130Smckusick }
446*52130Smckusick 
447*52130Smckusick void
448*52130Smckusick tzstrategy(bp)
449*52130Smckusick 	register struct buf *bp;
450*52130Smckusick {
451*52130Smckusick 	register int unit = tzunit(bp->b_dev);
452*52130Smckusick 	register struct tz_softc *sc = &tz_softc[unit];
453*52130Smckusick 	register struct buf *dp;
454*52130Smckusick 	register int s;
455*52130Smckusick 
456*52130Smckusick 	bp->av_forw = NULL;
457*52130Smckusick 	dp = &sc->sc_tab;
458*52130Smckusick 	s = splbio();
459*52130Smckusick 	if (dp->b_actf == NULL)
460*52130Smckusick 		dp->b_actf = bp;
461*52130Smckusick 	else
462*52130Smckusick 		dp->b_actl->av_forw = bp;
463*52130Smckusick 	dp->b_actl = bp;
464*52130Smckusick 	if (dp->b_active == 0) {
465*52130Smckusick 		dp->b_active = 1;
466*52130Smckusick 		tzstart(unit);
467*52130Smckusick 	}
468*52130Smckusick 	splx(s);
469*52130Smckusick }
470*52130Smckusick #endif
471