xref: /csrg-svn/sys/hp300/dev/st.c (revision 46286)
1*46286Smckusick /*
2*46286Smckusick  * Copyright (c) 1990 University of Utah.
3*46286Smckusick  * Copyright (c) 1990 The Regents of the University of California.
4*46286Smckusick  * All rights reserved.
5*46286Smckusick  *
6*46286Smckusick  * This code is derived from software contributed to Berkeley by
7*46286Smckusick  * the Systems Programming Group of the University of Utah Computer
8*46286Smckusick  * Science Department.
9*46286Smckusick  *
10*46286Smckusick  * %sccs.include.redist.c%
11*46286Smckusick  *
12*46286Smckusick  * from: Utah $Hdr: st.c 1.8 90/10/14$
13*46286Smckusick  *
14*46286Smckusick  *      @(#)st.c	7.1 (Berkeley) 02/05/91
15*46286Smckusick  */
16*46286Smckusick 
17*46286Smckusick /*
18*46286Smckusick  * SCSI CCS (Command Command Set) tape driver.
19*46286Smckusick  *
20*46286Smckusick  * Specific to Exabyte:
21*46286Smckusick  * mt status: residual="Mbytes to LEOM"
22*46286Smckusick  * minor bit 4 [b1bbbb] (aka /dev/rst16) selects short filemarks
23*46286Smckusick  * minor bit 5 [1bbbbb] (aka /dev/rst32) selects fix block mode, 1k blocks.
24*46286Smckusick  *
25*46286Smckusick  * Archive drive:
26*46286Smckusick  * can read both QIC-24 and QIC-II. But only writes
27*46286Smckusick  * QIC-24.
28*46286Smckusick  *
29*46286Smckusick  * Supports Archive Viper QIC-150 tape drive, but scsi.c reports selection
30*46286Smckusick  * errors.
31*46286Smckusick  *
32*46286Smckusick  * Supports Archive Python DAT drive, but will sometimes hang machine.
33*46286Smckusick  *
34*46286Smckusick  * Supports HP 35450A DAT drive, but will sometimes hang machine.
35*46286Smckusick  * Partitioning of tape not supported.
36*46286Smckusick  * Vendor unique support has not been added.
37*46286Smckusick  *
38*46286Smckusick  *
39*46286Smckusick  * Supports Archive VIPER (QIC-150).
40*46286Smckusick  * Mostly Supports Archive PYTHON (DAT).
41*46286Smckusick  *     Hangs if write after spin down.
42*46286Smckusick  *     Need scsi.c that does connect/disconnect.
43*46286Smckusick  */
44*46286Smckusick 
45*46286Smckusick /*
46*46286Smckusick  * support for the block device not implemented
47*46286Smckusick  */
48*46286Smckusick 
49*46286Smckusick #include "st.h"
50*46286Smckusick #if NST > 0
51*46286Smckusick 
52*46286Smckusick #include "param.h"
53*46286Smckusick #include "systm.h"
54*46286Smckusick #include "buf.h"
55*46286Smckusick #include "errno.h"
56*46286Smckusick #include "device.h"
57*46286Smckusick #include "scsireg.h"
58*46286Smckusick #include "file.h"
59*46286Smckusick #include "tty.h"
60*46286Smckusick #include "user.h"
61*46286Smckusick #include "proc.h"
62*46286Smckusick #include "mtio.h"
63*46286Smckusick #include "ioctl.h"
64*46286Smckusick #include "uio.h"
65*46286Smckusick #include "kernel.h"
66*46286Smckusick 
67*46286Smckusick #include "stvar.h"
68*46286Smckusick 
69*46286Smckusick extern int scsi_test_unit_rdy();
70*46286Smckusick extern int scsi_request_sense();
71*46286Smckusick extern int scsiustart();
72*46286Smckusick extern int scsigo();
73*46286Smckusick extern void scsifree();
74*46286Smckusick extern void scsireset();
75*46286Smckusick extern void scsi_delay();
76*46286Smckusick extern int scsi_tt_oddio();
77*46286Smckusick 
78*46286Smckusick extern int scsi_immed_command();
79*46286Smckusick 
80*46286Smckusick int	stinit(), ststart(), stgo(), stintr();
81*46286Smckusick struct	driver stdriver = {
82*46286Smckusick 	stinit, "st", ststart, stgo, stintr,
83*46286Smckusick };
84*46286Smckusick 
85*46286Smckusick struct	st_softc {
86*46286Smckusick 	struct	hp_device *sc_hd;
87*46286Smckusick 	struct	devqueue sc_dq;
88*46286Smckusick 	long	sc_blkno;       /* (possible block device support?) */
89*46286Smckusick 	long	sc_resid;	/* (possible block device support?) */
90*46286Smckusick 	int	sc_flags;
91*46286Smckusick 	int	sc_blklen;	/* 0 = variable len records */
92*46286Smckusick 	int	sc_filepos;	/* file position on tape */
93*46286Smckusick 	long	sc_numblks;	/* number of blocks on tape */
94*46286Smckusick 	short	sc_type;	/* ansi scsi type */
95*46286Smckusick 	short	sc_punit;	/* physical unit (scsi lun) */
96*46286Smckusick 	short	sc_tapeid;	/* tape drive id */
97*46286Smckusick 	char	sc_datalen[32];	/* additional data length on some commands */
98*46286Smckusick 	short	sc_tticntdwn;	/* interrupts between TTi display updates */
99*46286Smckusick 	caddr_t	sc_ctty;
100*46286Smckusick 	struct	buf *sc_bp;
101*46286Smckusick 	u_char	sc_cmd;
102*46286Smckusick } st_softc[NST];
103*46286Smckusick 
104*46286Smckusick /* softc flags */
105*46286Smckusick #define STF_ALIVE	0x0001
106*46286Smckusick #define STF_OPEN	0x0002
107*46286Smckusick #define STF_WMODE	0x0004
108*46286Smckusick #define STF_WRTTN	0x0008
109*46286Smckusick #define STF_CMD		0x0010
110*46286Smckusick #define STF_LEOT	0x0020
111*46286Smckusick #define STF_MOVED	0x0040
112*46286Smckusick 
113*46286Smckusick struct	st_mode st_mode[NST];
114*46286Smckusick 
115*46286Smckusick /*
116*46286Smckusick  * Maybe this should not be global, but gives chance to get
117*46286Smckusick  * tape remaining, Rewrites/ECC, etc outside the driver
118*46286Smckusick  */
119*46286Smckusick static struct st_xsense {
120*46286Smckusick 	struct	scsi_xsense sc_xsense;	/* data from sense */
121*46286Smckusick 	struct	exb_xsense exb_xsense;	/* additional info from exabyte */
122*46286Smckusick } st_xsense[NST];
123*46286Smckusick 
124*46286Smckusick static struct scsi_fmt_cdb stcmd[NST];
125*46286Smckusick 
126*46286Smckusick static struct scsi_fmt_cdb st_read_cmd = { 6, CMD_READ };
127*46286Smckusick static struct scsi_fmt_cdb st_write_cmd = { 6, CMD_WRITE };
128*46286Smckusick 
129*46286Smckusick struct buf sttab[NST];
130*46286Smckusick struct buf stbuf[NST];
131*46286Smckusick 
132*46286Smckusick #define UNIT(x)		(minor(x) & 3)
133*46286Smckusick #define stpunit(x)	((x) & 7)
134*46286Smckusick 
135*46286Smckusick #define STDEV_NOREWIND	0x04
136*46286Smckusick #define STDEV_HIDENSITY	0x08
137*46286Smckusick #define STDEV_EXSFMK	0x10
138*46286Smckusick #define STDEV_FIXEDBLK	0x20
139*46286Smckusick 
140*46286Smckusick #ifdef DEBUG
141*46286Smckusick int st_debug = 0x0000;
142*46286Smckusick #define ST_OPEN		0x0001
143*46286Smckusick #define ST_GO		0x0002
144*46286Smckusick #define ST_FMKS		0x0004
145*46286Smckusick #define ST_OPENSTAT	0x0008
146*46286Smckusick #define ST_BRESID	0x0010
147*46286Smckusick #define ST_ODDIO	0x0020
148*46286Smckusick #endif
149*46286Smckusick 
150*46286Smckusick /*
151*46286Smckusick  * Patchable variable.  If an even length read is requested a dma transfer is
152*46286Smckusick  * used.  Only after the read will we find out if the read had an odd number
153*46286Smckusick  * of bytes.  The HP98658 hardware cannot do odd length transfers, the last
154*46286Smckusick  * byte of the data will always be 0x00.  Normally, the driver will complain
155*46286Smckusick  * about such transfers and return EIO.  However, if st_dmaoddretry is non-
156*46286Smckusick  * zero, the driver will try and issue a BSR and then re-read the data using
157*46286Smckusick  * 'programmed transfer mode'.  In most cases this works, however for unknown
158*46286Smckusick  * reasons it will hang the machine in certain cases.
159*46286Smckusick  *
160*46286Smckusick  * Note:
161*46286Smckusick  * Odd length read requests are always done using programmed transfer mode.
162*46286Smckusick  */
163*46286Smckusick int st_dmaoddretry = 0;
164*46286Smckusick 
165*46286Smckusick /*
166*46286Smckusick  * Exabyte only:
167*46286Smckusick  * From adb can have access to fixed vs. variable length modes.
168*46286Smckusick  * Use 0x400 for 1k (best capacity) fixed length records.
169*46286Smckusick  * In st_open, if minor bit 4 set then 1k records are used.
170*46286Smckusick  * If st_exblken is set to anything other then 0 we are in fixed length mode.
171*46286Smckusick  * Minor bit 4 overrides any setting of st_exblklen.
172*46286Smckusick  *
173*46286Smckusick  */
174*46286Smckusick int st_exblklen = 0;
175*46286Smckusick 
176*46286Smckusick /* exabyte here for adb access, set at open time */
177*46286Smckusick #define EX_CT 	0x80		/* international cart - more space W/P6  */
178*46286Smckusick #define EX_ND	0x20		/* no disconnect  */
179*46286Smckusick #define EX_NBE	0x08		/* no busy enable  */
180*46286Smckusick #define EX_EBD	0x04		/* even byte disconnect  */
181*46286Smckusick #define EX_PE	0x02		/* parity enable  */
182*46286Smckusick #define EX_NAL	0x01		/* no auto load  */
183*46286Smckusick int st_exvup = (EX_CT|EX_ND|EX_NBE); /* vendor unique parameters */
184*46286Smckusick 
185*46286Smckusick /*
186*46286Smckusick  * motion and reconnect thresholds guidelines:
187*46286Smckusick  * write operation; lower motion threshold for faster transfer
188*46286Smckusick  *                  raise reconnect threshold for slower transfer
189*46286Smckusick  * read operation; lower motion threshold for slower transfer
190*46286Smckusick  *                 raise reconnect threshold for faster transfer
191*46286Smckusick  */
192*46286Smckusick int st_exmotthr = 0x80;		/* motion threshold, 0x80 default */
193*46286Smckusick int st_exreconthr = 0xa0;	/* reconnect threshold, 0xa0 default */
194*46286Smckusick int st_exgapthr = 7;		/* gap threshold, 7 default */
195*46286Smckusick #ifdef TTI
196*46286Smckusick int st_extti = 0x01;		/* bitmask of unit numbers, do extra */
197*46286Smckusick 				/* sensing so TTi display gets updated */
198*46286Smckusick #endif
199*46286Smckusick 
200*46286Smckusick stinit(hd)
201*46286Smckusick 	register struct hp_device *hd;
202*46286Smckusick {
203*46286Smckusick 	register struct st_softc *sc = &st_softc[hd->hp_unit];
204*46286Smckusick 
205*46286Smckusick 	sc->sc_hd = hd;
206*46286Smckusick 	sc->sc_punit = stpunit(hd->hp_flags);
207*46286Smckusick 	sc->sc_type = stident(sc, hd);
208*46286Smckusick 	if (sc->sc_type < 0)
209*46286Smckusick 		return(0);
210*46286Smckusick 	sc->sc_dq.dq_ctlr = hd->hp_ctlr;
211*46286Smckusick 	sc->sc_dq.dq_unit = hd->hp_unit;
212*46286Smckusick 	sc->sc_dq.dq_slave = hd->hp_slave;
213*46286Smckusick 	sc->sc_dq.dq_driver = &stdriver;
214*46286Smckusick 	sc->sc_blkno = 0;
215*46286Smckusick 	sc->sc_flags = STF_ALIVE;
216*46286Smckusick 	return(1);
217*46286Smckusick }
218*46286Smckusick 
219*46286Smckusick stident(sc, hd)
220*46286Smckusick 	register struct st_softc *sc;
221*46286Smckusick 	register struct hp_device *hd;
222*46286Smckusick {
223*46286Smckusick 	int unit;
224*46286Smckusick 	int ctlr, slave;
225*46286Smckusick 	int i, stat, inqlen;
226*46286Smckusick 	char idstr[32];
227*46286Smckusick #if 0
228*46286Smckusick 	static int havest = 0;
229*46286Smckusick #endif
230*46286Smckusick 	struct st_inquiry {
231*46286Smckusick 		struct	scsi_inquiry inqbuf;
232*46286Smckusick 		struct  exb_inquiry exb_inquiry;
233*46286Smckusick 	} st_inqbuf;
234*46286Smckusick 	static struct scsi_fmt_cdb st_inq = {
235*46286Smckusick 		6,
236*46286Smckusick 		CMD_INQUIRY, 0, 0, 0, sizeof(st_inqbuf), 0
237*46286Smckusick 	};
238*46286Smckusick 
239*46286Smckusick 	ctlr = hd->hp_ctlr;
240*46286Smckusick 	slave = hd->hp_slave;
241*46286Smckusick 	unit = sc->sc_punit;
242*46286Smckusick 	scsi_delay(-1);
243*46286Smckusick 
244*46286Smckusick 	inqlen = 0x05; /* min */
245*46286Smckusick 	st_inq.cdb[4] = 0x05;
246*46286Smckusick 	stat = scsi_immed_command(ctlr, slave, unit, &st_inq,
247*46286Smckusick 				  (u_char *)&st_inqbuf, inqlen, B_READ);
248*46286Smckusick 	/* do twice as first command on some scsi tapes always fails */
249*46286Smckusick 	stat = scsi_immed_command(ctlr, slave, unit, &st_inq,
250*46286Smckusick 				  (u_char *)&st_inqbuf, inqlen, B_READ);
251*46286Smckusick 	if (stat == -1)
252*46286Smckusick 		goto failed;
253*46286Smckusick 
254*46286Smckusick 	if (st_inqbuf.inqbuf.type != 0x01 ||  /* sequential access device */
255*46286Smckusick 	    st_inqbuf.inqbuf.qual != 0x80 ||  /* removable media */
256*46286Smckusick 	    (st_inqbuf.inqbuf.version != 0x01 && /* current ANSI SCSI spec */
257*46286Smckusick 	     st_inqbuf.inqbuf.version != 0x02))  /* 0x02 is for HP DAT */
258*46286Smckusick 		goto failed;
259*46286Smckusick 
260*46286Smckusick 	/* now get additonal info */
261*46286Smckusick 	inqlen = 0x05 + st_inqbuf.inqbuf.len;
262*46286Smckusick 	st_inq.cdb[4] = inqlen;
263*46286Smckusick 	bzero(&st_inqbuf, sizeof(st_inqbuf));
264*46286Smckusick 	stat = scsi_immed_command(ctlr, slave, unit, &st_inq,
265*46286Smckusick 				  (u_char *)&st_inqbuf, inqlen, B_READ);
266*46286Smckusick 
267*46286Smckusick 	if (st_inqbuf.inqbuf.len >= 28) {
268*46286Smckusick 		bcopy((caddr_t)&st_inqbuf.inqbuf.vendor_id, (caddr_t)idstr, 28);
269*46286Smckusick 		for (i = 27; i > 23; --i)
270*46286Smckusick 			if (idstr[i] != ' ')
271*46286Smckusick 				break;
272*46286Smckusick 		idstr[i+1] = 0;
273*46286Smckusick 		for (i = 23; i > 7; --i)
274*46286Smckusick 			if (idstr[i] != ' ')
275*46286Smckusick 				break;
276*46286Smckusick 		idstr[i+1] = 0;
277*46286Smckusick 		for (i = 7; i >= 0; --i)
278*46286Smckusick 			if (idstr[i] != ' ')
279*46286Smckusick 				break;
280*46286Smckusick 		idstr[i+1] = 0;
281*46286Smckusick 		printf("st%d: %s %s rev %s\n", hd->hp_unit, idstr, &idstr[8],
282*46286Smckusick 		       &idstr[24]);
283*46286Smckusick 	} else if (inqlen == 5)
284*46286Smckusick 		/* great it's a stupid device, doesn't know it's know name */
285*46286Smckusick 		idstr[0] = idstr[8] = '\0';
286*46286Smckusick 	else
287*46286Smckusick 		idstr[8] = '\0';
288*46286Smckusick 
289*46286Smckusick 	if (stat == 0xff) {
290*46286Smckusick 		printf("st%d: Cant handle this tape drive\n", hd->hp_unit);
291*46286Smckusick 		goto failed;
292*46286Smckusick 	}
293*46286Smckusick 
294*46286Smckusick 	if (bcmp("EXB-8200", &idstr[8], 8) == 0) {
295*46286Smckusick 		sc->sc_tapeid = MT_ISEXABYTE;
296*46286Smckusick 		sc->sc_datalen[CMD_REQUEST_SENSE] = 26;
297*46286Smckusick 		sc->sc_datalen[CMD_INQUIRY] = 52;
298*46286Smckusick 		sc->sc_datalen[CMD_MODE_SELECT] = 17;
299*46286Smckusick 		sc->sc_datalen[CMD_MODE_SENSE] = 17;
300*46286Smckusick 	} else if (bcmp("VIPER 150", &idstr[8], 9) == 0) {
301*46286Smckusick 		sc->sc_tapeid = MT_ISVIPER1;
302*46286Smckusick 		sc->sc_datalen[CMD_REQUEST_SENSE] = 14;
303*46286Smckusick 		sc->sc_datalen[CMD_INQUIRY] = 36;
304*46286Smckusick 		sc->sc_datalen[CMD_MODE_SELECT] = 12;
305*46286Smckusick 		sc->sc_datalen[CMD_MODE_SENSE] = 12;
306*46286Smckusick 	} else if (bcmp("Python 25501", &idstr[8], 12) == 0) {
307*46286Smckusick 		sc->sc_tapeid = MT_ISPYTHON;
308*46286Smckusick 		sc->sc_datalen[CMD_REQUEST_SENSE] = 14;
309*46286Smckusick 		sc->sc_datalen[CMD_INQUIRY] = 36;
310*46286Smckusick 		sc->sc_datalen[CMD_MODE_SELECT] = 12;
311*46286Smckusick 		sc->sc_datalen[CMD_MODE_SENSE] = 12;
312*46286Smckusick 	} else if (bcmp("HP35450A", &idstr[8], 8) == 0) {
313*46286Smckusick 		/* XXX "extra" stat makes the HP drive happy at boot time */
314*46286Smckusick 		stat = scsi_test_unit_rdy(ctlr, slave, unit);
315*46286Smckusick 		sc->sc_tapeid = MT_ISHPDAT;
316*46286Smckusick 		sc->sc_datalen[CMD_REQUEST_SENSE] = 14;
317*46286Smckusick 		sc->sc_datalen[CMD_INQUIRY] = 36;
318*46286Smckusick 		sc->sc_datalen[CMD_MODE_SELECT] = 12;
319*46286Smckusick 		sc->sc_datalen[CMD_MODE_SENSE] = 12;
320*46286Smckusick 	} else {
321*46286Smckusick 		if (idstr[8] == '\0')
322*46286Smckusick 			printf("st%d: No ID, assuming Archive\n", hd->hp_unit);
323*46286Smckusick 		else
324*46286Smckusick 			printf("st%d: Unsupported tape device\n", hd->hp_unit);
325*46286Smckusick 		sc->sc_tapeid = MT_ISAR;
326*46286Smckusick 		sc->sc_datalen[CMD_REQUEST_SENSE] = 8;
327*46286Smckusick 		sc->sc_datalen[CMD_INQUIRY] = 5;
328*46286Smckusick 		sc->sc_datalen[CMD_MODE_SELECT] = 12;
329*46286Smckusick 		sc->sc_datalen[CMD_MODE_SENSE] = 12;
330*46286Smckusick 	}
331*46286Smckusick 
332*46286Smckusick 	sc->sc_filepos = 0;
333*46286Smckusick 
334*46286Smckusick 	/* load xsense */
335*46286Smckusick 	stxsense(ctlr, slave, unit, sc);
336*46286Smckusick 
337*46286Smckusick 	scsi_delay(0);
338*46286Smckusick #if 0
339*46286Smckusick 	/* XXX if we have a tape, we must up the delays in the HA driver */
340*46286Smckusick 	if (!havest) {
341*46286Smckusick 		havest = 1;
342*46286Smckusick 		scsi_delay(20000);
343*46286Smckusick 	}
344*46286Smckusick #endif
345*46286Smckusick 	return(st_inqbuf.inqbuf.type);
346*46286Smckusick failed:
347*46286Smckusick 	scsi_delay(0);
348*46286Smckusick 	return(-1);
349*46286Smckusick }
350*46286Smckusick 
351*46286Smckusick stopen(dev, flag)
352*46286Smckusick 	dev_t dev;
353*46286Smckusick 	int flag;
354*46286Smckusick {
355*46286Smckusick 	register struct st_softc *sc = &st_softc[UNIT(dev)];
356*46286Smckusick 	register struct st_xsense *xsense;
357*46286Smckusick 	register int count;
358*46286Smckusick 	register int stat;
359*46286Smckusick 	int ctlr, slave, unit;
360*46286Smckusick 	struct mode_select_data msd;
361*46286Smckusick 	struct mode_sense mode;
362*46286Smckusick 	int modlen;
363*46286Smckusick 	static struct scsi_fmt_cdb modsel = {
364*46286Smckusick 		6,
365*46286Smckusick 		CMD_MODE_SELECT, 0, 0, 0, sizeof(msd), 0
366*46286Smckusick 	};
367*46286Smckusick 	static struct scsi_fmt_cdb unitready = {
368*46286Smckusick 		6,
369*46286Smckusick 		CMD_TEST_UNIT_READY, 0, 0, 0, 0, 0
370*46286Smckusick 	};
371*46286Smckusick 	static struct scsi_fmt_cdb modsense = {
372*46286Smckusick 		6,
373*46286Smckusick 		CMD_MODE_SENSE, 0, 0, 0, sizeof(mode), 0
374*46286Smckusick 	};
375*46286Smckusick 
376*46286Smckusick 	ctlr = sc->sc_dq.dq_ctlr;
377*46286Smckusick 	slave = sc->sc_dq.dq_slave;
378*46286Smckusick 	unit = sc->sc_punit;
379*46286Smckusick 	xsense = &st_xsense[UNIT(dev)];
380*46286Smckusick 
381*46286Smckusick 	if (UNIT(dev) > NST || (sc->sc_flags & STF_ALIVE) == 0)
382*46286Smckusick 		return(ENXIO);
383*46286Smckusick 	if (sc->sc_flags & STF_OPEN)
384*46286Smckusick 		return(EBUSY);
385*46286Smckusick 
386*46286Smckusick 	/* do a mode sense to get current */
387*46286Smckusick 	modlen = sc->sc_datalen[CMD_MODE_SENSE];
388*46286Smckusick 	modsense.cdb[4] = modlen;
389*46286Smckusick 	stat = scsi_immed_command(ctlr, slave, unit, &modsense,
390*46286Smckusick 				  (u_char *)&mode, modlen, B_READ);
391*46286Smckusick 
392*46286Smckusick 	/* do a mode sense to get current */
393*46286Smckusick 	modlen = sc->sc_datalen[CMD_MODE_SENSE];
394*46286Smckusick 	modsense.cdb[4] = modlen;
395*46286Smckusick 	stat = scsi_immed_command(ctlr, slave, unit, &modsense,
396*46286Smckusick 				  (u_char *)&mode, modlen, B_READ);
397*46286Smckusick 
398*46286Smckusick 	/* set record length */
399*46286Smckusick 	switch (sc->sc_tapeid) {
400*46286Smckusick 	case MT_ISAR:
401*46286Smckusick 		sc->sc_blklen = 512;
402*46286Smckusick 		break;
403*46286Smckusick 	case MT_ISEXABYTE:
404*46286Smckusick 		if (minor(dev) & STDEV_FIXEDBLK)
405*46286Smckusick 			sc->sc_blklen = 0x400;
406*46286Smckusick 		else
407*46286Smckusick 			sc->sc_blklen = st_exblklen;
408*46286Smckusick 		break;
409*46286Smckusick 	case MT_ISHPDAT:
410*46286Smckusick 		sc->sc_blklen = 512;
411*46286Smckusick 		break;
412*46286Smckusick 	case MT_ISVIPER1:
413*46286Smckusick 		sc->sc_blklen = 512;
414*46286Smckusick 		break;
415*46286Smckusick 	case MT_ISPYTHON:
416*46286Smckusick 		sc->sc_blklen = 512;
417*46286Smckusick 		break;
418*46286Smckusick 	default:
419*46286Smckusick 		if ((mode.md.blklen2 << 16 |
420*46286Smckusick 		     mode.md.blklen1 << 8 |
421*46286Smckusick 		     mode.md.blklen0) != 0)
422*46286Smckusick 			sc->sc_blklen = mode.md.blklen2 << 16 |
423*46286Smckusick 					mode.md.blklen1 << 8 |
424*46286Smckusick 					mode.md.blklen0;
425*46286Smckusick 		else
426*46286Smckusick 			sc->sc_blklen = 512;
427*46286Smckusick 	}
428*46286Smckusick 
429*46286Smckusick 	/* setup for mode select */
430*46286Smckusick 	msd.rsvd1 = 0;
431*46286Smckusick 	msd.rsvd2 = 0;
432*46286Smckusick 	msd.rsvd3 = 0;
433*46286Smckusick 	msd.buff = 1;
434*46286Smckusick 	msd.speed = 0;
435*46286Smckusick 	msd.blkdeslen = 0x08;
436*46286Smckusick 	msd.density = 0;
437*46286Smckusick 	msd.blks2 = 0;
438*46286Smckusick 	msd.blks1 = 0;
439*46286Smckusick 	msd.blks0 = 0;
440*46286Smckusick 	msd.rsvd4 = 0;
441*46286Smckusick 	msd.blklen2 = (sc->sc_blklen >> 16) & 0xff;
442*46286Smckusick 	msd.blklen1 = (sc->sc_blklen >> 8) & 0xff;
443*46286Smckusick 	msd.blklen0 = sc->sc_blklen & 0xff;
444*46286Smckusick 
445*46286Smckusick 	switch (sc->sc_tapeid) {
446*46286Smckusick 	case MT_ISAR:
447*46286Smckusick 		if (minor(dev) & STDEV_HIDENSITY)
448*46286Smckusick 			msd.density = 0x5;
449*46286Smckusick 		else {
450*46286Smckusick 			if (flag & FWRITE) {
451*46286Smckusick 				uprintf("Can only write QIC-24\n");
452*46286Smckusick 				return(EIO);
453*46286Smckusick 			}
454*46286Smckusick 			msd.density = 0x4;
455*46286Smckusick 		}
456*46286Smckusick 		break;
457*46286Smckusick 	case MT_ISEXABYTE:
458*46286Smckusick 		if (minor(dev) & STDEV_HIDENSITY)
459*46286Smckusick 			uprintf("EXB-8200 density support only\n");
460*46286Smckusick 		msd.vupb = (u_char)st_exvup;
461*46286Smckusick 		msd.rsvd5 = 0;
462*46286Smckusick 		msd.p5 = 0;
463*46286Smckusick 		msd.motionthres = (u_char)st_exmotthr;
464*46286Smckusick 		msd.reconthres = (u_char)st_exreconthr;
465*46286Smckusick 		msd.gapthres = (u_char)st_exgapthr;
466*46286Smckusick 		break;
467*46286Smckusick 	case MT_ISHPDAT:
468*46286Smckusick 	case MT_ISVIPER1:
469*46286Smckusick 	case MT_ISPYTHON:
470*46286Smckusick 		if (minor(dev) & STDEV_HIDENSITY)
471*46286Smckusick 			uprintf("Only one density supported\n");
472*46286Smckusick 		break;
473*46286Smckusick 	default:
474*46286Smckusick 		uprintf("Unsupported drive\n");
475*46286Smckusick 		return(EIO);
476*46286Smckusick 	}
477*46286Smckusick 
478*46286Smckusick 	modlen = sc->sc_datalen[CMD_MODE_SELECT];
479*46286Smckusick 	modsel.cdb[4] = modlen;
480*46286Smckusick 
481*46286Smckusick 	/* mode select */
482*46286Smckusick 	count = 0;
483*46286Smckusick retryselect:
484*46286Smckusick 	stat = scsi_immed_command(ctlr, slave, unit, &modsel,
485*46286Smckusick 				  (u_char *)&msd, modlen, B_WRITE);
486*46286Smckusick 	/*
487*46286Smckusick 	 * First command after power cycle, bus reset or tape change
488*46286Smckusick 	 * will error. Try command again
489*46286Smckusick 	 */
490*46286Smckusick 	if (stat == STS_CHECKCOND) {
491*46286Smckusick 		sc->sc_filepos = 0;
492*46286Smckusick 		stxsense(ctlr, slave, unit, sc);
493*46286Smckusick 		stat = scsi_immed_command(ctlr, slave, unit, &modsel,
494*46286Smckusick 					  (u_char *)&msd, modlen, B_WRITE);
495*46286Smckusick #ifdef DEBUG
496*46286Smckusick 		if (stat && (st_debug & ST_OPEN))
497*46286Smckusick 			printf("stopen: stat on mode select 0x%x second try\n", stat);
498*46286Smckusick #endif
499*46286Smckusick 		if (stat == STS_CHECKCOND) {
500*46286Smckusick 			stxsense(ctlr, slave, unit, sc);
501*46286Smckusick 			prtkey(UNIT(dev), sc);
502*46286Smckusick 		}
503*46286Smckusick 		if (stat)
504*46286Smckusick 			return(EIO);
505*46286Smckusick 	}
506*46286Smckusick 	if (stat == -1 || stat == STS_BUSY) {
507*46286Smckusick 		/*
508*46286Smckusick 		 * XXX it might just be that the bus is busy because
509*46286Smckusick 		 * another tape is doing a command. This would change
510*46286Smckusick 		 * with connect/disconnect, ie. the other drive would
511*46286Smckusick 		 * not hold onto the bus.
512*46286Smckusick 		 *
513*46286Smckusick 		 * Sleep on lbolt for up to 20 minutes (max time to FSF
514*46286Smckusick 		 * an exabyte to EOT: 16:xx minutes)
515*46286Smckusick 		 */
516*46286Smckusick 		if (++count > 60*20) {
517*46286Smckusick 			uprintf("SCSI bus timeout\n");
518*46286Smckusick 			return(EBUSY);
519*46286Smckusick 		}
520*46286Smckusick 		sleep((caddr_t)&lbolt, PZERO+1);
521*46286Smckusick 		goto retryselect;
522*46286Smckusick 	}
523*46286Smckusick 
524*46286Smckusick 	/* drive ready ? */
525*46286Smckusick 	stat = scsi_test_unit_rdy(ctlr, slave, unit);
526*46286Smckusick 
527*46286Smckusick 	if (stat == STS_CHECKCOND) {
528*46286Smckusick 		stxsense(ctlr, slave, unit, sc);
529*46286Smckusick 		switch (sc->sc_tapeid) {
530*46286Smckusick 		case MT_ISEXABYTE:
531*46286Smckusick 			if ((xsense->sc_xsense.key & XSK_NOTRDY) &&
532*46286Smckusick 			    xsense->exb_xsense.tnp)
533*46286Smckusick 				uprintf("no cartridge\n");
534*46286Smckusick 			else if (xsense->sc_xsense.key & XSK_NOTRDY)
535*46286Smckusick 				uprintf("cartridge not loaded\n");
536*46286Smckusick 			else if (xsense->sc_xsense.key & XSK_UNTATTEN) {
537*46286Smckusick 				uprintf("new cart/power interrupt\n");
538*46286Smckusick 				stat = 0;
539*46286Smckusick 			} else if ((xsense->sc_xsense.key & XSK_UNTATTEN) &&
540*46286Smckusick 				   xsense->exb_xsense.tnp)
541*46286Smckusick 				uprintf("cartridge unloading\n");
542*46286Smckusick 			else
543*46286Smckusick 				prtkey(UNIT(dev), sc);
544*46286Smckusick 			break;
545*46286Smckusick 		case MT_ISAR:
546*46286Smckusick 			if (xsense->sc_xsense.key & XSK_UNTATTEN)
547*46286Smckusick 				stat = scsi_test_unit_rdy(ctlr, slave, unit);
548*46286Smckusick 			if (stat == STS_CHECKCOND) {
549*46286Smckusick 				stxsense(ctlr, slave, unit, sc);
550*46286Smckusick 				if (xsense->sc_xsense.key)
551*46286Smckusick 					prtkey(UNIT(dev), sc);
552*46286Smckusick 			} else {
553*46286Smckusick 				sc->sc_filepos = 0; /* new tape */
554*46286Smckusick 				stat = 0;
555*46286Smckusick 			}
556*46286Smckusick 			break;
557*46286Smckusick 		case MT_ISHPDAT:
558*46286Smckusick 		case MT_ISVIPER1:
559*46286Smckusick 		case MT_ISPYTHON:
560*46286Smckusick 			if (xsense->sc_xsense.key & XSK_UNTATTEN)
561*46286Smckusick 				stat = scsi_test_unit_rdy(ctlr, slave, unit);
562*46286Smckusick 			if (stat == STS_CHECKCOND) {
563*46286Smckusick 				stxsense(ctlr, slave, unit, sc);
564*46286Smckusick 				if (xsense->sc_xsense.key)
565*46286Smckusick 					prtkey(UNIT(dev), sc);
566*46286Smckusick 			}
567*46286Smckusick 			break;
568*46286Smckusick 		default:
569*46286Smckusick 			uprintf("st%d: not ready\n", UNIT(dev));
570*46286Smckusick 			prtkey(UNIT(dev), sc);
571*46286Smckusick 			break;
572*46286Smckusick 		}
573*46286Smckusick 	}
574*46286Smckusick 	if (stat)
575*46286Smckusick 		return(EIO);
576*46286Smckusick 
577*46286Smckusick 	/* mode sense */
578*46286Smckusick 	modlen = sc->sc_datalen[CMD_MODE_SENSE];
579*46286Smckusick 	modsense.cdb[4] = modlen;
580*46286Smckusick 	stat = scsi_immed_command(ctlr, slave, unit, &modsense,
581*46286Smckusick 				  (u_char *)&mode, modlen, B_READ);
582*46286Smckusick #ifdef DEBUG
583*46286Smckusick 	if (st_debug & ST_OPENSTAT)
584*46286Smckusick 		prtmodstat(&mode);
585*46286Smckusick #endif
586*46286Smckusick 
587*46286Smckusick 	if (stat == STS_CHECKCOND) {
588*46286Smckusick 		stxsense(ctlr, slave, unit, sc);
589*46286Smckusick #ifdef DEBUG
590*46286Smckusick 		if (st_debug & ST_OPEN)
591*46286Smckusick 			dumpxsense(xsense);
592*46286Smckusick #endif
593*46286Smckusick 	}
594*46286Smckusick 	if (stat)
595*46286Smckusick 		return(EIO);
596*46286Smckusick 
597*46286Smckusick 	if ((flag & FWRITE) && mode.md.wp) {
598*46286Smckusick 		uprintf("st:%d write protected\n", UNIT(dev));
599*46286Smckusick 		return(EACCES);
600*46286Smckusick 	}
601*46286Smckusick 
602*46286Smckusick 	sc->sc_ctty = (caddr_t)(u.u_procp->p_flag&SCTTY ?
603*46286Smckusick 			u.u_procp->p_session->s_ttyvp : 0);
604*46286Smckusick 	/* save total number of blocks on tape */
605*46286Smckusick 	sc->sc_numblks = mode.md.numblk2 << 16 |
606*46286Smckusick 			 mode.md.numblk1 << 8 |
607*46286Smckusick 			 mode.md.numblk0;
608*46286Smckusick 
609*46286Smckusick 	if (xsense->sc_xsense.eom && !(sc->sc_flags & STF_LEOT))
610*46286Smckusick 		sc->sc_filepos = 0;
611*46286Smckusick #ifdef DEBUG
612*46286Smckusick 	if (st_debug & ST_FMKS)
613*46286Smckusick 		printf("st%d: open filepos = %d\n", UNIT(dev), sc->sc_filepos);
614*46286Smckusick #endif
615*46286Smckusick 
616*46286Smckusick 	sc->sc_flags |= (STF_OPEN);
617*46286Smckusick 	if (flag & FWRITE)
618*46286Smckusick 		sc->sc_flags |= STF_WMODE;
619*46286Smckusick 	sc->sc_flags &= ~STF_MOVED;
620*46286Smckusick 
621*46286Smckusick #ifdef TTI
622*46286Smckusick 	/* make stats available, also lit up TTi display */
623*46286Smckusick 	sc->sc_tticntdwn = 100;
624*46286Smckusick #endif
625*46286Smckusick 	stxsense(ctlr, slave, unit, sc);
626*46286Smckusick 
627*46286Smckusick 	return(0);
628*46286Smckusick }
629*46286Smckusick 
630*46286Smckusick /*ARGSUSED*/
631*46286Smckusick stclose(dev, flag)
632*46286Smckusick 	dev_t dev;
633*46286Smckusick 	int flag;
634*46286Smckusick {
635*46286Smckusick 	register struct st_softc *sc = &st_softc[UNIT(dev)];
636*46286Smckusick 	register int hit = 0;
637*46286Smckusick 
638*46286Smckusick 	if ((sc->sc_flags & (STF_WMODE|STF_WRTTN)) == (STF_WMODE|STF_WRTTN)) {
639*46286Smckusick 		/*
640*46286Smckusick 		 * XXX driver only supports cartridge tapes.
641*46286Smckusick 		 * Cartridge tapes don't do double EOFs on EOT.
642*46286Smckusick 		 */
643*46286Smckusick 		stcommand(dev, MTWEOF, 1);
644*46286Smckusick 		hit++;
645*46286Smckusick 	}
646*46286Smckusick 	if ((minor(dev) & STDEV_NOREWIND) == 0) {
647*46286Smckusick 		stcommand(dev, MTREW, 1);
648*46286Smckusick 		hit++;
649*46286Smckusick 	}
650*46286Smckusick #ifdef NOTDEF
651*46286Smckusick 	/* wait until more stable before trying [XXX Needed ?] */
652*46286Smckusick 	if (!hit && (sc->sc_flags & SFT_WMODE))
653*46286Smckusick 		/* force out any any bufferd write data */
654*46286Smckusick 		stcommand(dev, MTFSR, 0);
655*46286Smckusick #endif
656*46286Smckusick 	/* make stats available */
657*46286Smckusick 	stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave, sc->sc_punit, sc);
658*46286Smckusick 
659*46286Smckusick 	sc->sc_flags &= ~(STF_OPEN|STF_WMODE|STF_WRTTN);
660*46286Smckusick 	sc->sc_ctty = NULL;
661*46286Smckusick 	return(0);	/* XXX */
662*46286Smckusick }
663*46286Smckusick 
664*46286Smckusick ststrategy(bp)
665*46286Smckusick 	register struct buf *bp;
666*46286Smckusick {
667*46286Smckusick 	struct buf *dp;
668*46286Smckusick 	int unit, s;
669*46286Smckusick 
670*46286Smckusick 	unit = UNIT(bp->b_dev);
671*46286Smckusick 	dp = &sttab[unit];
672*46286Smckusick 	bp->av_forw = NULL;
673*46286Smckusick 	s = splbio();
674*46286Smckusick 	if (dp->b_actf == NULL)
675*46286Smckusick 		dp->b_actf = bp;
676*46286Smckusick 	else
677*46286Smckusick 		dp->b_actl->av_forw = bp;
678*46286Smckusick 	dp->b_actl = bp;
679*46286Smckusick 	if (dp->b_active == 0) {
680*46286Smckusick 		dp->b_active = 1;
681*46286Smckusick 		stustart(unit);
682*46286Smckusick 	}
683*46286Smckusick 	splx(s);
684*46286Smckusick }
685*46286Smckusick 
686*46286Smckusick stustart(unit)
687*46286Smckusick 	int unit;
688*46286Smckusick {
689*46286Smckusick 	if (scsireq(&st_softc[unit].sc_dq))
690*46286Smckusick 		ststart(unit);
691*46286Smckusick }
692*46286Smckusick 
693*46286Smckusick ststart(unit)
694*46286Smckusick 	int unit;
695*46286Smckusick {
696*46286Smckusick 	struct hp_device *hp = st_softc[unit].sc_hd;
697*46286Smckusick 
698*46286Smckusick 	if (scsiustart(hp->hp_ctlr))
699*46286Smckusick 		stgo(unit);
700*46286Smckusick }
701*46286Smckusick 
702*46286Smckusick stgo(unit)
703*46286Smckusick 	int unit;
704*46286Smckusick {
705*46286Smckusick 	register struct st_softc *sc = &st_softc[unit];
706*46286Smckusick 	register struct scsi_fmt_cdb *cmd;
707*46286Smckusick 	register struct buf *bp = sttab[unit].b_actf;
708*46286Smckusick 	struct hp_device *hp = sc->sc_hd;
709*46286Smckusick 	int pad, stat;
710*46286Smckusick 	long nblks;
711*46286Smckusick 
712*46286Smckusick 	if (sc->sc_flags & STF_CMD) {
713*46286Smckusick 		cmd = &stcmd[unit];
714*46286Smckusick 		pad = 0;
715*46286Smckusick 	} else {
716*46286Smckusick 		cmd = bp->b_flags & B_READ ? &st_read_cmd : &st_write_cmd;
717*46286Smckusick 		if (sc->sc_blklen)
718*46286Smckusick 			cmd->cdb[1] |= 0x01; /* fixed mode */
719*46286Smckusick 		else
720*46286Smckusick 			cmd->cdb[1] &= 0xfe;
721*46286Smckusick 		if (bp->b_flags & B_READ)
722*46286Smckusick 			sc->sc_flags &= ~STF_WRTTN;
723*46286Smckusick 		else
724*46286Smckusick 			sc->sc_flags |= STF_WRTTN;
725*46286Smckusick 
726*46286Smckusick 		if (sc->sc_blklen) { /* fixed mode */
727*46286Smckusick 			nblks = bp->b_bcount / sc->sc_blklen;
728*46286Smckusick 			if (bp->b_bcount % sc->sc_blklen) {
729*46286Smckusick 				tprintf(sc->sc_ctty,
730*46286Smckusick 					"st%d: I/O not block aligned %d/%ld\n",
731*46286Smckusick 					unit, sc->sc_blklen, bp->b_bcount);
732*46286Smckusick 				cmd->cdb[1] &= 0xfe; /* force error */
733*46286Smckusick 			}
734*46286Smckusick 		} else	/* variable len */
735*46286Smckusick 			nblks = bp->b_bcount;
736*46286Smckusick 
737*46286Smckusick 		*(u_char *)(&cmd->cdb[2]) = (u_char) (nblks >> 16);
738*46286Smckusick 		*(u_char *)(&cmd->cdb[3]) = (u_char) (nblks >> 8);
739*46286Smckusick 		*(u_char *)(&cmd->cdb[4]) = (u_char) nblks;
740*46286Smckusick 		/*
741*46286Smckusick 		 * Always Zero. We are either writing in variable
742*46286Smckusick 		 * length mode we are writing in fixed block mode,
743*46286Smckusick 		 * or we are going to do odd length IO and are not
744*46286Smckusick 		 * going to use DMA.
745*46286Smckusick 		 */
746*46286Smckusick 		pad = 0;
747*46286Smckusick 	}
748*46286Smckusick 
749*46286Smckusick #ifdef DEBUG
750*46286Smckusick 	if (st_debug & ST_GO)
751*46286Smckusick 		printf("stgo: cmd len %d [0]0x%x [1]0x%x [2]0x%x [3]0x%x [4]0x%x [5]0x%x\n",
752*46286Smckusick 		       cmd->len, cmd->cdb[0], cmd->cdb[1], cmd->cdb[2],
753*46286Smckusick 		       cmd->cdb[3], cmd->cdb[4], cmd->cdb[5]);
754*46286Smckusick #endif
755*46286Smckusick 
756*46286Smckusick 	sc->sc_flags |= STF_MOVED;
757*46286Smckusick 	if (bp->b_bcount & 1) {
758*46286Smckusick #ifdef DEBUG
759*46286Smckusick 		if (st_debug & ST_ODDIO)
760*46286Smckusick 			printf("stgo%d: odd count %d using manual transfer\n",
761*46286Smckusick 			       unit, bp->b_bcount);
762*46286Smckusick #endif
763*46286Smckusick 		stat = scsi_tt_oddio(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
764*46286Smckusick 				     bp->b_un.b_addr, bp->b_bcount,
765*46286Smckusick 				     bp->b_flags, 1);
766*46286Smckusick 		if (stat == 0) {
767*46286Smckusick 			bp->b_resid = 0;
768*46286Smckusick 			stfinish(unit, sc, bp);
769*46286Smckusick 		}
770*46286Smckusick 	} else
771*46286Smckusick 		stat = scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
772*46286Smckusick 			      bp, cmd, pad);
773*46286Smckusick 	if (stat) {
774*46286Smckusick 		bp->b_error = EIO;
775*46286Smckusick 		bp->b_flags |= B_ERROR;
776*46286Smckusick 		stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave,
777*46286Smckusick 			 sc->sc_punit, sc);
778*46286Smckusick 		sterror(unit, sc, stat);
779*46286Smckusick 		stfinish(unit, sc, bp);
780*46286Smckusick 	}
781*46286Smckusick }
782*46286Smckusick 
783*46286Smckusick stfinish(unit, sc, bp)
784*46286Smckusick 	int unit;
785*46286Smckusick 	struct st_softc *sc;
786*46286Smckusick 	struct buf *bp;
787*46286Smckusick {
788*46286Smckusick 	sttab[unit].b_errcnt = 0;
789*46286Smckusick 	sttab[unit].b_actf = bp->b_actf;
790*46286Smckusick 	iodone(bp);
791*46286Smckusick 	scsifree(&sc->sc_dq);
792*46286Smckusick 	if (sttab[unit].b_actf)
793*46286Smckusick 		stustart(unit);
794*46286Smckusick 	else
795*46286Smckusick 		sttab[unit].b_active = 0;
796*46286Smckusick }
797*46286Smckusick 
798*46286Smckusick stread(dev, uio)
799*46286Smckusick 	dev_t dev;
800*46286Smckusick 	struct uio *uio;
801*46286Smckusick {
802*46286Smckusick 	int unit = UNIT(dev);
803*46286Smckusick 
804*46286Smckusick 	return(physio(ststrategy, &stbuf[unit], dev, B_READ, minphys, uio));
805*46286Smckusick }
806*46286Smckusick 
807*46286Smckusick stwrite(dev, uio)
808*46286Smckusick 	dev_t dev;
809*46286Smckusick 	struct uio *uio;
810*46286Smckusick {
811*46286Smckusick 	int unit = UNIT(dev);
812*46286Smckusick 
813*46286Smckusick 	return(physio(ststrategy, &stbuf[unit], dev, B_WRITE, minphys, uio));
814*46286Smckusick }
815*46286Smckusick 
816*46286Smckusick /*ARGSUSED*/
817*46286Smckusick stdump(dev)
818*46286Smckusick 	dev_t dev;
819*46286Smckusick {
820*46286Smckusick 	return(ENXIO);
821*46286Smckusick }
822*46286Smckusick 
823*46286Smckusick /*ARGSUSED*/
824*46286Smckusick stioctl(dev, cmd, data, flag)
825*46286Smckusick 	dev_t dev;
826*46286Smckusick 	int cmd;
827*46286Smckusick 	caddr_t data;
828*46286Smckusick 	int flag;
829*46286Smckusick {
830*46286Smckusick 	register struct st_softc *sc = &st_softc[UNIT(dev)];
831*46286Smckusick 	register int cnt;
832*46286Smckusick 	register struct mtget *mtget;
833*46286Smckusick 	register struct st_xsense *xp = &st_xsense[UNIT(dev)];
834*46286Smckusick 	register struct mtop *op;
835*46286Smckusick 	long resid;
836*46286Smckusick 
837*46286Smckusick 	switch (cmd) {
838*46286Smckusick 
839*46286Smckusick 	/* tape operation */
840*46286Smckusick 	case MTIOCTOP:
841*46286Smckusick 		op = (struct mtop *)data;
842*46286Smckusick 		switch (op->mt_op) {
843*46286Smckusick 
844*46286Smckusick 		case MTBSR:
845*46286Smckusick 		case MTFSR:
846*46286Smckusick 			if (sc->sc_tapeid == MT_ISAR)
847*46286Smckusick 				return(ENXIO);
848*46286Smckusick 		case MTWEOF:
849*46286Smckusick 		case MTFSF:
850*46286Smckusick 		case MTBSF:
851*46286Smckusick 			cnt = (int)op->mt_count;
852*46286Smckusick 			break;
853*46286Smckusick 
854*46286Smckusick 		case MTREW:
855*46286Smckusick 		case MTOFFL:
856*46286Smckusick 			cnt = 1;
857*46286Smckusick 			break;
858*46286Smckusick 
859*46286Smckusick 		case MTNOP:
860*46286Smckusick 			return(0);
861*46286Smckusick 		default:
862*46286Smckusick 			return(EINVAL);
863*46286Smckusick 		}
864*46286Smckusick 		if (cnt <= 0)
865*46286Smckusick 			return(EINVAL);
866*46286Smckusick 		stcommand(dev, (u_int)op->mt_op, cnt);
867*46286Smckusick 		break;
868*46286Smckusick 
869*46286Smckusick 	/* drive status */
870*46286Smckusick 	case MTIOCGET:
871*46286Smckusick 		mtget = (struct mtget *)data;
872*46286Smckusick 		stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave,
873*46286Smckusick 			 sc->sc_punit, sc);
874*46286Smckusick 		mtget->mt_type = sc->sc_tapeid;
875*46286Smckusick 		mtget->mt_dsreg = 0;
876*46286Smckusick 		mtget->mt_erreg = ((xp->sc_xsense.valid << 15) |
877*46286Smckusick 				   (xp->sc_xsense.filemark << 14) |
878*46286Smckusick 				   (xp->sc_xsense.eom << 13) |
879*46286Smckusick 				   (xp->sc_xsense.ili << 12) |
880*46286Smckusick 				   (xp->sc_xsense.key << 8));
881*46286Smckusick 
882*46286Smckusick 		if (sc->sc_tapeid == MT_ISEXABYTE) {
883*46286Smckusick 			mtget->mt_dsreg = sc->sc_flags;
884*46286Smckusick 			resid = (xp->exb_xsense.tplft2 << 16 |
885*46286Smckusick 				 xp->exb_xsense.tplft1 << 8 |
886*46286Smckusick 				 xp->exb_xsense.tplft0);
887*46286Smckusick 			mtget->mt_resid = resid / 1000;
888*46286Smckusick 			mtget->mt_erreg |= (((xp->exb_xsense.rwerrcnt2 << 16 |
889*46286Smckusick 					      xp->exb_xsense.rwerrcnt1 << 8 |
890*46286Smckusick 					      xp->exb_xsense.rwerrcnt0) * 100) /
891*46286Smckusick 					    (sc->sc_numblks - resid)) & 0xff;
892*46286Smckusick 		} else if (xp->sc_xsense.valid) {
893*46286Smckusick 			resid = ((xp->sc_xsense.info1 << 24) |
894*46286Smckusick 				 (xp->sc_xsense.info2 << 16) |
895*46286Smckusick 				 (xp->sc_xsense.info3 << 8) |
896*46286Smckusick 				 (xp->sc_xsense.info4));
897*46286Smckusick 			if (sc->sc_blklen) /* if fixed mode */
898*46286Smckusick 				resid *= sc->sc_blklen;
899*46286Smckusick 			mtget->mt_resid = resid;
900*46286Smckusick 		} else
901*46286Smckusick 			mtget->mt_resid = 0;
902*46286Smckusick 		break;
903*46286Smckusick 
904*46286Smckusick 	default:
905*46286Smckusick 		return(ENXIO);
906*46286Smckusick 	}
907*46286Smckusick 	return(0);
908*46286Smckusick }
909*46286Smckusick 
910*46286Smckusick stintr(unit, stat)
911*46286Smckusick 	int unit, stat;
912*46286Smckusick {
913*46286Smckusick 	register struct st_softc *sc = &st_softc[unit];
914*46286Smckusick 	register struct st_xsense *xp = &st_xsense[unit];
915*46286Smckusick 	register struct buf *bp = sttab[unit].b_actf;
916*46286Smckusick 	struct hp_device *hp = sc->sc_hd;
917*46286Smckusick 
918*46286Smckusick #ifdef DEBUG
919*46286Smckusick 	if (bp == NULL) {
920*46286Smckusick 		printf("st%d: bp == NULL\n", unit);
921*46286Smckusick 		return;
922*46286Smckusick 	}
923*46286Smckusick #endif
924*46286Smckusick 	switch (stat) {
925*46286Smckusick 	/* scsi command completed ok */
926*46286Smckusick 	case 0:
927*46286Smckusick 		bp->b_resid = 0;
928*46286Smckusick 		break;
929*46286Smckusick 
930*46286Smckusick 	/* more status */
931*46286Smckusick 	case STS_CHECKCOND:
932*46286Smckusick 		stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave,
933*46286Smckusick 			 sc->sc_punit, sc);
934*46286Smckusick 		if (xp->sc_xsense.valid) {
935*46286Smckusick 			bp->b_resid = (u_long)((xp->sc_xsense.info1 << 24) |
936*46286Smckusick 					      (xp->sc_xsense.info2 << 16) |
937*46286Smckusick 					      (xp->sc_xsense.info3 << 8) |
938*46286Smckusick 					      (xp->sc_xsense.info4));
939*46286Smckusick 			if (sc->sc_blklen) /* fixed mode */
940*46286Smckusick 				bp->b_resid *= sc->sc_blklen;
941*46286Smckusick 		}
942*46286Smckusick 		if (xp->sc_xsense.filemark) {
943*46286Smckusick 			sc->sc_filepos++;
944*46286Smckusick 			break;
945*46286Smckusick 		}
946*46286Smckusick 		if (xp->sc_xsense.key) {
947*46286Smckusick 			sterror(unit, sc, stat);
948*46286Smckusick 			bp->b_flags |= B_ERROR;
949*46286Smckusick 			bp->b_error = EIO;
950*46286Smckusick 			break;
951*46286Smckusick 		}
952*46286Smckusick 		if (xp->sc_xsense.ili) {
953*46286Smckusick 			/*
954*46286Smckusick 			 * Fixed length blocks, an error.
955*46286Smckusick 			 */
956*46286Smckusick 			if (sc->sc_blklen) {
957*46286Smckusick 				tprintf(sc->sc_ctty,
958*46286Smckusick 					"st%d: Incorrect Length Indicator, blkcnt diff %d\n",
959*46286Smckusick 					unit, sc->sc_blklen - bp->b_resid);
960*46286Smckusick 				bp->b_flags |= B_ERROR;
961*46286Smckusick 				bp->b_error = EIO;
962*46286Smckusick 				break;
963*46286Smckusick 			}
964*46286Smckusick 			/*
965*46286Smckusick 			 * Variable length but read more than requested,
966*46286Smckusick 			 * an error.
967*46286Smckusick 			 */
968*46286Smckusick 			if (bp->b_resid < 0) {
969*46286Smckusick 				bp->b_resid = 0;
970*46286Smckusick 				bp->b_flags |= B_ERROR;
971*46286Smckusick 				bp->b_error = ENOMEM;
972*46286Smckusick 				break;
973*46286Smckusick 			}
974*46286Smckusick 			/*
975*46286Smckusick 			 * Variable length and odd, may require special
976*46286Smckusick 			 * handling.
977*46286Smckusick 			 */
978*46286Smckusick 			if (bp->b_resid & 1 && sc->sc_tapeid != MT_ISAR) {
979*46286Smckusick 				/*
980*46286Smckusick 				 * Normal behavior, treat as an error.
981*46286Smckusick 				 */
982*46286Smckusick 				if (!st_dmaoddretry) {
983*46286Smckusick 					tprintf(sc->sc_ctty,
984*46286Smckusick 						"st%d: Odd length read %d\n",
985*46286Smckusick 						UNIT(bp->b_dev),
986*46286Smckusick 						bp->b_bcount - bp->b_resid);
987*46286Smckusick 					bp->b_error = EIO;
988*46286Smckusick 					bp->b_flags |= B_ERROR;
989*46286Smckusick 					break;
990*46286Smckusick 				}
991*46286Smckusick 				/*
992*46286Smckusick 				 * Attempt to back up and re-read using oddio.
993*46286Smckusick 				 */
994*46286Smckusick #ifdef DEBUG
995*46286Smckusick 				if (st_debug & ST_ODDIO)
996*46286Smckusick 					printf("st%d: stintr odd count %d, do BSR then oddio\n",
997*46286Smckusick 					       UNIT(bp->b_dev),
998*46286Smckusick 					       bp->b_bcount - bp->b_resid);
999*46286Smckusick #endif
1000*46286Smckusick 				stat = scsi_tt_oddio(hp->hp_ctlr, hp->hp_slave,
1001*46286Smckusick 						     sc->sc_punit, 0, -1, 0, 0);
1002*46286Smckusick 				if (stat == 0)
1003*46286Smckusick 					stat = scsi_tt_oddio(hp->hp_ctlr,
1004*46286Smckusick 							     hp->hp_slave,
1005*46286Smckusick 							     sc->sc_punit,
1006*46286Smckusick 							     bp->b_un.b_addr,
1007*46286Smckusick 							     bp->b_bcount - bp->b_resid,
1008*46286Smckusick 							     bp->b_flags, 0);
1009*46286Smckusick 				if (stat) {
1010*46286Smckusick 					bp->b_error = EIO;
1011*46286Smckusick 					bp->b_flags |= B_ERROR;
1012*46286Smckusick 					stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave,
1013*46286Smckusick 						 sc->sc_punit, sc);
1014*46286Smckusick 					sterror(unit, sc, stat);
1015*46286Smckusick 				}
1016*46286Smckusick 			}
1017*46286Smckusick 			break;
1018*46286Smckusick 		}
1019*46286Smckusick 		if (xp->sc_xsense.eom) {
1020*46286Smckusick 			bp->b_flags |= B_ERROR;
1021*46286Smckusick 			bp->b_error = ENOSPC;
1022*46286Smckusick 			break;
1023*46286Smckusick 		}
1024*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: unknown scsi error\n", unit);
1025*46286Smckusick 		bp->b_flags |= B_ERROR;
1026*46286Smckusick 		bp->b_error = EIO;
1027*46286Smckusick 		break;
1028*46286Smckusick 
1029*46286Smckusick 	default:
1030*46286Smckusick 		printf("st%d: stintr unknown stat 0x%x\n", unit, stat);
1031*46286Smckusick 		break;
1032*46286Smckusick 	}
1033*46286Smckusick #ifdef DEBUG
1034*46286Smckusick 	if ((st_debug & ST_BRESID) && bp->b_resid != 0)
1035*46286Smckusick 		printf("b_resid %d b_flags 0x%x b_error 0x%x\n",
1036*46286Smckusick 		       bp->b_resid, bp->b_flags, bp->b_error);
1037*46286Smckusick #endif
1038*46286Smckusick 	/* asked for more filemarks then on tape */
1039*46286Smckusick 	if (bp->b_resid != 0 &&
1040*46286Smckusick 	    (sc->sc_flags & STF_CMD) && sc->sc_cmd == CMD_SPACE) {
1041*46286Smckusick 		sc->sc_filepos -= bp->b_resid;
1042*46286Smckusick 		if (sc->sc_filepos < 0)
1043*46286Smckusick 			sc->sc_filepos = 0;
1044*46286Smckusick 	}
1045*46286Smckusick 
1046*46286Smckusick #ifdef TTI
1047*46286Smckusick 	if (st_extti & (1<<unit) &&
1048*46286Smckusick 	    sc->sc_type == MT_ISEXABYTE) /* to make display lit up */
1049*46286Smckusick 		/*
1050*46286Smckusick 		 * XXX severe performance penality for this.
1051*46286Smckusick 		 * Try and throttle by not calling stxsense on every intr.
1052*46286Smckusick 		 * Mostly for TTi we, get a stxsense call in open and close.
1053*46286Smckusick 		 */
1054*46286Smckusick 		if (sc->sc_tticntdwn-- == 0) {
1055*46286Smckusick 			stxsense(sc->sc_dq.dq_ctlr, sc->sc_dq.dq_slave,
1056*46286Smckusick 				 sc->sc_punit, sc);
1057*46286Smckusick 			sc->sc_tticntdwn = 100;
1058*46286Smckusick 		}
1059*46286Smckusick #endif
1060*46286Smckusick 
1061*46286Smckusick 	stfinish(unit, sc, bp);
1062*46286Smckusick }
1063*46286Smckusick 
1064*46286Smckusick stcommand(dev, command, cnt)
1065*46286Smckusick 	dev_t dev;
1066*46286Smckusick 	u_int command;
1067*46286Smckusick 	int cnt;
1068*46286Smckusick {
1069*46286Smckusick 	register struct st_softc *sc = &st_softc[UNIT(dev)];
1070*46286Smckusick 	register struct buf *bp = &stbuf[UNIT(dev)];
1071*46286Smckusick 	register struct scsi_fmt_cdb *cmd = &stcmd[UNIT(dev)];
1072*46286Smckusick 	register cmdcnt;
1073*46286Smckusick 	int s;
1074*46286Smckusick 
1075*46286Smckusick 	cmd->len = 6; /* all tape commands are cdb6 */
1076*46286Smckusick 	cmd->cdb[1] = sc->sc_punit;
1077*46286Smckusick 	cmd->cdb[2] = cmd->cdb[3] = cmd->cdb[4] = cmd->cdb[5] = 0;
1078*46286Smckusick 	cmdcnt = 0;
1079*46286Smckusick 
1080*46286Smckusick 	/*
1081*46286Smckusick 	 * XXX Assumption is that everything except Archive can take
1082*46286Smckusick 	 * repeat count in cdb block.
1083*46286Smckusick 	 */
1084*46286Smckusick 	switch (command) {
1085*46286Smckusick 	case MTWEOF:
1086*46286Smckusick 		cmd->cdb[0] = CMD_WRITE_FILEMARK;
1087*46286Smckusick 		if (sc->sc_tapeid != MT_ISAR) {
1088*46286Smckusick 			cmdcnt = cnt;
1089*46286Smckusick 			cnt = 1;
1090*46286Smckusick 		} else
1091*46286Smckusick 			cmdcnt = 1;
1092*46286Smckusick 		*(u_char *)(&cmd->cdb[2]) = (u_char) (cmdcnt >> 16);
1093*46286Smckusick 		*(u_char *)(&cmd->cdb[3]) = (u_char) (cmdcnt >> 8);
1094*46286Smckusick 		*(u_char *)(&cmd->cdb[4]) = (u_char) cmdcnt;
1095*46286Smckusick 
1096*46286Smckusick 		if (sc->sc_tapeid == MT_ISEXABYTE &&
1097*46286Smckusick 		    (minor(dev) & STDEV_EXSFMK)) /* short filemarks */
1098*46286Smckusick 			cmd->cdb[5] |= 0x80;
1099*46286Smckusick 		else
1100*46286Smckusick 			cmd->cdb[5] &= 0x7f;
1101*46286Smckusick 		break;
1102*46286Smckusick 	case MTBSF:
1103*46286Smckusick 		/* Archive can't back up, will not get to BSR case */
1104*46286Smckusick 		if (sc->sc_tapeid == MT_ISAR) {
1105*46286Smckusick 			if ((sc->sc_filepos - cnt) < 0) {
1106*46286Smckusick 				stcommand(dev, MTREW, 1);
1107*46286Smckusick 				return;
1108*46286Smckusick 			}
1109*46286Smckusick 			cmdcnt = sc->sc_filepos - cnt + 1;
1110*46286Smckusick 			stcommand(dev, MTREW, 1);
1111*46286Smckusick 			stcommand(dev, MTFSF, cmdcnt);
1112*46286Smckusick 			return;
1113*46286Smckusick 		}
1114*46286Smckusick 	case MTBSR:
1115*46286Smckusick 	case MTFSR:
1116*46286Smckusick 	case MTFSF:
1117*46286Smckusick 		if (command == MTBSF || command == MTBSR)
1118*46286Smckusick 			cnt = cnt * (-1); /* backward move */
1119*46286Smckusick 		if (command == MTFSF || command == MTBSF)
1120*46286Smckusick 			cmd->cdb[1] |= 0x01; /* filemarks */
1121*46286Smckusick 		else
1122*46286Smckusick 			cmd->cdb[1] |= 0x00; /* logical blocks */
1123*46286Smckusick 		if (sc->sc_tapeid != MT_ISAR) {
1124*46286Smckusick 			cmdcnt = cnt;
1125*46286Smckusick 			cnt = 1;
1126*46286Smckusick 		} else
1127*46286Smckusick 			cmdcnt = 1;
1128*46286Smckusick 		*(u_char *)(&cmd->cdb[2]) = (u_char) (cmdcnt >> 16);
1129*46286Smckusick 		*(u_char *)(&cmd->cdb[3]) = (u_char) (cmdcnt >> 8);
1130*46286Smckusick 		*(u_char *)(&cmd->cdb[4]) = (u_char) cmdcnt;
1131*46286Smckusick 		cmd->cdb[0] = CMD_SPACE;
1132*46286Smckusick 		break;
1133*46286Smckusick 	case MTREW:
1134*46286Smckusick 		cmd->cdb[0] = CMD_REWIND;
1135*46286Smckusick 		sc->sc_filepos = 0;
1136*46286Smckusick 		break;
1137*46286Smckusick 	case MTOFFL:
1138*46286Smckusick 		cmd->cdb[0] = CMD_LOADUNLOAD;
1139*46286Smckusick 		sc->sc_filepos = 0;
1140*46286Smckusick 		break;
1141*46286Smckusick 	default:
1142*46286Smckusick 		printf("st%d: stcommand bad command 0x%x\n",
1143*46286Smckusick 		       UNIT(dev), command);
1144*46286Smckusick 	}
1145*46286Smckusick 
1146*46286Smckusick 	sc->sc_flags |= STF_CMD;
1147*46286Smckusick 	sc->sc_cmd = cmd->cdb[0];
1148*46286Smckusick 
1149*46286Smckusick 	sc->sc_bp = bp;
1150*46286Smckusick again:
1151*46286Smckusick #ifdef DEBUG
1152*46286Smckusick 	if (st_debug & ST_FMKS)
1153*46286Smckusick 		printf("st%d: stcommand filepos %d cmdcnt %d cnt %d\n",
1154*46286Smckusick 		       UNIT(dev), sc->sc_filepos, cmdcnt, cnt);
1155*46286Smckusick #endif
1156*46286Smckusick 	s = splbio();
1157*46286Smckusick 	while (bp->b_flags & B_BUSY) {
1158*46286Smckusick 		if (bp->b_flags & B_DONE)
1159*46286Smckusick 			break;
1160*46286Smckusick 		bp->b_flags |= B_WANTED;
1161*46286Smckusick 		sleep((caddr_t)bp, PRIBIO);
1162*46286Smckusick 	}
1163*46286Smckusick 	bp->b_flags = B_BUSY|B_READ;
1164*46286Smckusick 	splx(s);
1165*46286Smckusick 	bp->b_dev = dev;
1166*46286Smckusick 	bp->b_bcount = 0;
1167*46286Smckusick 	bp->b_resid = 0;
1168*46286Smckusick 	bp->b_blkno = 0;
1169*46286Smckusick 	bp->b_error = 0;
1170*46286Smckusick 	ststrategy(bp);
1171*46286Smckusick 	iowait(bp);
1172*46286Smckusick 	if (bp->b_flags & B_WANTED)
1173*46286Smckusick 		wakeup((caddr_t)bp);
1174*46286Smckusick 	bp->b_flags &= B_ERROR;
1175*46286Smckusick 
1176*46286Smckusick 	if (command == MTWEOF || command == MTFSF || command == MTBSF)
1177*46286Smckusick 		sc->sc_filepos += cmdcnt;
1178*46286Smckusick 
1179*46286Smckusick 	if (--cnt > 0)
1180*46286Smckusick 		goto again;
1181*46286Smckusick 
1182*46286Smckusick 	sc->sc_flags |= STF_MOVED;
1183*46286Smckusick 	sc->sc_flags &= ~(STF_CMD|STF_WRTTN);
1184*46286Smckusick }
1185*46286Smckusick 
1186*46286Smckusick sterror(unit, sc, stat)
1187*46286Smckusick 	int unit, stat;
1188*46286Smckusick 	struct st_softc *sc;
1189*46286Smckusick {
1190*46286Smckusick 	/* stxsense must have been called before sterror() */
1191*46286Smckusick 	if (stat & STS_CHECKCOND)
1192*46286Smckusick 		prtkey(unit, sc);
1193*46286Smckusick 	else if (stat)
1194*46286Smckusick 		tprintf(sc->sc_ctty,
1195*46286Smckusick 			"st%d: bad scsi status 0x%x\n", unit, stat);
1196*46286Smckusick 
1197*46286Smckusick 	if ((sc->sc_flags & STF_CMD) && sc->sc_cmd == CMD_SPACE) /* fsf */
1198*46286Smckusick 		sc->sc_filepos--;
1199*46286Smckusick }
1200*46286Smckusick 
1201*46286Smckusick stxsense(ctlr, slave, unit, sc)
1202*46286Smckusick 	int ctlr, slave, unit;
1203*46286Smckusick 	struct st_softc *sc;
1204*46286Smckusick {
1205*46286Smckusick 	u_char *sensebuf;
1206*46286Smckusick 	unsigned len;
1207*46286Smckusick 
1208*46286Smckusick 	sensebuf = (u_char *)&st_xsense[sc->sc_dq.dq_unit];
1209*46286Smckusick 	len = sc->sc_datalen[CMD_REQUEST_SENSE];
1210*46286Smckusick 	scsi_request_sense(ctlr, slave, unit, sensebuf, len);
1211*46286Smckusick }
1212*46286Smckusick 
1213*46286Smckusick prtkey(unit, sc)
1214*46286Smckusick 	int unit;
1215*46286Smckusick 	struct st_softc *sc;
1216*46286Smckusick {
1217*46286Smckusick 	register struct st_xsense *xp = &st_xsense[unit];
1218*46286Smckusick 
1219*46286Smckusick 	switch (xp->sc_xsense.key) {
1220*46286Smckusick 	case XSK_NOSENCE:
1221*46286Smckusick 		break;
1222*46286Smckusick 	case XSK_NOTUSED1:
1223*46286Smckusick 	case XSK_NOTUSEDC:
1224*46286Smckusick 	case XSK_NOTUSEDE:
1225*46286Smckusick 		break;
1226*46286Smckusick 	case XSK_REVERVED:
1227*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: Reserved sense key 0x%x\n",
1228*46286Smckusick 			unit, xp->sc_xsense.key);
1229*46286Smckusick 		break;
1230*46286Smckusick 	case XSK_NOTRDY:
1231*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: NOT READY\n", unit);
1232*46286Smckusick 		break;
1233*46286Smckusick 	case XSK_MEDERR:
1234*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: MEDIUM ERROR\n", unit);
1235*46286Smckusick 		break;
1236*46286Smckusick 	case XSK_HRDWERR:
1237*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: HARDWARE ERROR\n", unit);
1238*46286Smckusick 		break;
1239*46286Smckusick 	case XSK_ILLREQ:
1240*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: ILLEGAL REQUEST\n", unit);
1241*46286Smckusick 		break;
1242*46286Smckusick 	case XSK_UNTATTEN:
1243*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: UNIT ATTENTION\n", unit);
1244*46286Smckusick 		break;
1245*46286Smckusick 	case XSK_DATAPROT:
1246*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: DATA PROTECT\n", unit);
1247*46286Smckusick 		break;
1248*46286Smckusick 	case XSK_BLNKCHK:
1249*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: BLANK CHECK\n", unit);
1250*46286Smckusick 		break;
1251*46286Smckusick 	case XSK_VENDOR:
1252*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: VENDER UNIQUE SENSE KEY ", unit);
1253*46286Smckusick 		switch (sc->sc_tapeid) {
1254*46286Smckusick 		case MT_ISEXABYTE:
1255*46286Smckusick 			tprintf(sc->sc_ctty, "Exabyte: ");
1256*46286Smckusick 			if (xp->exb_xsense.xfr)
1257*46286Smckusick 				tprintf(sc->sc_ctty,
1258*46286Smckusick 					"Transfer Abort Error\n");
1259*46286Smckusick 			if (xp->exb_xsense.tmd)
1260*46286Smckusick 				tprintf(sc->sc_ctty,
1261*46286Smckusick 					"Tape Mark Detect Error\n");
1262*46286Smckusick 			break;
1263*46286Smckusick 		default:
1264*46286Smckusick 			tprintf(sc->sc_ctty, "\n");
1265*46286Smckusick 		}
1266*46286Smckusick 		break;
1267*46286Smckusick 	case XSK_CPYABORT:
1268*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: COPY ABORTED\n", unit);
1269*46286Smckusick 		break;
1270*46286Smckusick 	case XSK_ABORTCMD:
1271*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: ABORTED COMMAND\n", unit);
1272*46286Smckusick 		break;
1273*46286Smckusick 	case XSK_VOLOVER:
1274*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: VOLUME OVERFLOW\n", unit);
1275*46286Smckusick 		break;
1276*46286Smckusick 	default:
1277*46286Smckusick 		tprintf(sc->sc_ctty, "st%d: unknown sense key 0x%x\n",
1278*46286Smckusick 			unit, xp->sc_xsense.key);
1279*46286Smckusick 	}
1280*46286Smckusick 	if (sc->sc_tapeid == MT_ISEXABYTE) {
1281*46286Smckusick 		if (xp->exb_xsense.bpe)
1282*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: Bus Parity Errorn", unit);
1283*46286Smckusick 		if (xp->exb_xsense.fpe)
1284*46286Smckusick 			tprintf(sc->sc_ctty,
1285*46286Smckusick 				"st%d: Formatted Buffer Parity Errorn", unit);
1286*46286Smckusick 		if (xp->exb_xsense.eco)
1287*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: Error Counter Overflown",
1288*46286Smckusick 				unit);
1289*46286Smckusick 		if (xp->exb_xsense.tme)
1290*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: Tape Motion Errorn", unit);
1291*46286Smckusick 		if (xp->exb_xsense.xfr)
1292*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: Transfer About Errorn",
1293*46286Smckusick 				unit);
1294*46286Smckusick 		if (xp->exb_xsense.tmd)
1295*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: Tape Mark Detect Errorn",
1296*46286Smckusick 				unit);
1297*46286Smckusick 		if (xp->exb_xsense.fmke)
1298*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: Filemark Errorn", unit);
1299*46286Smckusick 		if (xp->exb_xsense.ure)
1300*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: Under Run Errorn", unit);
1301*46286Smckusick 		if (xp->exb_xsense.sse)
1302*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: Servo System Errorn",
1303*46286Smckusick 				unit);
1304*46286Smckusick 		if (xp->exb_xsense.fe)
1305*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: Formatter Errorn", unit);
1306*46286Smckusick 		if (xp->exb_xsense.wseb)
1307*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: WSEB Errorn", unit);
1308*46286Smckusick 		if (xp->exb_xsense.wseo)
1309*46286Smckusick 			tprintf(sc->sc_ctty, "st%d: WSEO Errorn", unit);
1310*46286Smckusick 	}
1311*46286Smckusick }
1312*46286Smckusick 
1313*46286Smckusick #ifdef DEBUG
1314*46286Smckusick 
1315*46286Smckusick dumpxsense(sensebuf)
1316*46286Smckusick 	struct st_xsense *sensebuf;
1317*46286Smckusick {
1318*46286Smckusick         struct st_xsense *xp = sensebuf;
1319*46286Smckusick 
1320*46286Smckusick 	printf("valid 0x%x errorclass 0x%x errorcode 0x%x\n",
1321*46286Smckusick 	       xp->sc_xsense.valid,
1322*46286Smckusick 	       xp->sc_xsense.class, xp->sc_xsense.code);
1323*46286Smckusick 	printf("seg number 0x%x\n", xp->sc_xsense.segment);
1324*46286Smckusick 	printf("FMK 0x%x EOM 0x%x ILI 0x%x RSVD 0x%x sensekey 0x%x\n",
1325*46286Smckusick 	       xp->sc_xsense.filemark, xp->sc_xsense.eom, xp->sc_xsense.ili,
1326*46286Smckusick 	       xp->sc_xsense.rsvd, xp->sc_xsense.key);
1327*46286Smckusick 	printf("info 0x%lx\n",
1328*46286Smckusick 	       (u_long)((xp->sc_xsense.info1<<24)|(xp->sc_xsense.info2<<16)|
1329*46286Smckusick 			(xp->sc_xsense.info3<<8)|(xp->sc_xsense.info4)) );
1330*46286Smckusick 	printf("ASenseL 0x%x\n", xp->sc_xsense.len);
1331*46286Smckusick 
1332*46286Smckusick 	if (xp->sc_xsense.len != 0x12) /* MT_ISEXB Exabyte only ?? */
1333*46286Smckusick 		return;			/* What about others */
1334*46286Smckusick 
1335*46286Smckusick 	printf("ASenseC 0x%x\n", xp->exb_xsense.addsens);
1336*46286Smckusick 	printf("AsenseQ 0x%x\n", xp->exb_xsense.addsensq);
1337*46286Smckusick 	printf("R/W Errors 0x%lx\n",
1338*46286Smckusick 	       (u_long)((xp->exb_xsense.rwerrcnt2<<16)|
1339*46286Smckusick 			(xp->exb_xsense.rwerrcnt1<<8)|
1340*46286Smckusick 			(xp->exb_xsense.rwerrcnt1)) );
1341*46286Smckusick 	printf("PF   0x%x BPE  0x%x FPE 0x%x ME   0x%x ECO 0x%x TME 0x%x TNP 0x%x BOT 0x%x\n",
1342*46286Smckusick 	       xp->exb_xsense.pf, xp->exb_xsense.bpe, xp->exb_xsense.fpe,
1343*46286Smckusick 	       xp->exb_xsense.me, xp->exb_xsense.eco, xp->exb_xsense.tme,
1344*46286Smckusick 	       xp->exb_xsense.tnp, xp->exb_xsense.bot);
1345*46286Smckusick 	printf("XFR  0x%x TMD  0x%x WP  0x%x FMKE 0x%x URE 0x%x WE1 0x%x SSE 0x%x FE  0x%x\n",
1346*46286Smckusick 	       xp->exb_xsense.xfr, xp->exb_xsense.tmd, xp->exb_xsense.wp,
1347*46286Smckusick 	       xp->exb_xsense.fmke, xp->exb_xsense.ure, xp->exb_xsense.we1,
1348*46286Smckusick 	       xp->exb_xsense.sse, xp->exb_xsense.fe);
1349*46286Smckusick 	printf("WSEB 0x%x WSEO 0x%x\n",
1350*46286Smckusick 	       xp->exb_xsense.wseb, xp->exb_xsense.wseo);
1351*46286Smckusick 	printf("Remaining Tape 0x%lx\n",
1352*46286Smckusick 	       (u_long)((xp->exb_xsense.tplft2<<16)|
1353*46286Smckusick 			(xp->exb_xsense.tplft1<<8)|
1354*46286Smckusick 			(xp->exb_xsense.tplft0)) );
1355*46286Smckusick }
1356*46286Smckusick 
1357*46286Smckusick prtmodsel(msd, modlen)
1358*46286Smckusick 	struct mode_select_data *msd;
1359*46286Smckusick 	int modlen;
1360*46286Smckusick {
1361*46286Smckusick 	printf("Modsel command. len is 0x%x.\n", modlen);
1362*46286Smckusick 	printf("rsvd1 0x%x rsvd2 0x%x rsvd3 0x%x bufferd 0x%x speed 0x%x bckdeslen 0x%x\n",
1363*46286Smckusick 	       msd->rsvd1,msd->rsvd2,msd->rsvd3,msd->buff,msd->speed,msd->blkdeslen);
1364*46286Smckusick 	printf("density 0x%x blks2 0x%x blks1 0x%x blks0 0x%x rsvd 0x%x blklen2 0x%x blklen1 0x%x blklen0 0x%x\n",
1365*46286Smckusick 	       msd->density,msd->blks2,msd->blks1,msd->blks0,msd->rsvd4,msd->blklen2,msd->blklen1,msd->blklen0);
1366*46286Smckusick 	printf("vupb 0x%x rsvd 0x%x p5 0x%x motionthres 0x%x reconthres 0x%x gapthres 0x%x \n",
1367*46286Smckusick 	       msd->vupb,msd->rsvd5,msd->p5,msd->motionthres,msd->reconthres,msd->gapthres);
1368*46286Smckusick }
1369*46286Smckusick 
1370*46286Smckusick prtmodstat(mode)
1371*46286Smckusick 	struct mode_sense *mode;
1372*46286Smckusick {
1373*46286Smckusick 	printf("Mode Status\n");
1374*46286Smckusick 	printf("sdl 0x%x medtype 0x%x wp 0x%x bfmd 0x%x speed 0x%x bdl 0x%x\n",
1375*46286Smckusick 	       mode->md.sdl, mode->md.medtype, mode->md.wp, mode->md.bfmd,
1376*46286Smckusick 	       mode->md.speed, mode->md.bdl);
1377*46286Smckusick 	printf("dencod 0x%x numblk 0x%x blklen 0x%x\n",
1378*46286Smckusick 	       mode->md.dencod,
1379*46286Smckusick 	       (mode->md.numblk2<<16)|(mode->md.numblk1<<8)|(mode->md.numblk0),
1380*46286Smckusick 	       (mode->md.blklen2<<16)|(mode->md.blklen1<<8)|(mode->md.blklen0) );
1381*46286Smckusick 	printf("ct 0x%x nd 0x%x nbe 0x%x edb 0x%x pe 0x%x nal 0x%x p5 0x%x\n",
1382*46286Smckusick 	       mode->ex.ct, mode->ex.nd, mode->ex.nbe,
1383*46286Smckusick 	       mode->ex.ebd, mode->ex.pe, mode->ex.nal, mode->ex.p5);
1384*46286Smckusick 	printf("motionthres 0x%x reconthres 0x%x gapthres 0x%x\n",
1385*46286Smckusick 	       mode->ex.motionthres, mode->ex.reconthres,  mode->ex.gapthres);
1386*46286Smckusick }
1387*46286Smckusick #endif /* DEBUG */
1388*46286Smckusick 
1389*46286Smckusick #endif
1390