scsi_sa.c revision 83366
1/*
2 * $FreeBSD: head/sys/cam/scsi/scsi_sa.c 83366 2001-09-12 08:38:13Z julian $
3 *
4 * Implementation of SCSI Sequential Access Peripheral driver for CAM.
5 *
6 * Copyright (c) 1999, 2000 Matthew Jacob
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions, and the following disclaimer,
14 *    without modification, immediately at the beginning of the file.
15 * 2. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 */
31
32#include <sys/param.h>
33#include <sys/queue.h>
34#ifdef _KERNEL
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#endif
38#include <sys/types.h>
39#include <sys/bio.h>
40#include <sys/malloc.h>
41#include <sys/mtio.h>
42#ifdef _KERNEL
43#include <sys/conf.h>
44#endif
45#include <sys/devicestat.h>
46#include <machine/limits.h>
47
48#ifndef _KERNEL
49#include <stdio.h>
50#include <string.h>
51#endif
52
53#include <cam/cam.h>
54#include <cam/cam_ccb.h>
55#include <cam/cam_extend.h>
56#include <cam/cam_periph.h>
57#include <cam/cam_xpt_periph.h>
58#include <cam/cam_debug.h>
59
60#include <cam/scsi/scsi_all.h>
61#include <cam/scsi/scsi_message.h>
62#include <cam/scsi/scsi_sa.h>
63
64#ifdef _KERNEL
65
66#include <opt_sa.h>
67
68#ifndef SA_IO_TIMEOUT
69#define SA_IO_TIMEOUT		4
70#endif
71#ifndef SA_SPACE_TIMEOUT
72#define SA_SPACE_TIMEOUT	1 * 60
73#endif
74#ifndef SA_REWIND_TIMEOUT
75#define SA_REWIND_TIMEOUT	2 * 60
76#endif
77#ifndef SA_ERASE_TIMEOUT
78#define SA_ERASE_TIMEOUT	4 * 60
79#endif
80
81#define	SCSIOP_TIMEOUT		(60 * 1000)	/* not an option */
82
83#define	IO_TIMEOUT		(SA_IO_TIMEOUT * 60 * 1000)
84#define	REWIND_TIMEOUT		(SA_REWIND_TIMEOUT * 60 * 1000)
85#define	ERASE_TIMEOUT		(SA_ERASE_TIMEOUT * 60 * 1000)
86#define	SPACE_TIMEOUT		(SA_SPACE_TIMEOUT * 60 * 1000)
87
88/*
89 * Additional options that can be set for config: SA_1FM_AT_EOT
90 */
91
92#ifndef	UNUSED_PARAMETER
93#define	UNUSED_PARAMETER(x)	x = x
94#endif
95
96#define	QFRLS(ccb)	\
97	if (((ccb)->ccb_h.status & CAM_DEV_QFRZN) != 0)	\
98		cam_release_devq((ccb)->ccb_h.path, 0, 0, 0, FALSE)
99
100/*
101 * Driver states
102 */
103
104
105typedef enum {
106	SA_STATE_NORMAL, SA_STATE_ABNORMAL
107} sa_state;
108
109#define ccb_pflags	ppriv_field0
110#define ccb_bp	 	ppriv_ptr1
111
112#define	SA_CCB_BUFFER_IO	0x0
113#define	SA_CCB_WAITING		0x1
114#define	SA_CCB_TYPEMASK		0x1
115#define	SA_POSITION_UPDATED	0x2
116
117#define	Set_CCB_Type(x, type)				\
118	x->ccb_h.ccb_pflags &= ~SA_CCB_TYPEMASK;	\
119	x->ccb_h.ccb_pflags |= type
120
121#define	CCB_Type(x)	(x->ccb_h.ccb_pflags & SA_CCB_TYPEMASK)
122
123
124
125typedef enum {
126	SA_FLAG_OPEN		= 0x0001,
127	SA_FLAG_FIXED		= 0x0002,
128	SA_FLAG_TAPE_LOCKED	= 0x0004,
129	SA_FLAG_TAPE_MOUNTED	= 0x0008,
130	SA_FLAG_TAPE_WP		= 0x0010,
131	SA_FLAG_TAPE_WRITTEN	= 0x0020,
132	SA_FLAG_EOM_PENDING	= 0x0040,
133	SA_FLAG_EIO_PENDING	= 0x0080,
134	SA_FLAG_EOF_PENDING	= 0x0100,
135	SA_FLAG_ERR_PENDING	= (SA_FLAG_EOM_PENDING|SA_FLAG_EIO_PENDING|
136				   SA_FLAG_EOF_PENDING),
137	SA_FLAG_INVALID		= 0x0200,
138	SA_FLAG_COMP_ENABLED	= 0x0400,
139	SA_FLAG_COMP_SUPP	= 0x0800,
140	SA_FLAG_COMP_UNSUPP	= 0x1000,
141	SA_FLAG_TAPE_FROZEN	= 0x2000
142} sa_flags;
143
144typedef enum {
145	SA_MODE_REWIND		= 0x00,
146	SA_MODE_NOREWIND	= 0x01,
147	SA_MODE_OFFLINE		= 0x02
148} sa_mode;
149
150typedef enum {
151	SA_PARAM_NONE		= 0x00,
152	SA_PARAM_BLOCKSIZE	= 0x01,
153	SA_PARAM_DENSITY	= 0x02,
154	SA_PARAM_COMPRESSION	= 0x04,
155	SA_PARAM_BUFF_MODE	= 0x08,
156	SA_PARAM_NUMBLOCKS	= 0x10,
157	SA_PARAM_WP		= 0x20,
158	SA_PARAM_SPEED		= 0x40,
159	SA_PARAM_ALL		= 0x7f
160} sa_params;
161
162typedef enum {
163	SA_QUIRK_NONE		= 0x00,
164	SA_QUIRK_NOCOMP		= 0x01,	/* Can't deal with compression at all */
165	SA_QUIRK_FIXED		= 0x02,	/* Force fixed mode */
166	SA_QUIRK_VARIABLE	= 0x04,	/* Force variable mode */
167	SA_QUIRK_2FM		= 0x08,	/* Needs Two File Marks at EOD */
168	SA_QUIRK_1FM		= 0x10,	/* No more than 1 File Mark at EOD */
169	SA_QUIRK_NODREAD	= 0x20,	/* Don't try and dummy read density */
170	SA_QUIRK_NO_MODESEL	= 0x40,	/* Don't do mode select at all */
171	SA_QUIRK_NO_CPAGE	= 0x80	/* Don't use DEVICE COMPRESSION page */
172} sa_quirks;
173
174/* units are bits 4-7, 16-21 (1024 units) */
175#define SAUNIT(DEV) \
176	(((minor(DEV) & 0xF0) >> 4) |  ((minor(DEV) & 0x3f0000) >> 16))
177
178#define SAMODE(z) ((minor(z) & 0x3))
179#define SADENSITY(z) (((minor(z) >> 2) & 0x3))
180#define	SA_IS_CTRL(z) (minor(z) & (1 << 29))
181
182#define SA_NOT_CTLDEV	0
183#define SA_CTLDEV	1
184
185#define SA_ATYPE_R	0
186#define SA_ATYPE_NR	1
187#define SA_ATYPE_ER	2
188
189#define SAMINOR(ctl, unit, mode, access) \
190	((ctl << 29) | ((unit & 0x3f0) << 16) | ((unit & 0xf) << 4) | \
191	(mode << 0x2) | (access & 0x3))
192
193#define SA_NUM_MODES	4
194struct sa_devs {
195	dev_t	ctl_dev;
196	struct sa_mode_devs {
197		dev_t	r_dev;
198		dev_t	nr_dev;
199		dev_t	er_dev;
200	} mode_devs[SA_NUM_MODES];
201};
202
203struct sa_softc {
204	sa_state	state;
205	sa_flags	flags;
206	sa_quirks	quirks;
207	struct		bio_queue_head bio_queue;
208	int		queue_count;
209	struct		devstat device_stats;
210	struct sa_devs	devs;
211	int		blk_gran;
212	int		blk_mask;
213	int		blk_shift;
214	u_int32_t	max_blk;
215	u_int32_t	min_blk;
216	u_int32_t	comp_algorithm;
217	u_int32_t	saved_comp_algorithm;
218	u_int32_t	media_blksize;
219	u_int32_t	last_media_blksize;
220	u_int32_t	media_numblks;
221	u_int8_t	media_density;
222	u_int8_t	speed;
223	u_int8_t	scsi_rev;
224	u_int8_t	dsreg;		/* mtio mt_dsreg, redux */
225	int		buffer_mode;
226	int		filemarks;
227	union		ccb saved_ccb;
228	int		last_resid_was_io;
229
230	/*
231	 * Relative to BOT Location.
232	 */
233	daddr_t		fileno;
234	daddr_t		blkno;
235
236	/*
237	 * Latched Error Info
238	 */
239	struct {
240		struct scsi_sense_data _last_io_sense;
241		u_int32_t _last_io_resid;
242		u_int8_t _last_io_cdb[CAM_MAX_CDBLEN];
243		struct scsi_sense_data _last_ctl_sense;
244		u_int32_t _last_ctl_resid;
245		u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN];
246#define	last_io_sense	errinfo._last_io_sense
247#define	last_io_resid	errinfo._last_io_resid
248#define	last_io_cdb	errinfo._last_io_cdb
249#define	last_ctl_sense	errinfo._last_ctl_sense
250#define	last_ctl_resid	errinfo._last_ctl_resid
251#define	last_ctl_cdb	errinfo._last_ctl_cdb
252	} errinfo;
253	/*
254	 * Misc other flags/state
255	 */
256	u_int32_t
257				: 31,
258		ctrl_mode	: 1;	/* control device open */
259};
260
261struct sa_quirk_entry {
262	struct scsi_inquiry_pattern inq_pat;	/* matching pattern */
263	sa_quirks quirks;	/* specific quirk type */
264	u_int32_t prefblk;	/* preferred blocksize when in fixed mode */
265};
266
267static struct sa_quirk_entry sa_quirk_table[] =
268{
269	{
270		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "OnStream",
271		  "ADR*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_NODREAD |
272		   SA_QUIRK_1FM|SA_QUIRK_NO_MODESEL, 32768
273	},
274	{
275		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
276		  "Python 06408*", "*"}, SA_QUIRK_NODREAD, 0
277	},
278	{
279		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
280		  "Python 25601*", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_NODREAD, 0
281	},
282	{
283		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
284		  "Python*", "*"}, SA_QUIRK_NODREAD, 0
285	},
286	{
287		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
288		  "VIPER 150*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
289	},
290	{
291		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
292		  "VIPER 2525 25462", "-011"},
293		  SA_QUIRK_NOCOMP|SA_QUIRK_1FM|SA_QUIRK_NODREAD, 0
294	},
295	{
296		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
297		  "VIPER 2525*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024
298	},
299#if	0
300	{
301		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
302		  "C15*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_NO_CPAGE, 0,
303	},
304#endif
305	{
306		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
307		  "T20*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
308	},
309	{
310		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
311		  "T4000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
312	},
313	{
314		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
315		  "HP-88780*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
316	},
317	{
318		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY",
319		  "*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
320	},
321	{
322		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "M4 DATA",
323		  "123107 SCSI*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
324	},
325	{	/* jreynold@primenet.com */
326		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate",
327		"STT8000N*", "*"}, SA_QUIRK_1FM, 0
328	},
329	{	/* mike@sentex.net */
330		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate",
331		"STT20000*", "*"}, SA_QUIRK_1FM, 0
332	},
333	{
334		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
335		  " TDC 3600", "U07:"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
336	},
337	{
338		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
339		  " TDC 3800", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
340	},
341	{
342		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
343		  " TDC 4100", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
344	},
345	{
346		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
347		  " TDC 4200", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
348	},
349	{
350		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
351		  " SLR*", "*"}, SA_QUIRK_1FM, 0
352	},
353	{
354		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK",
355		  "5525ES*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
356	},
357	{
358		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK",
359		  "51000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024
360	}
361};
362
363static	d_open_t	saopen;
364static	d_close_t	saclose;
365static	d_strategy_t	sastrategy;
366static	d_ioctl_t	saioctl;
367static	periph_init_t	sainit;
368static	periph_ctor_t	saregister;
369static	periph_oninv_t	saoninvalidate;
370static	periph_dtor_t	sacleanup;
371static	periph_start_t	sastart;
372static	void		saasync(void *callback_arg, u_int32_t code,
373				struct cam_path *path, void *arg);
374static	void		sadone(struct cam_periph *periph,
375			       union ccb *start_ccb);
376static  int		saerror(union ccb *ccb, u_int32_t cam_flags,
377				u_int32_t sense_flags);
378static int		samarkswanted(struct cam_periph *);
379static int		sacheckeod(struct cam_periph *periph);
380static int		sagetparams(struct cam_periph *periph,
381				    sa_params params_to_get,
382				    u_int32_t *blocksize, u_int8_t *density,
383				    u_int32_t *numblocks, int *buff_mode,
384				    u_int8_t *write_protect, u_int8_t *speed,
385				    int *comp_supported, int *comp_enabled,
386				    u_int32_t *comp_algorithm,
387				    sa_comp_t *comp_page);
388static int		sasetparams(struct cam_periph *periph,
389				    sa_params params_to_set,
390				    u_int32_t blocksize, u_int8_t density,
391				    u_int32_t comp_algorithm,
392				    u_int32_t sense_flags);
393static void		saprevent(struct cam_periph *periph, int action);
394static int		sarewind(struct cam_periph *periph);
395static int		saspace(struct cam_periph *periph, int count,
396				scsi_space_code code);
397static int		samount(struct cam_periph *, int, dev_t);
398static int		saretension(struct cam_periph *periph);
399static int		sareservereleaseunit(struct cam_periph *periph,
400					     int reserve);
401static int		saloadunload(struct cam_periph *periph, int load);
402static int		saerase(struct cam_periph *periph, int longerase);
403static int		sawritefilemarks(struct cam_periph *periph,
404					 int nmarks, int setmarks);
405static int		sardpos(struct cam_periph *periph, int, u_int32_t *);
406static int		sasetpos(struct cam_periph *periph, int, u_int32_t *);
407
408
409static struct periph_driver sadriver =
410{
411	sainit, "sa",
412	TAILQ_HEAD_INITIALIZER(sadriver.units), /* generation */ 0
413};
414
415PERIPHDRIVER_DECLARE(sa, sadriver);
416
417/* For 2.2-stable support */
418#ifndef D_TAPE
419#define D_TAPE 0
420#endif
421
422#define SA_CDEV_MAJOR 14
423
424static struct cdevsw sa_cdevsw = {
425	/* open */	saopen,
426	/* close */	saclose,
427	/* read */	physread,
428	/* write */	physwrite,
429	/* ioctl */	saioctl,
430	/* poll */	nopoll,
431	/* mmap */	nommap,
432	/* strategy */	sastrategy,
433	/* name */	"sa",
434	/* maj */	SA_CDEV_MAJOR,
435	/* dump */	nodump,
436	/* psize */	nopsize,
437	/* flags */	D_TAPE,
438};
439
440static struct extend_array *saperiphs;
441
442static int
443saopen(dev_t dev, int flags, int fmt, struct thread *td)
444{
445	struct cam_periph *periph;
446	struct sa_softc *softc;
447	int unit;
448	int mode;
449	int density;
450	int error;
451	int s;
452
453	unit = SAUNIT(dev);
454	mode = SAMODE(dev);
455	density = SADENSITY(dev);
456
457	s = splsoftcam();
458	periph = cam_extend_get(saperiphs, unit);
459	if (periph == NULL) {
460		(void) splx(s);
461		return (ENXIO);
462	}
463	softc = (struct sa_softc *)periph->softc;
464	if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
465		splx(s);
466		return (error);
467	}
468	splx(s);
469
470	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO,
471	    ("saopen(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
472
473	if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
474		cam_periph_unlock(periph);
475		return (ENXIO);
476	}
477	if (SA_IS_CTRL(dev)) {
478		softc->ctrl_mode = 1;
479		cam_periph_unlock(periph);
480		return (0);
481	}
482
483
484	if (softc->flags & SA_FLAG_OPEN) {
485		error = EBUSY;
486	} else if (softc->flags & SA_FLAG_INVALID) {
487		error = ENXIO;
488	} else {
489		/*
490		 * The function samount ensures media is loaded and ready.
491		 * It also does a device RESERVE if the tape isn't yet mounted.
492		 */
493		error = samount(periph, flags, dev);
494	}
495
496	if (error) {
497		cam_periph_release(periph);
498	} else {
499		saprevent(periph, PR_PREVENT);
500		softc->flags |= SA_FLAG_OPEN;
501	}
502	cam_periph_unlock(periph);
503	return (error);
504}
505
506static int
507saclose(dev_t dev, int flag, int fmt, struct thread *td)
508{
509	struct	cam_periph *periph;
510	struct	sa_softc *softc;
511	int	unit, mode, error, writing, tmp;
512	int	closedbits = SA_FLAG_OPEN;
513
514	unit = SAUNIT(dev);
515	mode = SAMODE(dev);
516	periph = cam_extend_get(saperiphs, unit);
517	if (periph == NULL)
518		return (ENXIO);
519
520	softc = (struct sa_softc *)periph->softc;
521
522	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO,
523	    ("saclose(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
524
525
526	if ((error = cam_periph_lock(periph, PRIBIO)) != 0) {
527		return (error);
528	}
529
530	if (SA_IS_CTRL(dev)) {
531		softc->ctrl_mode = 0;
532		cam_periph_release(periph);
533		cam_periph_unlock(periph);
534		return (0);
535	}
536
537	/*
538	 * Were we writing the tape?
539	 */
540	writing = (softc->flags & SA_FLAG_TAPE_WRITTEN) != 0;
541
542	/*
543	 * See whether or not we need to write filemarks. If this
544	 * fails, we probably have to assume we've lost tape
545	 * position.
546	 */
547	error = sacheckeod(periph);
548	if (error) {
549		xpt_print_path(periph->path);
550		printf("failed to write terminating filemark(s)\n");
551		softc->flags |= SA_FLAG_TAPE_FROZEN;
552	}
553
554	/*
555	 * Whatever we end up doing, allow users to eject tapes from here on.
556	 */
557	saprevent(periph, PR_ALLOW);
558
559	/*
560	 * Decide how to end...
561	 */
562	if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) {
563		closedbits |= SA_FLAG_TAPE_FROZEN;
564	} else switch (mode) {
565	case SA_MODE_OFFLINE:
566		/*
567		 * An 'offline' close is an unconditional release of
568		 * frozen && mount conditions, irrespective of whether
569		 * these operations succeeded. The reason for this is
570		 * to allow at least some kind of programmatic way
571		 * around our state getting all fouled up. If somebody
572		 * issues an 'offline' command, that will be allowed
573		 * to clear state.
574		 */
575		(void) sarewind(periph);
576		(void) saloadunload(periph, FALSE);
577		closedbits |= SA_FLAG_TAPE_MOUNTED|SA_FLAG_TAPE_FROZEN;
578		break;
579	case SA_MODE_REWIND:
580		/*
581		 * If the rewind fails, return an error- if anyone cares,
582		 * but not overwriting any previous error.
583		 *
584		 * We don't clear the notion of mounted here, but we do
585		 * clear the notion of frozen if we successfully rewound.
586		 */
587		tmp = sarewind(periph);
588		if (tmp) {
589			if (error != 0)
590				error = tmp;
591		} else {
592			closedbits |= SA_FLAG_TAPE_FROZEN;
593		}
594		break;
595	case SA_MODE_NOREWIND:
596		/*
597		 * If we're not rewinding/unloading the tape, find out
598		 * whether we need to back up over one of two filemarks
599		 * we wrote (if we wrote two filemarks) so that appends
600		 * from this point on will be sane.
601		 */
602		if (error == 0 && writing && (softc->quirks & SA_QUIRK_2FM)) {
603			tmp = saspace(periph, -1, SS_FILEMARKS);
604			if (tmp) {
605				xpt_print_path(periph->path);
606				printf("unable to backspace over one of double"
607				   " filemarks at end of tape\n");
608				xpt_print_path(periph->path);
609				printf("it is possible that this device"
610				   " needs a SA_QUIRK_1FM quirk set for it\n");
611				softc->flags |= SA_FLAG_TAPE_FROZEN;
612			}
613		}
614		break;
615	default:
616		xpt_print_path(periph->path);
617		panic("unknown mode 0x%x in saclose\n", mode);
618		/* NOTREACHED */
619		break;
620	}
621
622	/*
623	 * We wish to note here that there are no more filemarks to be written.
624	 */
625	softc->filemarks = 0;
626	softc->flags &= ~SA_FLAG_TAPE_WRITTEN;
627
628	/*
629	 * And we are no longer open for business.
630	 */
631	softc->flags &= ~closedbits;
632
633	/*
634	 * Inform users if tape state if frozen....
635	 */
636	if (softc->flags & SA_FLAG_TAPE_FROZEN) {
637		xpt_print_path(periph->path);
638		printf("tape is now frozen- use an OFFLINE, REWIND or MTEOM "
639		    "command to clear this state.\n");
640	}
641
642	/* release the device if it is no longer mounted */
643	if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0)
644		sareservereleaseunit(periph, FALSE);
645
646	cam_periph_unlock(periph);
647	cam_periph_release(periph);
648
649	return (error);
650}
651
652/*
653 * Actually translate the requested transfer into one the physical driver
654 * can understand.  The transfer is described by a buf and will include
655 * only one physical transfer.
656 */
657static void
658sastrategy(struct bio *bp)
659{
660	struct cam_periph *periph;
661	struct sa_softc *softc;
662	u_int  unit;
663	int    s;
664
665	bp->bio_resid = bp->bio_bcount;
666	if (SA_IS_CTRL(bp->bio_dev)) {
667		biofinish(bp, NULL, EINVAL);
668		return;
669	}
670	unit = SAUNIT(bp->bio_dev);
671	periph = cam_extend_get(saperiphs, unit);
672	if (periph == NULL) {
673		biofinish(bp, NULL, ENXIO);
674		return;
675	}
676	softc = (struct sa_softc *)periph->softc;
677
678	s = splsoftcam();
679
680	if (softc->flags & SA_FLAG_INVALID) {
681		splx(s);
682		biofinish(bp, NULL, ENXIO);
683		return;
684	}
685
686	if (softc->flags & SA_FLAG_TAPE_FROZEN) {
687		splx(s);
688		biofinish(bp, NULL, EPERM);
689		return;
690	}
691
692	splx(s);
693
694	/*
695	 * If it's a null transfer, return immediatly
696	 */
697	if (bp->bio_bcount == 0) {
698		biodone(bp);
699		return;
700	}
701
702	/* valid request?  */
703	if (softc->flags & SA_FLAG_FIXED) {
704		/*
705		 * Fixed block device.  The byte count must
706		 * be a multiple of our block size.
707		 */
708		if (((softc->blk_mask != ~0) &&
709		    ((bp->bio_bcount & softc->blk_mask) != 0)) ||
710		    ((softc->blk_mask == ~0) &&
711		    ((bp->bio_bcount % softc->min_blk) != 0))) {
712			xpt_print_path(periph->path);
713			printf("Invalid request.  Fixed block device "
714			       "requests must be a multiple "
715			       "of %d bytes\n", softc->min_blk);
716			biofinish(bp, NULL, EINVAL);
717			return;
718		}
719	} else if ((bp->bio_bcount > softc->max_blk) ||
720		   (bp->bio_bcount < softc->min_blk) ||
721		   (bp->bio_bcount & softc->blk_mask) != 0) {
722
723		xpt_print_path(periph->path);
724		printf("Invalid request.  Variable block device "
725		    "requests must be ");
726		if (softc->blk_mask != 0) {
727			printf("a multiple of %d ", (0x1 << softc->blk_gran));
728		}
729		printf("between %d and %d bytes\n", softc->min_blk,
730		    softc->max_blk);
731		biofinish(bp, NULL, EINVAL);
732		return;
733        }
734
735	/*
736	 * Mask interrupts so that the device cannot be invalidated until
737	 * after we are in the queue.  Otherwise, we might not properly
738	 * clean up one of the buffers.
739	 */
740	s = splbio();
741
742	/*
743	 * Place it at the end of the queue.
744	 */
745	bioq_insert_tail(&softc->bio_queue, bp);
746
747	softc->queue_count++;
748	CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("sastrategy: enqueuing a %d "
749	    "%s byte %s queue count now %d\n", (int) bp->bio_bcount,
750	     (softc->flags & SA_FLAG_FIXED)?  "fixed" : "variable",
751	     (bp->bio_cmd == BIO_READ)? "read" : "write", softc->queue_count));
752
753	splx(s);
754
755	/*
756	 * Schedule ourselves for performing the work.
757	 */
758	xpt_schedule(periph, 1);
759
760	return;
761}
762
763static int
764saioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
765{
766	struct cam_periph *periph;
767	struct sa_softc *softc;
768	scsi_space_code spaceop;
769	int didlockperiph = 0;
770	int s;
771	int unit;
772	int mode;
773	int density;
774	int error = 0;
775
776	unit = SAUNIT(dev);
777	mode = SAMODE(dev);
778	density = SADENSITY(dev);
779	error = 0;		/* shut up gcc */
780	spaceop = 0;		/* shut up gcc */
781
782	periph = cam_extend_get(saperiphs, unit);
783	if (periph == NULL)
784		return (ENXIO);
785
786	softc = (struct sa_softc *)periph->softc;
787
788	/*
789	 * Check for control mode accesses. We allow MTIOCGET and
790	 * MTIOCERRSTAT (but need to be the only one open in order
791	 * to clear latched status), and MTSETBSIZE, MTSETDNSTY
792	 * and MTCOMP (but need to be the only one accessing this
793	 * device to run those).
794	 */
795
796	if (SA_IS_CTRL(dev)) {
797		switch (cmd) {
798		case MTIOCGETEOTMODEL:
799		case MTIOCGET:
800			break;
801		case MTIOCERRSTAT:
802			/*
803			 * If the periph isn't already locked, lock it
804			 * so our MTIOCERRSTAT can reset latched error stats.
805			 *
806			 * If the periph is already locked, skip it because
807			 * we're just getting status and it'll be up to the
808			 * other thread that has this device open to do
809			 * an MTIOCERRSTAT that would clear latched status.
810			 */
811			s = splsoftcam();
812			if ((periph->flags & CAM_PERIPH_LOCKED) == 0) {
813				error = cam_periph_lock(periph, PRIBIO|PCATCH);
814				if (error != 0) {
815					splx(s);
816					return (error);
817				}
818				didlockperiph = 1;
819			}
820			break;
821
822		case MTIOCSETEOTMODEL:
823		case MTSETBSIZ:
824		case MTSETDNSTY:
825		case MTCOMP:
826			/*
827			 * We need to acquire the peripheral here rather
828			 * than at open time because we are sharing writable
829			 * access to data structures.
830			 */
831			s = splsoftcam();
832			error = cam_periph_lock(periph, PRIBIO|PCATCH);
833			if (error != 0) {
834				splx(s);
835				return (error);
836			}
837			didlockperiph = 1;
838			break;
839
840		default:
841			return (EINVAL);
842		}
843	}
844
845	/*
846	 * Find the device that the user is talking about
847	 */
848	switch (cmd) {
849	case MTIOCGET:
850	{
851		struct mtget *g = (struct mtget *)arg;
852
853		/*
854		 * If this isn't the control mode device, actually go out
855		 * and ask the drive again what it's set to.
856		 */
857		if (!SA_IS_CTRL(dev)) {
858			u_int8_t write_protect;
859			int comp_enabled, comp_supported;
860			error = sagetparams(periph, SA_PARAM_ALL,
861			    &softc->media_blksize, &softc->media_density,
862			    &softc->media_numblks, &softc->buffer_mode,
863			    &write_protect, &softc->speed, &comp_supported,
864			    &comp_enabled, &softc->comp_algorithm, NULL);
865			if (error)
866				break;
867			if (write_protect)
868				softc->flags |= SA_FLAG_TAPE_WP;
869			else
870				softc->flags &= ~SA_FLAG_TAPE_WP;
871			softc->flags &= ~(SA_FLAG_COMP_SUPP|
872			    SA_FLAG_COMP_ENABLED|SA_FLAG_COMP_UNSUPP);
873			if (comp_supported) {
874				if (softc->saved_comp_algorithm == 0)
875					softc->saved_comp_algorithm =
876					    softc->comp_algorithm;
877				softc->flags |= SA_FLAG_COMP_SUPP;
878				if (comp_enabled)
879					softc->flags |= SA_FLAG_COMP_ENABLED;
880			} else
881				softc->flags |= SA_FLAG_COMP_UNSUPP;
882		}
883		bzero(g, sizeof(struct mtget));
884		g->mt_type = MT_ISAR;
885		if (softc->flags & SA_FLAG_COMP_UNSUPP) {
886			g->mt_comp = MT_COMP_UNSUPP;
887			g->mt_comp0 = MT_COMP_UNSUPP;
888			g->mt_comp1 = MT_COMP_UNSUPP;
889			g->mt_comp2 = MT_COMP_UNSUPP;
890			g->mt_comp3 = MT_COMP_UNSUPP;
891		} else {
892			if ((softc->flags & SA_FLAG_COMP_ENABLED) == 0) {
893				g->mt_comp = MT_COMP_DISABLED;
894			} else {
895				g->mt_comp = softc->comp_algorithm;
896			}
897			g->mt_comp0 = softc->comp_algorithm;
898			g->mt_comp1 = softc->comp_algorithm;
899			g->mt_comp2 = softc->comp_algorithm;
900			g->mt_comp3 = softc->comp_algorithm;
901		}
902		g->mt_density = softc->media_density;
903		g->mt_density0 = softc->media_density;
904		g->mt_density1 = softc->media_density;
905		g->mt_density2 = softc->media_density;
906		g->mt_density3 = softc->media_density;
907		g->mt_blksiz = softc->media_blksize;
908		g->mt_blksiz0 = softc->media_blksize;
909		g->mt_blksiz1 = softc->media_blksize;
910		g->mt_blksiz2 = softc->media_blksize;
911		g->mt_blksiz3 = softc->media_blksize;
912		g->mt_fileno = softc->fileno;
913		g->mt_blkno = softc->blkno;
914		g->mt_dsreg = (short) softc->dsreg;
915		/*
916		 * Yes, we know that this is likely to overflow
917		 */
918		if (softc->last_resid_was_io) {
919			if ((g->mt_resid = (short) softc->last_io_resid) != 0) {
920				if (SA_IS_CTRL(dev) == 0 || didlockperiph) {
921					softc->last_io_resid = 0;
922				}
923			}
924		} else {
925			if ((g->mt_resid = (short)softc->last_ctl_resid) != 0) {
926				if (SA_IS_CTRL(dev) == 0 || didlockperiph) {
927					softc->last_ctl_resid = 0;
928				}
929			}
930		}
931		error = 0;
932		break;
933	}
934	case MTIOCERRSTAT:
935	{
936		struct scsi_tape_errors *sep =
937		    &((union mterrstat *)arg)->scsi_errstat;
938
939		CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
940		    ("saioctl: MTIOCERRSTAT\n"));
941
942		bzero(sep, sizeof(*sep));
943		sep->io_resid = softc->last_io_resid;
944		bcopy((caddr_t) &softc->last_io_sense, sep->io_sense,
945		    sizeof (sep->io_sense));
946		bcopy((caddr_t) &softc->last_io_cdb, sep->io_cdb,
947		    sizeof (sep->io_cdb));
948		sep->ctl_resid = softc->last_ctl_resid;
949		bcopy((caddr_t) &softc->last_ctl_sense, sep->ctl_sense,
950		    sizeof (sep->ctl_sense));
951		bcopy((caddr_t) &softc->last_ctl_cdb, sep->ctl_cdb,
952		    sizeof (sep->ctl_cdb));
953
954		if (SA_IS_CTRL(dev) == 0 || didlockperiph)
955			bzero((caddr_t) &softc->errinfo,
956			    sizeof (softc->errinfo));
957		error = 0;
958		break;
959	}
960	case MTIOCTOP:
961	{
962		struct mtop *mt;
963		int    count;
964
965		mt = (struct mtop *)arg;
966
967		CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
968			 ("saioctl: op=0x%x count=0x%x\n",
969			  mt->mt_op, mt->mt_count));
970
971		count = mt->mt_count;
972		switch (mt->mt_op) {
973		case MTWEOF:	/* write an end-of-file marker */
974			/*
975			 * We don't need to clear the SA_FLAG_TAPE_WRITTEN
976			 * flag because by keeping track of filemarks
977			 * we have last written we know ehether or not
978			 * we need to write more when we close the device.
979			 */
980			error = sawritefilemarks(periph, count, FALSE);
981			break;
982		case MTWSS:	/* write a setmark */
983			error = sawritefilemarks(periph, count, TRUE);
984			break;
985		case MTBSR:	/* backward space record */
986		case MTFSR:	/* forward space record */
987		case MTBSF:	/* backward space file */
988		case MTFSF:	/* forward space file */
989		case MTBSS:	/* backward space setmark */
990		case MTFSS:	/* forward space setmark */
991		case MTEOD:	/* space to end of recorded medium */
992		{
993			int nmarks;
994
995			spaceop = SS_FILEMARKS;
996			nmarks = softc->filemarks;
997			error = sacheckeod(periph);
998			if (error) {
999				xpt_print_path(periph->path);
1000				printf("EOD check prior to spacing failed\n");
1001				softc->flags |= SA_FLAG_EIO_PENDING;
1002				break;
1003			}
1004			nmarks -= softc->filemarks;
1005			switch(mt->mt_op) {
1006			case MTBSR:
1007				count = -count;
1008				/* FALLTHROUGH */
1009			case MTFSR:
1010				spaceop = SS_BLOCKS;
1011				break;
1012			case MTBSF:
1013				count = -count;
1014				/* FALLTHROUGH */
1015			case MTFSF:
1016				break;
1017			case MTBSS:
1018				count = -count;
1019				/* FALLTHROUGH */
1020			case MTFSS:
1021				spaceop = SS_SETMARKS;
1022				break;
1023			case MTEOD:
1024				spaceop = SS_EOD;
1025				count = 0;
1026				nmarks = 0;
1027				break;
1028			default:
1029				error = EINVAL;
1030				break;
1031			}
1032			if (error)
1033				break;
1034
1035			nmarks = softc->filemarks;
1036			/*
1037			 * XXX: Why are we checking again?
1038			 */
1039			error = sacheckeod(periph);
1040			if (error)
1041				break;
1042			nmarks -= softc->filemarks;
1043			error = saspace(periph, count - nmarks, spaceop);
1044			/*
1045			 * At this point, clear that we've written the tape
1046			 * and that we've written any filemarks. We really
1047			 * don't know what the applications wishes to do next-
1048			 * the sacheckeod's will make sure we terminated the
1049			 * tape correctly if we'd been writing, but the next
1050			 * action the user application takes will set again
1051			 * whether we need to write filemarks.
1052			 */
1053			softc->flags &=
1054			    ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
1055			softc->filemarks = 0;
1056			break;
1057		}
1058		case MTREW:	/* rewind */
1059			(void) sacheckeod(periph);
1060			error = sarewind(periph);
1061			/* see above */
1062			softc->flags &=
1063			    ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
1064			softc->flags &= ~SA_FLAG_ERR_PENDING;
1065			softc->filemarks = 0;
1066			break;
1067		case MTERASE:	/* erase */
1068			error = saerase(periph, count);
1069			softc->flags &=
1070			    ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
1071			softc->flags &= ~SA_FLAG_ERR_PENDING;
1072			break;
1073		case MTRETENS:	/* re-tension tape */
1074			error = saretension(periph);
1075			softc->flags &=
1076			    ~(SA_FLAG_TAPE_WRITTEN|SA_FLAG_TAPE_FROZEN);
1077			softc->flags &= ~SA_FLAG_ERR_PENDING;
1078			break;
1079		case MTOFFL:	/* rewind and put the drive offline */
1080
1081			(void) sacheckeod(periph);
1082			/* see above */
1083			softc->flags &= ~SA_FLAG_TAPE_WRITTEN;
1084			softc->filemarks = 0;
1085
1086			error = sarewind(periph);
1087			/* clear the frozen flag anyway */
1088			softc->flags &= ~SA_FLAG_TAPE_FROZEN;
1089
1090			/*
1091			 * Be sure to allow media removal before ejecting.
1092			 */
1093
1094			saprevent(periph, PR_ALLOW);
1095			if (error == 0) {
1096				error = saloadunload(periph, FALSE);
1097				if (error == 0) {
1098					softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
1099				}
1100			}
1101			break;
1102
1103		case MTNOP:	/* no operation, sets status only */
1104		case MTCACHE:	/* enable controller cache */
1105		case MTNOCACHE:	/* disable controller cache */
1106			error = 0;
1107			break;
1108
1109		case MTSETBSIZ:	/* Set block size for device */
1110
1111			error = sasetparams(periph, SA_PARAM_BLOCKSIZE, count,
1112					    0, 0, 0);
1113			if (error == 0) {
1114				softc->last_media_blksize =
1115				    softc->media_blksize;
1116				softc->media_blksize = count;
1117				if (count) {
1118					softc->flags |= SA_FLAG_FIXED;
1119					if (powerof2(count)) {
1120						softc->blk_shift =
1121						    ffs(count) - 1;
1122						softc->blk_mask = count - 1;
1123					} else {
1124						softc->blk_mask = ~0;
1125						softc->blk_shift = 0;
1126					}
1127					/*
1128					 * Make the user's desire 'persistent'.
1129					 */
1130					softc->quirks &= ~SA_QUIRK_VARIABLE;
1131					softc->quirks |= SA_QUIRK_FIXED;
1132				} else {
1133					softc->flags &= ~SA_FLAG_FIXED;
1134					if (softc->max_blk == 0) {
1135						softc->max_blk = ~0;
1136					}
1137					softc->blk_shift = 0;
1138					if (softc->blk_gran != 0) {
1139						softc->blk_mask =
1140						    softc->blk_gran - 1;
1141					} else {
1142						softc->blk_mask = 0;
1143					}
1144					/*
1145					 * Make the user's desire 'persistent'.
1146					 */
1147					softc->quirks |= SA_QUIRK_VARIABLE;
1148					softc->quirks &= ~SA_QUIRK_FIXED;
1149				}
1150			}
1151			break;
1152		case MTSETDNSTY:	/* Set density for device and mode */
1153			if (count > UCHAR_MAX) {
1154				error = EINVAL;
1155				break;
1156			} else {
1157				error = sasetparams(periph, SA_PARAM_DENSITY,
1158						    0, count, 0, 0);
1159			}
1160			break;
1161		case MTCOMP:	/* enable compression */
1162			/*
1163			 * Some devices don't support compression, and
1164			 * don't like it if you ask them for the
1165			 * compression page.
1166			 */
1167			if ((softc->quirks & SA_QUIRK_NOCOMP) ||
1168			    (softc->flags & SA_FLAG_COMP_UNSUPP)) {
1169				error = ENODEV;
1170				break;
1171			}
1172			error = sasetparams(periph, SA_PARAM_COMPRESSION,
1173			    0, 0, count, SF_NO_PRINT);
1174			break;
1175		default:
1176			error = EINVAL;
1177		}
1178		break;
1179	}
1180	case MTIOCIEOT:
1181	case MTIOCEEOT:
1182		error = 0;
1183		break;
1184	case MTIOCRDSPOS:
1185		error = sardpos(periph, 0, (u_int32_t *) arg);
1186		break;
1187	case MTIOCRDHPOS:
1188		error = sardpos(periph, 1, (u_int32_t *) arg);
1189		break;
1190	case MTIOCSLOCATE:
1191		error = sasetpos(periph, 0, (u_int32_t *) arg);
1192		break;
1193	case MTIOCHLOCATE:
1194		error = sasetpos(periph, 1, (u_int32_t *) arg);
1195		break;
1196	case MTIOCGETEOTMODEL:
1197		error = 0;
1198		if (softc->quirks & SA_QUIRK_1FM)
1199			mode = 1;
1200		else
1201			mode = 2;
1202		*((u_int32_t *) arg) = mode;
1203		break;
1204	case MTIOCSETEOTMODEL:
1205		error = 0;
1206		switch (*((u_int32_t *) arg)) {
1207		case 1:
1208			softc->quirks &= ~SA_QUIRK_2FM;
1209			softc->quirks |= SA_QUIRK_1FM;
1210			break;
1211		case 2:
1212			softc->quirks &= ~SA_QUIRK_1FM;
1213			softc->quirks |= SA_QUIRK_2FM;
1214			break;
1215		default:
1216			error = EINVAL;
1217			break;
1218		}
1219		break;
1220	default:
1221		error = cam_periph_ioctl(periph, cmd, arg, saerror);
1222		break;
1223	}
1224
1225	/*
1226	 * Check to see if we cleared a frozen state
1227	 */
1228	if (error == 0 && (softc->flags & SA_FLAG_TAPE_FROZEN)) {
1229		switch(cmd) {
1230		case MTIOCRDSPOS:
1231		case MTIOCRDHPOS:
1232		case MTIOCSLOCATE:
1233		case MTIOCHLOCATE:
1234			softc->fileno = (daddr_t) -1;
1235			softc->blkno = (daddr_t) -1;
1236			softc->flags &= ~SA_FLAG_TAPE_FROZEN;
1237			xpt_print_path(periph->path);
1238			printf("tape state now unfrozen.\n");
1239			break;
1240		default:
1241			break;
1242		}
1243	}
1244	if (didlockperiph) {
1245		cam_periph_unlock(periph);
1246	}
1247	return (error);
1248}
1249
1250static void
1251sainit(void)
1252{
1253	cam_status status;
1254	struct cam_path *path;
1255
1256	/*
1257	 * Create our extend array for storing the devices we attach to.
1258	 */
1259	saperiphs = cam_extend_new();
1260	if (saperiphs == NULL) {
1261		printf("sa: Failed to alloc extend array!\n");
1262		return;
1263	}
1264
1265	/*
1266	 * Install a global async callback.
1267	 */
1268	status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID,
1269				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
1270
1271	if (status == CAM_REQ_CMP) {
1272		/* Register the async callbacks of interrest */
1273		struct ccb_setasync csa; /*
1274					  * This is an immediate CCB,
1275					  * so using the stack is OK
1276					  */
1277		xpt_setup_ccb(&csa.ccb_h, path, 5);
1278		csa.ccb_h.func_code = XPT_SASYNC_CB;
1279		csa.event_enable = AC_FOUND_DEVICE;
1280		csa.callback = saasync;
1281		csa.callback_arg = NULL;
1282		xpt_action((union ccb *)&csa);
1283		status = csa.ccb_h.status;
1284		xpt_free_path(path);
1285	}
1286
1287	if (status != CAM_REQ_CMP) {
1288		printf("sa: Failed to attach master async callback "
1289		       "due to status 0x%x!\n", status);
1290	}
1291}
1292
1293static void
1294saoninvalidate(struct cam_periph *periph)
1295{
1296	struct sa_softc *softc;
1297	struct bio *q_bp;
1298	struct ccb_setasync csa;
1299	int s;
1300
1301	softc = (struct sa_softc *)periph->softc;
1302
1303	/*
1304	 * De-register any async callbacks.
1305	 */
1306	xpt_setup_ccb(&csa.ccb_h, periph->path,
1307		      /* priority */ 5);
1308	csa.ccb_h.func_code = XPT_SASYNC_CB;
1309	csa.event_enable = 0;
1310	csa.callback = saasync;
1311	csa.callback_arg = periph;
1312	xpt_action((union ccb *)&csa);
1313
1314	softc->flags |= SA_FLAG_INVALID;
1315
1316	/*
1317	 * Although the oninvalidate() routines are always called at
1318	 * splsoftcam, we need to be at splbio() here to keep the buffer
1319	 * queue from being modified while we traverse it.
1320	 */
1321	s = splbio();
1322
1323	/*
1324	 * Return all queued I/O with ENXIO.
1325	 * XXX Handle any transactions queued to the card
1326	 *     with XPT_ABORT_CCB.
1327	 */
1328	while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){
1329		bioq_remove(&softc->bio_queue, q_bp);
1330		q_bp->bio_resid = q_bp->bio_bcount;
1331		biofinish(q_bp, NULL, ENXIO);
1332	}
1333	softc->queue_count = 0;
1334	splx(s);
1335
1336	xpt_print_path(periph->path);
1337	printf("lost device\n");
1338
1339}
1340
1341static void
1342sacleanup(struct cam_periph *periph)
1343{
1344	struct sa_softc *softc;
1345	int i;
1346
1347	softc = (struct sa_softc *)periph->softc;
1348
1349	devstat_remove_entry(&softc->device_stats);
1350
1351	destroy_dev(softc->devs.ctl_dev);
1352
1353	for (i = 0; i < SA_NUM_MODES; i++) {
1354		destroy_dev(softc->devs.mode_devs[i].r_dev);
1355		destroy_dev(softc->devs.mode_devs[i].nr_dev);
1356		destroy_dev(softc->devs.mode_devs[i].er_dev);
1357	}
1358
1359	cam_extend_release(saperiphs, periph->unit_number);
1360	xpt_print_path(periph->path);
1361	printf("removing device entry\n");
1362	free(softc, M_DEVBUF);
1363}
1364
1365static void
1366saasync(void *callback_arg, u_int32_t code,
1367	struct cam_path *path, void *arg)
1368{
1369	struct cam_periph *periph;
1370
1371	periph = (struct cam_periph *)callback_arg;
1372	switch (code) {
1373	case AC_FOUND_DEVICE:
1374	{
1375		struct ccb_getdev *cgd;
1376		cam_status status;
1377
1378		cgd = (struct ccb_getdev *)arg;
1379		if (cgd == NULL)
1380			break;
1381
1382		if (SID_TYPE(&cgd->inq_data) != T_SEQUENTIAL)
1383			break;
1384
1385		/*
1386		 * Allocate a peripheral instance for
1387		 * this device and start the probe
1388		 * process.
1389		 */
1390		status = cam_periph_alloc(saregister, saoninvalidate,
1391					  sacleanup, sastart,
1392					  "sa", CAM_PERIPH_BIO, cgd->ccb_h.path,
1393					  saasync, AC_FOUND_DEVICE, cgd);
1394
1395		if (status != CAM_REQ_CMP
1396		 && status != CAM_REQ_INPROG)
1397			printf("saasync: Unable to probe new device "
1398				"due to status 0x%x\n", status);
1399		break;
1400	}
1401	default:
1402		cam_periph_async(periph, code, path, arg);
1403		break;
1404	}
1405}
1406
1407static cam_status
1408saregister(struct cam_periph *periph, void *arg)
1409{
1410	struct sa_softc *softc;
1411	struct ccb_setasync csa;
1412	struct ccb_getdev *cgd;
1413	caddr_t match;
1414	int i;
1415
1416	cgd = (struct ccb_getdev *)arg;
1417	if (periph == NULL) {
1418		printf("saregister: periph was NULL!!\n");
1419		return (CAM_REQ_CMP_ERR);
1420	}
1421
1422	if (cgd == NULL) {
1423		printf("saregister: no getdev CCB, can't register device\n");
1424		return (CAM_REQ_CMP_ERR);
1425	}
1426
1427	softc = (struct sa_softc *)
1428	    malloc(sizeof (*softc), M_DEVBUF, M_NOWAIT | M_ZERO);
1429	if (softc == NULL) {
1430		printf("saregister: Unable to probe new device. "
1431		       "Unable to allocate softc\n");
1432		return (CAM_REQ_CMP_ERR);
1433	}
1434	softc->scsi_rev = SID_ANSI_REV(&cgd->inq_data);
1435	softc->state = SA_STATE_NORMAL;
1436	softc->fileno = (daddr_t) -1;
1437	softc->blkno = (daddr_t) -1;
1438
1439	bioq_init(&softc->bio_queue);
1440	periph->softc = softc;
1441	cam_extend_set(saperiphs, periph->unit_number, periph);
1442
1443	/*
1444	 * See if this device has any quirks.
1445	 */
1446	match = cam_quirkmatch((caddr_t)&cgd->inq_data,
1447			       (caddr_t)sa_quirk_table,
1448			       sizeof(sa_quirk_table)/sizeof(*sa_quirk_table),
1449			       sizeof(*sa_quirk_table), scsi_inquiry_match);
1450
1451	if (match != NULL) {
1452		softc->quirks = ((struct sa_quirk_entry *)match)->quirks;
1453		softc->last_media_blksize =
1454		    ((struct sa_quirk_entry *)match)->prefblk;
1455#ifdef	CAMDEBUG
1456		xpt_print_path(periph->path);
1457		printf("found quirk entry %d\n", (int)
1458		    (((struct sa_quirk_entry *) match) - sa_quirk_table));
1459#endif
1460	} else
1461		softc->quirks = SA_QUIRK_NONE;
1462
1463	/*
1464 	 * The SA driver supports a blocksize, but we don't know the
1465	 * blocksize until we media is inserted.  So, set a flag to
1466	 * indicate that the blocksize is unavailable right now.
1467	 */
1468	devstat_add_entry(&softc->device_stats, "sa", periph->unit_number, 0,
1469	    DEVSTAT_BS_UNAVAILABLE, SID_TYPE(&cgd->inq_data) |
1470	    DEVSTAT_TYPE_IF_SCSI, DEVSTAT_PRIORITY_TAPE);
1471
1472	softc->devs.ctl_dev = make_dev(&sa_cdevsw, SAMINOR(SA_CTLDEV,
1473	    periph->unit_number, 0, SA_ATYPE_R), UID_ROOT, GID_OPERATOR,
1474	    0660, "%s%d.ctl", periph->periph_name, periph->unit_number);
1475
1476	for (i = 0; i < SA_NUM_MODES; i++) {
1477
1478		softc->devs.mode_devs[i].r_dev = make_dev(&sa_cdevsw,
1479		    SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_R),
1480		    UID_ROOT, GID_OPERATOR, 0660, "%s%d.%d",
1481		    periph->periph_name, periph->unit_number, i);
1482
1483		softc->devs.mode_devs[i].nr_dev = make_dev(&sa_cdevsw,
1484		    SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_NR),
1485		    UID_ROOT, GID_OPERATOR, 0660, "n%s%d.%d",
1486		    periph->periph_name, periph->unit_number, i);
1487
1488
1489		softc->devs.mode_devs[i].er_dev = make_dev(&sa_cdevsw,
1490		    SAMINOR(SA_NOT_CTLDEV, periph->unit_number, i, SA_ATYPE_ER),
1491		    UID_ROOT, GID_OPERATOR, 0660, "e%s%d.%d",
1492		    periph->periph_name, periph->unit_number, i);
1493
1494		/*
1495		 * Make the (well known) aliases for the first mode.
1496		 */
1497		if (i == 0) {
1498			make_dev_alias(softc->devs.mode_devs[i].r_dev,
1499			   "%s%d", periph->periph_name, periph->unit_number);
1500			make_dev_alias(softc->devs.mode_devs[i].nr_dev,
1501			    "n%s%d", periph->periph_name, periph->unit_number);
1502			make_dev_alias(softc->devs.mode_devs[i].er_dev,
1503			    "e%s%d", periph->periph_name, periph->unit_number);
1504		}
1505	}
1506
1507	/*
1508	 * Add an async callback so that we get
1509	 * notified if this device goes away.
1510	 */
1511	xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5);
1512	csa.ccb_h.func_code = XPT_SASYNC_CB;
1513	csa.event_enable = AC_LOST_DEVICE;
1514	csa.callback = saasync;
1515	csa.callback_arg = periph;
1516	xpt_action((union ccb *)&csa);
1517
1518	xpt_announce_periph(periph, NULL);
1519
1520	return (CAM_REQ_CMP);
1521}
1522
1523static void
1524sastart(struct cam_periph *periph, union ccb *start_ccb)
1525{
1526	struct sa_softc *softc;
1527
1528	softc = (struct sa_softc *)periph->softc;
1529
1530	CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("sastart"));
1531
1532
1533	switch (softc->state) {
1534	case SA_STATE_NORMAL:
1535	{
1536		/* Pull a buffer from the queue and get going on it */
1537		struct bio *bp;
1538		int s;
1539
1540		/*
1541		 * See if there is a buf with work for us to do..
1542		 */
1543		s = splbio();
1544		bp = bioq_first(&softc->bio_queue);
1545		if (periph->immediate_priority <= periph->pinfo.priority) {
1546			CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
1547					("queuing for immediate ccb\n"));
1548			Set_CCB_Type(start_ccb, SA_CCB_WAITING);
1549			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
1550					  periph_links.sle);
1551			periph->immediate_priority = CAM_PRIORITY_NONE;
1552			splx(s);
1553			wakeup(&periph->ccb_list);
1554		} else if (bp == NULL) {
1555			splx(s);
1556			xpt_release_ccb(start_ccb);
1557		} else if ((softc->flags & SA_FLAG_ERR_PENDING) != 0) {
1558			struct bio *done_bp;
1559again:
1560			softc->queue_count--;
1561			bioq_remove(&softc->bio_queue, bp);
1562			bp->bio_resid = bp->bio_bcount;
1563			done_bp = bp;
1564			if ((softc->flags & SA_FLAG_EOM_PENDING) != 0) {
1565				/*
1566				 * We now just clear errors in this case
1567				 * and let the residual be the notifier.
1568				 */
1569				bp->bio_error = 0;
1570			} else if ((softc->flags & SA_FLAG_EOF_PENDING) != 0) {
1571				/*
1572				 * This can only happen if we're reading
1573				 * in fixed length mode. In this case,
1574				 * we dump the rest of the list the
1575				 * same way.
1576				 */
1577				bp->bio_error = 0;
1578				if (bioq_first(&softc->bio_queue) != NULL) {
1579					biodone(done_bp);
1580					goto again;
1581				}
1582			} else if ((softc->flags & SA_FLAG_EIO_PENDING) != 0) {
1583				bp->bio_error = EIO;
1584				bp->bio_flags |= BIO_ERROR;
1585			}
1586			bp = bioq_first(&softc->bio_queue);
1587			/*
1588			 * Only if we have no other buffers queued up
1589			 * do we clear the pending error flag.
1590			 */
1591			if (bp == NULL)
1592				softc->flags &= ~SA_FLAG_ERR_PENDING;
1593			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
1594			    ("sastart- ERR_PENDING now 0x%x, bp is %sNULL, "
1595			    "%d more buffers queued up\n",
1596			    (softc->flags & SA_FLAG_ERR_PENDING),
1597			    (bp != NULL)? "not " : " ", softc->queue_count));
1598			splx(s);
1599			xpt_release_ccb(start_ccb);
1600			biodone(done_bp);
1601		} else {
1602			u_int32_t length;
1603
1604			bioq_remove(&softc->bio_queue, bp);
1605			softc->queue_count--;
1606
1607			if ((softc->flags & SA_FLAG_FIXED) != 0) {
1608				if (softc->blk_shift != 0) {
1609					length =
1610					    bp->bio_bcount >> softc->blk_shift;
1611				} else if (softc->media_blksize != 0) {
1612					length = bp->bio_bcount /
1613					    softc->media_blksize;
1614				} else {
1615					bp->bio_error = EIO;
1616					xpt_print_path(periph->path);
1617					printf("zero blocksize for "
1618					    "FIXED length writes?\n");
1619					splx(s);
1620					biodone(bp);
1621					break;
1622				}
1623				CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
1624				    ("Fixed Record Count is %d\n", length));
1625			} else {
1626				length = bp->bio_bcount;
1627				CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
1628				    ("Variable Record Count is %d\n", length));
1629			}
1630			devstat_start_transaction(&softc->device_stats);
1631			/*
1632			 * Some people have theorized that we should
1633			 * suppress illegal length indication if we are
1634			 * running in variable block mode so that we don't
1635			 * have to request sense every time our requested
1636			 * block size is larger than the written block.
1637			 * The residual information from the ccb allows
1638			 * us to identify this situation anyway.  The only
1639			 * problem with this is that we will not get
1640			 * information about blocks that are larger than
1641			 * our read buffer unless we set the block size
1642			 * in the mode page to something other than 0.
1643			 *
1644			 * I believe that this is a non-issue. If user apps
1645			 * don't adjust their read size to match our record
1646			 * size, that's just life. Anyway, the typical usage
1647			 * would be to issue, e.g., 64KB reads and occasionally
1648			 * have to do deal with 512 byte or 1KB intermediate
1649			 * records.
1650			 */
1651			softc->dsreg = (bp->bio_cmd == BIO_READ)?
1652			    MTIO_DSREG_RD : MTIO_DSREG_WR;
1653			scsi_sa_read_write(&start_ccb->csio, 0, sadone,
1654			    MSG_SIMPLE_Q_TAG, (bp->bio_cmd == BIO_READ),
1655			    FALSE, (softc->flags & SA_FLAG_FIXED) != 0,
1656			    length, bp->bio_data, bp->bio_bcount, SSD_FULL_SIZE,
1657			    IO_TIMEOUT);
1658			start_ccb->ccb_h.ccb_pflags &= ~SA_POSITION_UPDATED;
1659			Set_CCB_Type(start_ccb, SA_CCB_BUFFER_IO);
1660			start_ccb->ccb_h.ccb_bp = bp;
1661			bp = bioq_first(&softc->bio_queue);
1662			splx(s);
1663			xpt_action(start_ccb);
1664		}
1665
1666		if (bp != NULL) {
1667			/* Have more work to do, so ensure we stay scheduled */
1668			xpt_schedule(periph, 1);
1669		}
1670		break;
1671	}
1672	case SA_STATE_ABNORMAL:
1673	default:
1674		panic("state 0x%x in sastart", softc->state);
1675		break;
1676	}
1677}
1678
1679
1680static void
1681sadone(struct cam_periph *periph, union ccb *done_ccb)
1682{
1683	struct sa_softc *softc;
1684	struct ccb_scsiio *csio;
1685
1686	softc = (struct sa_softc *)periph->softc;
1687	csio = &done_ccb->csio;
1688	switch (CCB_Type(csio)) {
1689	case SA_CCB_BUFFER_IO:
1690	{
1691		struct bio *bp;
1692		int error;
1693
1694		softc->dsreg = MTIO_DSREG_REST;
1695		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
1696		error = 0;
1697		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1698			if ((error = saerror(done_ccb, 0, 0)) == ERESTART) {
1699				/*
1700				 * A retry was scheduled, so just return.
1701				 */
1702				return;
1703			}
1704		}
1705
1706		if (error == EIO) {
1707			int s;
1708			struct bio *q_bp;
1709
1710			/*
1711			 * Catastrophic error. Mark the tape as frozen
1712			 * (we no longer know tape position).
1713			 *
1714			 * Return all queued I/O with EIO, and unfreeze
1715			 * our queue so that future transactions that
1716			 * attempt to fix this problem can get to the
1717			 * device.
1718			 *
1719			 */
1720
1721			s = splbio();
1722			softc->flags |= SA_FLAG_TAPE_FROZEN;
1723			while ((q_bp = bioq_first(&softc->bio_queue)) != NULL) {
1724				bioq_remove(&softc->bio_queue, q_bp);
1725				q_bp->bio_resid = q_bp->bio_bcount;
1726				biofinish(q_bp, NULL, EIO);
1727			}
1728			splx(s);
1729		}
1730		if (error != 0) {
1731			bp->bio_resid = bp->bio_bcount;
1732			bp->bio_error = error;
1733			bp->bio_flags |= BIO_ERROR;
1734			/*
1735			 * In the error case, position is updated in saerror.
1736			 */
1737		} else {
1738			bp->bio_resid = csio->resid;
1739			bp->bio_error = 0;
1740			if (csio->resid != 0) {
1741				bp->bio_flags |= BIO_ERROR;
1742			}
1743			if (bp->bio_cmd == BIO_WRITE) {
1744				softc->flags |= SA_FLAG_TAPE_WRITTEN;
1745				softc->filemarks = 0;
1746			}
1747			if (!(csio->ccb_h.ccb_pflags & SA_POSITION_UPDATED) &&
1748			    (softc->blkno != (daddr_t) -1)) {
1749				if ((softc->flags & SA_FLAG_FIXED) != 0) {
1750					u_int32_t l;
1751					if (softc->blk_shift != 0) {
1752						l = bp->bio_bcount >>
1753							softc->blk_shift;
1754					} else {
1755						l = bp->bio_bcount /
1756							softc->media_blksize;
1757					}
1758					softc->blkno += (daddr_t) l;
1759				} else {
1760					softc->blkno++;
1761				}
1762			}
1763		}
1764		/*
1765		 * If we had an error (immediate or pending),
1766		 * release the device queue now.
1767		 */
1768		if (error || (softc->flags & SA_FLAG_ERR_PENDING))
1769			cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0);
1770#ifdef	CAMDEBUG
1771		if (error || bp->bio_resid) {
1772			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
1773			    	  ("error %d resid %ld count %ld\n", error,
1774				  bp->bio_resid, bp->bio_bcount));
1775		}
1776#endif
1777		biofinish(bp, &softc->device_stats, 0);
1778		break;
1779	}
1780	case SA_CCB_WAITING:
1781	{
1782		/* Caller will release the CCB */
1783		wakeup(&done_ccb->ccb_h.cbfcnp);
1784		return;
1785	}
1786	}
1787	xpt_release_ccb(done_ccb);
1788}
1789
1790/*
1791 * Mount the tape (make sure it's ready for I/O).
1792 */
1793static int
1794samount(struct cam_periph *periph, int oflags, dev_t dev)
1795{
1796	struct	sa_softc *softc;
1797	union	ccb *ccb;
1798	int	error;
1799
1800	/*
1801	 * oflags can be checked for 'kind' of open (read-only check) - later
1802	 * dev can be checked for a control-mode or compression open - later
1803	 */
1804	UNUSED_PARAMETER(oflags);
1805	UNUSED_PARAMETER(dev);
1806
1807
1808	softc = (struct sa_softc *)periph->softc;
1809
1810	/*
1811	 * This should determine if something has happend since the last
1812	 * open/mount that would invalidate the mount. We do *not* want
1813	 * to retry this command- we just want the status. But we only
1814	 * do this if we're mounted already- if we're not mounted,
1815	 * we don't care about the unit read state and can instead use
1816	 * this opportunity to attempt to reserve the tape unit.
1817	 */
1818
1819	if (softc->flags & SA_FLAG_TAPE_MOUNTED) {
1820		ccb = cam_periph_getccb(periph, 1);
1821		scsi_test_unit_ready(&ccb->csio, 0, sadone,
1822		    MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT);
1823		error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
1824		    &softc->device_stats);
1825		QFRLS(ccb);
1826		if (error == ENXIO) {
1827			softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
1828			scsi_test_unit_ready(&ccb->csio, 0, sadone,
1829			    MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT);
1830			error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
1831			    &softc->device_stats);
1832			QFRLS(ccb);
1833		} else if (error) {
1834			/*
1835			 * We don't need to freeze the tape because we
1836			 * will now attempt to rewind/load it.
1837			 */
1838			softc->flags &= ~SA_FLAG_TAPE_MOUNTED;
1839			if (CAM_DEBUGGED(ccb->ccb_h.path, CAM_DEBUG_INFO)) {
1840				xpt_print_path(ccb->ccb_h.path);
1841				printf("error %d on TUR in samount\n", error);
1842			}
1843		}
1844	} else {
1845		error = sareservereleaseunit(periph, TRUE);
1846		if (error) {
1847			return (error);
1848		}
1849		ccb = cam_periph_getccb(periph, 1);
1850		scsi_test_unit_ready(&ccb->csio, 0, sadone,
1851		    MSG_SIMPLE_Q_TAG, SSD_FULL_SIZE, IO_TIMEOUT);
1852		error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
1853		    &softc->device_stats);
1854		QFRLS(ccb);
1855	}
1856
1857	if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) {
1858		struct scsi_read_block_limits_data *rblim = NULL;
1859		int comp_enabled, comp_supported;
1860		u_int8_t write_protect, guessing = 0;
1861
1862		/*
1863		 * Clear out old state.
1864		 */
1865		softc->flags &= ~(SA_FLAG_TAPE_WP|SA_FLAG_TAPE_WRITTEN|
1866				  SA_FLAG_ERR_PENDING|SA_FLAG_COMP_ENABLED|
1867				  SA_FLAG_COMP_SUPP|SA_FLAG_COMP_UNSUPP);
1868		softc->filemarks = 0;
1869
1870		/*
1871		 * *Very* first off, make sure we're loaded to BOT.
1872		 */
1873		scsi_load_unload(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE,
1874		    FALSE, FALSE, 1, SSD_FULL_SIZE, REWIND_TIMEOUT);
1875		error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
1876		    &softc->device_stats);
1877		QFRLS(ccb);
1878
1879		/*
1880		 * In case this doesn't work, do a REWIND instead
1881		 */
1882		if (error) {
1883			scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG,
1884			    FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT);
1885			error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
1886				&softc->device_stats);
1887			QFRLS(ccb);
1888		}
1889		if (error) {
1890			xpt_release_ccb(ccb);
1891			goto exit;
1892		}
1893
1894		/*
1895		 * Do a dummy test read to force access to the
1896		 * media so that the drive will really know what's
1897		 * there. We actually don't really care what the
1898		 * blocksize on tape is and don't expect to really
1899		 * read a full record.
1900		 */
1901		rblim = (struct  scsi_read_block_limits_data *)
1902		    malloc(8192, M_TEMP, M_WAITOK);
1903		if (rblim == NULL) {
1904			xpt_print_path(ccb->ccb_h.path);
1905			printf("no memory for test read\n");
1906			xpt_release_ccb(ccb);
1907			error = ENOMEM;
1908			goto exit;
1909		}
1910
1911		if ((softc->quirks & SA_QUIRK_NODREAD) == 0) {
1912			scsi_sa_read_write(&ccb->csio, 0, sadone,
1913			    MSG_SIMPLE_Q_TAG, 1, FALSE, 0, 8192,
1914			    (void *) rblim, 8192, SSD_FULL_SIZE,
1915			    IO_TIMEOUT);
1916			(void) cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
1917			    &softc->device_stats);
1918			QFRLS(ccb);
1919			scsi_rewind(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
1920			    FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT);
1921			error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO,
1922			    SF_NO_PRINT | SF_RETRY_UA,
1923			    &softc->device_stats);
1924			QFRLS(ccb);
1925			if (error) {
1926				xpt_print_path(ccb->ccb_h.path);
1927				printf("unable to rewind after test read\n");
1928				xpt_release_ccb(ccb);
1929				goto exit;
1930			}
1931		}
1932
1933		/*
1934		 * Next off, determine block limits.
1935		 */
1936		scsi_read_block_limits(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG,
1937		    rblim, SSD_FULL_SIZE, SCSIOP_TIMEOUT);
1938
1939		error = cam_periph_runccb(ccb, saerror, CAM_RETRY_SELTO,
1940		    SF_NO_PRINT | SF_RETRY_UA, &softc->device_stats);
1941
1942		QFRLS(ccb);
1943		xpt_release_ccb(ccb);
1944
1945		if (error != 0) {
1946			/*
1947			 * If it's less than SCSI-2, READ BLOCK LIMITS is not
1948			 * a MANDATORY command. Anyway- it doesn't matter-
1949			 * we can proceed anyway.
1950			 */
1951			softc->blk_gran = 0;
1952			softc->max_blk = ~0;
1953			softc->min_blk = 0;
1954		} else {
1955			if (softc->scsi_rev >= SCSI_REV_SPC) {
1956				softc->blk_gran = RBL_GRAN(rblim);
1957			} else {
1958				softc->blk_gran = 0;
1959			}
1960			/*
1961			 * We take max_blk == min_blk to mean a default to
1962			 * fixed mode- but note that whatever we get out of
1963			 * sagetparams below will actually determine whether
1964			 * we are actually *in* fixed mode.
1965			 */
1966			softc->max_blk = scsi_3btoul(rblim->maximum);
1967			softc->min_blk = scsi_2btoul(rblim->minimum);
1968
1969
1970		}
1971		/*
1972		 * Next, perform a mode sense to determine
1973		 * current density, blocksize, compression etc.
1974		 */
1975		error = sagetparams(periph, SA_PARAM_ALL,
1976				    &softc->media_blksize,
1977				    &softc->media_density,
1978				    &softc->media_numblks,
1979				    &softc->buffer_mode, &write_protect,
1980				    &softc->speed, &comp_supported,
1981				    &comp_enabled, &softc->comp_algorithm,
1982				    NULL);
1983
1984		if (error != 0) {
1985			/*
1986			 * We could work a little harder here. We could
1987			 * adjust our attempts to get information. It
1988			 * might be an ancient tape drive. If someone
1989			 * nudges us, we'll do that.
1990			 */
1991			goto exit;
1992		}
1993
1994		/*
1995		 * If no quirk has determined that this is a device that is
1996		 * preferred to be in fixed or variable mode, now is the time
1997		 * to find out.
1998	 	 */
1999		if ((softc->quirks & (SA_QUIRK_FIXED|SA_QUIRK_VARIABLE)) == 0) {
2000			guessing = 1;
2001			/*
2002			 * This could be expensive to find out. Luckily we
2003			 * only need to do this once. If we start out in
2004			 * 'default' mode, try and set ourselves to one
2005			 * of the densities that would determine a wad
2006			 * of other stuff. Go from highest to lowest.
2007			 */
2008			if (softc->media_density == SCSI_DEFAULT_DENSITY) {
2009				int i;
2010				static u_int8_t ctry[] = {
2011					SCSI_DENSITY_HALFINCH_PE,
2012					SCSI_DENSITY_HALFINCH_6250C,
2013					SCSI_DENSITY_HALFINCH_6250,
2014					SCSI_DENSITY_HALFINCH_1600,
2015					SCSI_DENSITY_HALFINCH_800,
2016					SCSI_DENSITY_QIC_4GB,
2017					SCSI_DENSITY_QIC_2GB,
2018					SCSI_DENSITY_QIC_525_320,
2019					SCSI_DENSITY_QIC_150,
2020					SCSI_DENSITY_QIC_120,
2021					SCSI_DENSITY_QIC_24,
2022					SCSI_DENSITY_QIC_11_9TRK,
2023					SCSI_DENSITY_QIC_11_4TRK,
2024					SCSI_DENSITY_QIC_1320,
2025					SCSI_DENSITY_QIC_3080,
2026					0
2027				};
2028				for (i = 0; ctry[i]; i++) {
2029					error = sasetparams(periph,
2030					    SA_PARAM_DENSITY, 0, ctry[i],
2031					    0, SF_NO_PRINT);
2032					if (error == 0) {
2033						softc->media_density = ctry[i];
2034						break;
2035					}
2036				}
2037			}
2038			switch (softc->media_density) {
2039			case SCSI_DENSITY_QIC_11_4TRK:
2040			case SCSI_DENSITY_QIC_11_9TRK:
2041			case SCSI_DENSITY_QIC_24:
2042			case SCSI_DENSITY_QIC_120:
2043			case SCSI_DENSITY_QIC_150:
2044			case SCSI_DENSITY_QIC_525_320:
2045			case SCSI_DENSITY_QIC_1320:
2046			case SCSI_DENSITY_QIC_3080:
2047				softc->quirks &= ~SA_QUIRK_2FM;
2048				softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM;
2049				softc->last_media_blksize = 512;
2050				break;
2051			case SCSI_DENSITY_QIC_4GB:
2052			case SCSI_DENSITY_QIC_2GB:
2053				softc->quirks &= ~SA_QUIRK_2FM;
2054				softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM;
2055				softc->last_media_blksize = 1024;
2056				break;
2057			default:
2058				softc->last_media_blksize =
2059				    softc->media_blksize;
2060				softc->quirks |= SA_QUIRK_VARIABLE;
2061				break;
2062			}
2063		}
2064
2065		/*
2066		 * If no quirk has determined that this is a device that needs
2067		 * to have 2 Filemarks at EOD, now is the time to find out.
2068		 */
2069
2070		if ((softc->quirks & SA_QUIRK_2FM) == 0) {
2071			switch (softc->media_density) {
2072			case SCSI_DENSITY_HALFINCH_800:
2073			case SCSI_DENSITY_HALFINCH_1600:
2074			case SCSI_DENSITY_HALFINCH_6250:
2075			case SCSI_DENSITY_HALFINCH_6250C:
2076			case SCSI_DENSITY_HALFINCH_PE:
2077				softc->quirks &= ~SA_QUIRK_1FM;
2078				softc->quirks |= SA_QUIRK_2FM;
2079				break;
2080			default:
2081				break;
2082			}
2083		}
2084
2085		/*
2086		 * Now validate that some info we got makes sense.
2087		 */
2088		if ((softc->max_blk < softc->media_blksize) ||
2089		    (softc->min_blk > softc->media_blksize &&
2090		    softc->media_blksize)) {
2091			xpt_print_path(ccb->ccb_h.path);
2092			printf("BLOCK LIMITS (%d..%d) could not match current "
2093			    "block settings (%d)- adjusting\n", softc->min_blk,
2094			    softc->max_blk, softc->media_blksize);
2095			softc->max_blk = softc->min_blk =
2096			    softc->media_blksize;
2097		}
2098
2099		/*
2100		 * Now put ourselves into the right frame of mind based
2101		 * upon quirks...
2102		 */
2103tryagain:
2104		/*
2105		 * If we want to be in FIXED mode and our current blocksize
2106		 * is not equal to our last blocksize (if nonzero), try and
2107		 * set ourselves to this last blocksize (as the 'preferred'
2108		 * block size).  The initial quirkmatch at registry sets the
2109		 * initial 'last' blocksize. If, for whatever reason, this
2110		 * 'last' blocksize is zero, set the blocksize to 512,
2111		 * or min_blk if that's larger.
2112		 */
2113		if ((softc->quirks & SA_QUIRK_FIXED) &&
2114		    (softc->quirks & SA_QUIRK_NO_MODESEL) == 0 &&
2115		    (softc->media_blksize != softc->last_media_blksize)) {
2116			softc->media_blksize = softc->last_media_blksize;
2117			if (softc->media_blksize == 0) {
2118				softc->media_blksize = 512;
2119				if (softc->media_blksize < softc->min_blk) {
2120					softc->media_blksize = softc->min_blk;
2121				}
2122			}
2123			error = sasetparams(periph, SA_PARAM_BLOCKSIZE,
2124			    softc->media_blksize, 0, 0, SF_NO_PRINT);
2125			if (error) {
2126				xpt_print_path(ccb->ccb_h.path);
2127				printf("unable to set fixed blocksize to %d\n",
2128				     softc->media_blksize);
2129				goto exit;
2130			}
2131		}
2132
2133		if ((softc->quirks & SA_QUIRK_VARIABLE) &&
2134		    (softc->media_blksize != 0)) {
2135			softc->last_media_blksize = softc->media_blksize;
2136			softc->media_blksize = 0;
2137			error = sasetparams(periph, SA_PARAM_BLOCKSIZE,
2138			    0, 0, 0, SF_NO_PRINT);
2139			if (error) {
2140				/*
2141				 * If this fails and we were guessing, just
2142				 * assume that we got it wrong and go try
2143				 * fixed block mode. Don't even check against
2144				 * density code at this point.
2145				 */
2146				if (guessing) {
2147					softc->quirks &= ~SA_QUIRK_VARIABLE;
2148					softc->quirks |= SA_QUIRK_FIXED;
2149					if (softc->last_media_blksize == 0)
2150						softc->last_media_blksize = 512;
2151					goto tryagain;
2152				}
2153				xpt_print_path(ccb->ccb_h.path);
2154				printf("unable to set variable blocksize\n");
2155				goto exit;
2156			}
2157		}
2158
2159		/*
2160		 * Now that we have the current block size,
2161		 * set up some parameters for sastart's usage.
2162		 */
2163		if (softc->media_blksize) {
2164			softc->flags |= SA_FLAG_FIXED;
2165			if (powerof2(softc->media_blksize)) {
2166				softc->blk_shift =
2167				    ffs(softc->media_blksize) - 1;
2168				softc->blk_mask = softc->media_blksize - 1;
2169			} else {
2170				softc->blk_mask = ~0;
2171				softc->blk_shift = 0;
2172			}
2173		} else {
2174			/*
2175			 * The SCSI-3 spec allows 0 to mean "unspecified".
2176			 * The SCSI-1 spec allows 0 to mean 'infinite'.
2177			 *
2178			 * Either works here.
2179			 */
2180			if (softc->max_blk == 0) {
2181				softc->max_blk = ~0;
2182			}
2183			softc->blk_shift = 0;
2184			if (softc->blk_gran != 0) {
2185				softc->blk_mask = softc->blk_gran - 1;
2186			} else {
2187				softc->blk_mask = 0;
2188			}
2189		}
2190
2191		if (write_protect)
2192			softc->flags |= SA_FLAG_TAPE_WP;
2193
2194		if (comp_supported) {
2195			if (softc->saved_comp_algorithm == 0)
2196				softc->saved_comp_algorithm =
2197				    softc->comp_algorithm;
2198			softc->flags |= SA_FLAG_COMP_SUPP;
2199			if (comp_enabled)
2200				softc->flags |= SA_FLAG_COMP_ENABLED;
2201		} else
2202			softc->flags |= SA_FLAG_COMP_UNSUPP;
2203
2204		if ((softc->buffer_mode == SMH_SA_BUF_MODE_NOBUF) &&
2205		    (softc->quirks & SA_QUIRK_NO_MODESEL) == 0) {
2206			error = sasetparams(periph, SA_PARAM_BUFF_MODE, 0,
2207			    0, 0, SF_NO_PRINT);
2208			if (error == 0)
2209				softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF;
2210			xpt_print_path(ccb->ccb_h.path);
2211			printf("unable to set buffered mode\n");
2212			error = 0;	/* not an error */
2213		}
2214
2215
2216		if (error == 0) {
2217			softc->flags |= SA_FLAG_TAPE_MOUNTED;
2218		}
2219exit:
2220		if (rblim != NULL)
2221			free(rblim, M_TEMP);
2222
2223		if (error != 0) {
2224			softc->dsreg = MTIO_DSREG_NIL;
2225		} else {
2226			softc->fileno = softc->blkno = 0;
2227			softc->dsreg = MTIO_DSREG_REST;
2228		}
2229#ifdef	SA_1FM_AT_EOD
2230		if ((softc->quirks & SA_QUIRK_2FM) == 0)
2231			softc->quirks |= SA_QUIRK_1FM;
2232#else
2233		if ((softc->quirks & SA_QUIRK_1FM) == 0)
2234			softc->quirks |= SA_QUIRK_2FM;
2235#endif
2236	} else
2237		xpt_release_ccb(ccb);
2238
2239	/*
2240	 * If we return an error, we're not mounted any more,
2241	 * so release any device reservation.
2242	 */
2243	if (error != 0) {
2244		(void) sareservereleaseunit(periph, FALSE);
2245	} else {
2246		/*
2247		 * Clear I/O residual.
2248		 */
2249		softc->last_io_resid = 0;
2250		softc->last_ctl_resid = 0;
2251	}
2252	return (error);
2253}
2254
2255/*
2256 * How many filemarks do we need to write if we were to terminate the
2257 * tape session right now? Note that this can be a negative number
2258 */
2259
2260static int
2261samarkswanted(struct cam_periph *periph)
2262{
2263	int	markswanted;
2264	struct	sa_softc *softc;
2265
2266	softc = (struct sa_softc *)periph->softc;
2267	markswanted = 0;
2268	if ((softc->flags & SA_FLAG_TAPE_WRITTEN) != 0) {
2269		markswanted++;
2270		if (softc->quirks & SA_QUIRK_2FM)
2271			markswanted++;
2272	}
2273	markswanted -= softc->filemarks;
2274	return (markswanted);
2275}
2276
2277static int
2278sacheckeod(struct cam_periph *periph)
2279{
2280	int	error;
2281	int	markswanted;
2282	struct	sa_softc *softc;
2283
2284	softc = (struct sa_softc *)periph->softc;
2285	markswanted = samarkswanted(periph);
2286
2287	if (markswanted > 0) {
2288		error = sawritefilemarks(periph, markswanted, FALSE);
2289	} else {
2290		error = 0;
2291	}
2292	return (error);
2293}
2294
2295static int
2296saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
2297{
2298	static const char *toobig =
2299	    "%d-byte tape record bigger than suplied buffer\n";
2300	struct	cam_periph *periph;
2301	struct	sa_softc *softc;
2302	struct	ccb_scsiio *csio;
2303	struct	scsi_sense_data *sense;
2304	u_int32_t resid = 0;
2305	int32_t	info = 0;
2306	cam_status status;
2307	int error_code, sense_key, asc, ascq, error, aqvalid;
2308
2309	periph = xpt_path_periph(ccb->ccb_h.path);
2310	softc = (struct sa_softc *)periph->softc;
2311	csio = &ccb->csio;
2312	sense = &csio->sense_data;
2313	scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq);
2314	aqvalid = sense->extra_len >= 6;
2315	error = 0;
2316
2317	status = csio->ccb_h.status & CAM_STATUS_MASK;
2318
2319	/*
2320	 * Calculate/latch up, any residuals... We do this in a funny 2-step
2321	 * so we can print stuff here if we have CAM_DEBUG enabled for this
2322	 * unit.
2323	 */
2324	if (status == CAM_SCSI_STATUS_ERROR) {
2325		if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
2326			info = (int32_t) scsi_4btoul(sense->info);
2327			resid = info;
2328			if ((softc->flags & SA_FLAG_FIXED) != 0)
2329				resid *= softc->media_blksize;
2330		} else {
2331			resid = csio->dxfer_len;
2332			info = resid;
2333			if ((softc->flags & SA_FLAG_FIXED) != 0) {
2334				if (softc->media_blksize)
2335					info /= softc->media_blksize;
2336			}
2337		}
2338		if (CCB_Type(csio) == SA_CCB_BUFFER_IO) {
2339			bcopy((caddr_t) sense, (caddr_t) &softc->last_io_sense,
2340			    sizeof (struct scsi_sense_data));
2341			bcopy(csio->cdb_io.cdb_bytes, softc->last_io_cdb,
2342			    (int) csio->cdb_len);
2343			softc->last_io_resid = resid;
2344			softc->last_resid_was_io = 1;
2345		} else {
2346			bcopy((caddr_t) sense, (caddr_t) &softc->last_ctl_sense,
2347			    sizeof (struct scsi_sense_data));
2348			bcopy(csio->cdb_io.cdb_bytes, softc->last_ctl_cdb,
2349			    (int) csio->cdb_len);
2350			softc->last_ctl_resid = resid;
2351			softc->last_resid_was_io = 0;
2352		}
2353		CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("CDB[0]=0x%x Key 0x%x "
2354		    "ASC/ASCQ 0x%x/0x%x CAM STATUS 0x%x flags 0x%x resid %d "
2355		    "dxfer_len %d\n", csio->cdb_io.cdb_bytes[0] & 0xff,
2356		    sense_key, asc, ascq, status,
2357		    sense->flags & ~SSD_KEY_RESERVED, resid, csio->dxfer_len));
2358	} else {
2359		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
2360		    ("Cam Status 0x%x\n", status));
2361	}
2362
2363	switch (status) {
2364	case CAM_REQ_CMP:
2365		return (0);
2366	case CAM_SCSI_STATUS_ERROR:
2367		/*
2368		 * If a read/write command, we handle it here.
2369		 */
2370		if (CCB_Type(csio) != SA_CCB_WAITING) {
2371			break;
2372		}
2373		/*
2374		 * If this was just EOM/EOP, Filemark, Setmark or ILI detected
2375		 * on a non read/write command, we assume it's not an error
2376		 * and propagate the residule and return.
2377		 */
2378		if ((aqvalid && asc == 0 && ascq > 0 && ascq <= 5) ||
2379		    (aqvalid == 0 && sense_key == SSD_KEY_NO_SENSE)) {
2380			csio->resid = resid;
2381			QFRLS(ccb);
2382			return (0);
2383		}
2384		/*
2385		 * Otherwise, we let the common code handle this.
2386		 */
2387		return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb));
2388
2389	/*
2390	 * XXX: To Be Fixed
2391	 * We cannot depend upon CAM honoring retry counts for these.
2392	 */
2393	case CAM_SCSI_BUS_RESET:
2394	case CAM_BDR_SENT:
2395		if (ccb->ccb_h.retry_count <= 0) {
2396			return (EIO);
2397			break;
2398		}
2399		/* FALLTHROUGH */
2400	default:
2401		return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb));
2402	}
2403
2404	/*
2405	 * Handle filemark, end of tape, mismatched record sizes....
2406	 * From this point out, we're only handling read/write cases.
2407	 * Handle writes && reads differently.
2408	 */
2409
2410	if (csio->cdb_io.cdb_bytes[0] == SA_WRITE) {
2411		if (sense_key == SSD_KEY_VOLUME_OVERFLOW) {
2412			csio->resid = resid;
2413			error = ENOSPC;
2414		} else if (sense->flags & SSD_EOM) {
2415			softc->flags |= SA_FLAG_EOM_PENDING;
2416			/*
2417			 * Grotesque as it seems, the few times
2418			 * I've actually seen a non-zero resid,
2419			 * the tape drive actually lied and had
2420			 * writtent all the data!.
2421			 */
2422			csio->resid = 0;
2423		}
2424	} else {
2425		csio->resid = resid;
2426		if (sense_key == SSD_KEY_BLANK_CHECK) {
2427			if (softc->quirks & SA_QUIRK_1FM) {
2428				error = 0;
2429				softc->flags |= SA_FLAG_EOM_PENDING;
2430			} else {
2431				error = EIO;
2432			}
2433		} else if (sense->flags & SSD_FILEMARK) {
2434			if (softc->flags & SA_FLAG_FIXED) {
2435				error = -1;
2436				softc->flags |= SA_FLAG_EOF_PENDING;
2437			}
2438			/*
2439			 * Unconditionally, if we detected a filemark on a read,
2440			 * mark that we've run moved a file ahead.
2441			 */
2442			if (softc->fileno != (daddr_t) -1) {
2443				softc->fileno++;
2444				softc->blkno = 0;
2445				csio->ccb_h.ccb_pflags |= SA_POSITION_UPDATED;
2446			}
2447		}
2448	}
2449
2450	/*
2451	 * Incorrect Length usually applies to read, but can apply to writes.
2452	 */
2453	if (error == 0 && (sense->flags & SSD_ILI)) {
2454		if (info < 0) {
2455			xpt_print_path(csio->ccb_h.path);
2456			printf(toobig, csio->dxfer_len - info);
2457			csio->resid = csio->dxfer_len;
2458			error = EIO;
2459		} else {
2460			csio->resid = resid;
2461			if (softc->flags & SA_FLAG_FIXED) {
2462				softc->flags |= SA_FLAG_EIO_PENDING;
2463			}
2464			/*
2465			 * Bump the block number if we hadn't seen a filemark.
2466			 * Do this independent of errors (we've moved anyway).
2467			 */
2468			if ((sense->flags & SSD_FILEMARK) == 0) {
2469				if (softc->blkno != (daddr_t) -1) {
2470					softc->blkno++;
2471					csio->ccb_h.ccb_pflags |=
2472					   SA_POSITION_UPDATED;
2473				}
2474			}
2475		}
2476	}
2477
2478	if (error <= 0) {
2479		/*
2480		 * Unfreeze the queue if frozen as we're not returning anything
2481		 * to our waiters that would indicate an I/O error has occurred
2482		 * (yet).
2483		 */
2484		QFRLS(ccb);
2485		error = 0;
2486	}
2487	return (error);
2488}
2489
2490static int
2491sagetparams(struct cam_periph *periph, sa_params params_to_get,
2492	    u_int32_t *blocksize, u_int8_t *density, u_int32_t *numblocks,
2493	    int *buff_mode, u_int8_t *write_protect, u_int8_t *speed,
2494	    int *comp_supported, int *comp_enabled, u_int32_t *comp_algorithm,
2495	    sa_comp_t *tcs)
2496{
2497	union ccb *ccb;
2498	void *mode_buffer;
2499	struct scsi_mode_header_6 *mode_hdr;
2500	struct scsi_mode_blk_desc *mode_blk;
2501	int mode_buffer_len;
2502	struct sa_softc *softc;
2503	u_int8_t cpage;
2504	int error;
2505	cam_status status;
2506
2507	softc = (struct sa_softc *)periph->softc;
2508	ccb = cam_periph_getccb(periph, 1);
2509	if (softc->quirks & SA_QUIRK_NO_CPAGE)
2510		cpage = SA_DEVICE_CONFIGURATION_PAGE;
2511	else
2512		cpage = SA_DATA_COMPRESSION_PAGE;
2513
2514retry:
2515	mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk);
2516
2517	if (params_to_get & SA_PARAM_COMPRESSION) {
2518		if (softc->quirks & SA_QUIRK_NOCOMP) {
2519			*comp_supported = FALSE;
2520			params_to_get &= ~SA_PARAM_COMPRESSION;
2521		} else
2522			mode_buffer_len += sizeof (sa_comp_t);
2523	}
2524
2525	mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK | M_ZERO);
2526	mode_hdr = (struct scsi_mode_header_6 *)mode_buffer;
2527	mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
2528
2529	/* it is safe to retry this */
2530	scsi_mode_sense(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
2531	    SMS_PAGE_CTRL_CURRENT, (params_to_get & SA_PARAM_COMPRESSION) ?
2532	    cpage : SMS_VENDOR_SPECIFIC_PAGE, mode_buffer, mode_buffer_len,
2533	    SSD_FULL_SIZE, SCSIOP_TIMEOUT);
2534
2535	error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
2536	    &softc->device_stats);
2537	QFRLS(ccb);
2538
2539	status = ccb->ccb_h.status & CAM_STATUS_MASK;
2540
2541	if (error == EINVAL && (params_to_get & SA_PARAM_COMPRESSION) != 0) {
2542		/*
2543		 * Hmm. Let's see if we can try another page...
2544		 * If we've already done that, give up on compression
2545		 * for this device and remember this for the future
2546		 * and attempt the request without asking for compression
2547		 * info.
2548		 */
2549		if (cpage == SA_DATA_COMPRESSION_PAGE) {
2550			cpage = SA_DEVICE_CONFIGURATION_PAGE;
2551			goto retry;
2552		}
2553		softc->quirks |= SA_QUIRK_NOCOMP;
2554		free(mode_buffer, M_TEMP);
2555		goto retry;
2556	} else if (status == CAM_SCSI_STATUS_ERROR) {
2557		/* Tell the user about the fatal error. */
2558		scsi_sense_print(&ccb->csio);
2559		goto sagetparamsexit;
2560	}
2561
2562	/*
2563	 * If the user only wants the compression information, and
2564	 * the device doesn't send back the block descriptor, it's
2565	 * no big deal.  If the user wants more than just
2566	 * compression, though, and the device doesn't pass back the
2567	 * block descriptor, we need to send another mode sense to
2568	 * get the block descriptor.
2569	 */
2570	if ((mode_hdr->blk_desc_len == 0) &&
2571	    (params_to_get & SA_PARAM_COMPRESSION) &&
2572	    (params_to_get & ~(SA_PARAM_COMPRESSION))) {
2573
2574		/*
2575		 * Decrease the mode buffer length by the size of
2576		 * the compression page, to make sure the data
2577		 * there doesn't get overwritten.
2578		 */
2579		mode_buffer_len -= sizeof (sa_comp_t);
2580
2581		/*
2582		 * Now move the compression page that we presumably
2583		 * got back down the memory chunk a little bit so
2584		 * it doesn't get spammed.
2585		 */
2586		bcopy(&mode_hdr[0], &mode_hdr[1], sizeof (sa_comp_t));
2587		bzero(&mode_hdr[0], sizeof (mode_hdr[0]));
2588
2589		/*
2590		 * Now, we issue another mode sense and just ask
2591		 * for the block descriptor, etc.
2592		 */
2593
2594		scsi_mode_sense(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE,
2595		    SMS_PAGE_CTRL_CURRENT, SMS_VENDOR_SPECIFIC_PAGE,
2596		    mode_buffer, mode_buffer_len, SSD_FULL_SIZE,
2597		    SCSIOP_TIMEOUT);
2598
2599		error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
2600		    &softc->device_stats);
2601		QFRLS(ccb);
2602
2603		if (error != 0)
2604			goto sagetparamsexit;
2605	}
2606
2607	if (params_to_get & SA_PARAM_BLOCKSIZE)
2608		*blocksize = scsi_3btoul(mode_blk->blklen);
2609
2610	if (params_to_get & SA_PARAM_NUMBLOCKS)
2611		*numblocks = scsi_3btoul(mode_blk->nblocks);
2612
2613	if (params_to_get & SA_PARAM_BUFF_MODE)
2614		*buff_mode = mode_hdr->dev_spec & SMH_SA_BUF_MODE_MASK;
2615
2616	if (params_to_get & SA_PARAM_DENSITY)
2617		*density = mode_blk->density;
2618
2619	if (params_to_get & SA_PARAM_WP)
2620		*write_protect = (mode_hdr->dev_spec & SMH_SA_WP)? TRUE : FALSE;
2621
2622	if (params_to_get & SA_PARAM_SPEED)
2623		*speed = mode_hdr->dev_spec & SMH_SA_SPEED_MASK;
2624
2625	if (params_to_get & SA_PARAM_COMPRESSION) {
2626		sa_comp_t *ntcs = (sa_comp_t *) &mode_blk[1];
2627		if (cpage == SA_DATA_COMPRESSION_PAGE) {
2628			struct scsi_data_compression_page *cp = &ntcs->dcomp;
2629			*comp_supported =
2630			    (cp->dce_and_dcc & SA_DCP_DCC)? TRUE : FALSE;
2631			*comp_enabled =
2632			    (cp->dce_and_dcc & SA_DCP_DCE)? TRUE : FALSE;
2633			*comp_algorithm = scsi_4btoul(cp->comp_algorithm);
2634		} else {
2635			struct scsi_dev_conf_page *cp = &ntcs->dconf;
2636			/*
2637			 * We don't really know whether this device supports
2638			 * Data Compression if the the algorithm field is
2639			 * zero. Just say we do.
2640			 */
2641			*comp_supported = TRUE;
2642			*comp_enabled =
2643			    (cp->sel_comp_alg != SA_COMP_NONE)? TRUE : FALSE;
2644			*comp_algorithm = cp->sel_comp_alg;
2645		}
2646		if (tcs != NULL)
2647			bcopy(ntcs, tcs, sizeof (sa_comp_t));
2648	}
2649
2650	if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
2651		int idx;
2652		char *xyz = mode_buffer;
2653		xpt_print_path(periph->path);
2654		printf("Mode Sense Data=");
2655		for (idx = 0; idx < mode_buffer_len; idx++)
2656			printf(" 0x%02x", xyz[idx] & 0xff);
2657		printf("\n");
2658	}
2659
2660sagetparamsexit:
2661
2662	xpt_release_ccb(ccb);
2663	free(mode_buffer, M_TEMP);
2664	return (error);
2665}
2666
2667/*
2668 * The purpose of this function is to set one of four different parameters
2669 * for a tape drive:
2670 *	- blocksize
2671 *	- density
2672 *	- compression / compression algorithm
2673 *	- buffering mode
2674 *
2675 * The assumption is that this will be called from saioctl(), and therefore
2676 * from a process context.  Thus the waiting malloc calls below.  If that
2677 * assumption ever changes, the malloc calls should be changed to be
2678 * NOWAIT mallocs.
2679 *
2680 * Any or all of the four parameters may be set when this function is
2681 * called.  It should handle setting more than one parameter at once.
2682 */
2683static int
2684sasetparams(struct cam_periph *periph, sa_params params_to_set,
2685	    u_int32_t blocksize, u_int8_t density, u_int32_t calg,
2686	    u_int32_t sense_flags)
2687{
2688	struct sa_softc *softc;
2689	u_int32_t current_blocksize;
2690	u_int32_t current_calg;
2691	u_int8_t current_density;
2692	u_int8_t current_speed;
2693	int comp_enabled, comp_supported;
2694	void *mode_buffer;
2695	int mode_buffer_len;
2696	struct scsi_mode_header_6 *mode_hdr;
2697	struct scsi_mode_blk_desc *mode_blk;
2698	sa_comp_t *ccomp, *cpage;
2699	int buff_mode;
2700	union ccb *ccb = NULL;
2701	int error;
2702
2703	softc = (struct sa_softc *)periph->softc;
2704
2705	ccomp = malloc(sizeof (sa_comp_t), M_TEMP, M_WAITOK);
2706
2707	/*
2708	 * Since it doesn't make sense to set the number of blocks, or
2709	 * write protection, we won't try to get the current value.  We
2710	 * always want to get the blocksize, so we can set it back to the
2711	 * proper value.
2712	 */
2713	error = sagetparams(periph,
2714	    params_to_set | SA_PARAM_BLOCKSIZE | SA_PARAM_SPEED,
2715	    &current_blocksize, &current_density, NULL, &buff_mode, NULL,
2716	    &current_speed, &comp_supported, &comp_enabled,
2717	    &current_calg, ccomp);
2718
2719	if (error != 0) {
2720		free(ccomp, M_TEMP);
2721		return (error);
2722	}
2723
2724	mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk);
2725	if (params_to_set & SA_PARAM_COMPRESSION)
2726		mode_buffer_len += sizeof (sa_comp_t);
2727
2728	mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK | M_ZERO);
2729
2730	mode_hdr = (struct scsi_mode_header_6 *)mode_buffer;
2731	mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
2732
2733	ccb = cam_periph_getccb(periph, 1);
2734
2735retry:
2736
2737	if (params_to_set & SA_PARAM_COMPRESSION) {
2738		if (mode_blk) {
2739			cpage = (sa_comp_t *)&mode_blk[1];
2740		} else {
2741			cpage = (sa_comp_t *)&mode_hdr[1];
2742		}
2743		bcopy(ccomp, cpage, sizeof (sa_comp_t));
2744		cpage->hdr.pagecode &= ~0x80;
2745	} else
2746		cpage = NULL;
2747
2748	/*
2749	 * If the caller wants us to set the blocksize, use the one they
2750	 * pass in.  Otherwise, use the blocksize we got back from the
2751	 * mode select above.
2752	 */
2753	if (mode_blk) {
2754		if (params_to_set & SA_PARAM_BLOCKSIZE)
2755			scsi_ulto3b(blocksize, mode_blk->blklen);
2756		else
2757			scsi_ulto3b(current_blocksize, mode_blk->blklen);
2758
2759		/*
2760		 * Set density if requested, else preserve old density.
2761		 * SCSI_SAME_DENSITY only applies to SCSI-2 or better
2762		 * devices, else density we've latched up in our softc.
2763		 */
2764		if (params_to_set & SA_PARAM_DENSITY) {
2765			mode_blk->density = density;
2766		} else if (softc->scsi_rev > SCSI_REV_CCS) {
2767			mode_blk->density = SCSI_SAME_DENSITY;
2768		} else {
2769			mode_blk->density = softc->media_density;
2770		}
2771	}
2772
2773	/*
2774	 * For mode selects, these two fields must be zero.
2775	 */
2776	mode_hdr->data_length = 0;
2777	mode_hdr->medium_type = 0;
2778
2779	/* set the speed to the current value */
2780	mode_hdr->dev_spec = current_speed;
2781
2782	/* set single-initiator buffering mode */
2783	mode_hdr->dev_spec |= SMH_SA_BUF_MODE_SIBUF;
2784
2785	if (mode_blk)
2786		mode_hdr->blk_desc_len = sizeof(struct scsi_mode_blk_desc);
2787	else
2788		mode_hdr->blk_desc_len = 0;
2789
2790	/*
2791	 * First, if the user wants us to set the compression algorithm or
2792	 * just turn compression on, check to make sure that this drive
2793	 * supports compression.
2794	 */
2795	if (params_to_set & SA_PARAM_COMPRESSION) {
2796		/*
2797		 * If the compression algorithm is 0, disable compression.
2798		 * If the compression algorithm is non-zero, enable
2799		 * compression and set the compression type to the
2800		 * specified compression algorithm, unless the algorithm is
2801		 * MT_COMP_ENABLE.  In that case, we look at the
2802		 * compression algorithm that is currently set and if it is
2803		 * non-zero, we leave it as-is.  If it is zero, and we have
2804		 * saved a compression algorithm from a time when
2805		 * compression was enabled before, set the compression to
2806		 * the saved value.
2807		 */
2808		switch (ccomp->hdr.pagecode & ~0x80) {
2809		case SA_DATA_COMPRESSION_PAGE:
2810		if (ccomp->dcomp.dce_and_dcc & SA_DCP_DCC) {
2811			struct scsi_data_compression_page *dcp = &cpage->dcomp;
2812			if (calg == 0) {
2813				/*
2814				 * Disable compression, but leave the
2815				 * decompression and the capability bit
2816				 * alone.
2817				 */
2818				dcp->dce_and_dcc = SA_DCP_DCC;
2819				dcp->dde_and_red |= SA_DCP_DDE;
2820				break;
2821			}
2822			/* enable compression && decompression */
2823			dcp->dce_and_dcc = SA_DCP_DCE | SA_DCP_DCC;
2824			dcp->dde_and_red |= SA_DCP_DDE;
2825			/*
2826			 * If there, use compression algorithm from caller.
2827			 * Otherwise, if there's a saved compression algorithm
2828			 * and there is no current algorithm, use the saved
2829			 * algorithm. Else parrot back what we got and hope
2830			 * for the best.
2831			 */
2832			if (calg != MT_COMP_ENABLE) {
2833				scsi_ulto4b(calg, dcp->comp_algorithm);
2834				scsi_ulto4b(calg, dcp->decomp_algorithm);
2835			} else if (scsi_4btoul(dcp->comp_algorithm) == 0 &&
2836			    softc->saved_comp_algorithm != 0) {
2837				scsi_ulto4b(softc->saved_comp_algorithm,
2838				    dcp->comp_algorithm);
2839				scsi_ulto4b(softc->saved_comp_algorithm,
2840				    dcp->decomp_algorithm);
2841			}
2842			break;
2843		}
2844		case SA_DEVICE_CONFIGURATION_PAGE:
2845		{
2846			struct scsi_dev_conf_page *dcp = &cpage->dconf;
2847			if (calg == 0) {
2848				dcp->sel_comp_alg = SA_COMP_NONE;
2849				break;
2850			}
2851			if (calg != MT_COMP_ENABLE) {
2852				dcp->sel_comp_alg = calg;
2853			} else if (dcp->sel_comp_alg == SA_COMP_NONE &&
2854			    softc->saved_comp_algorithm != 0) {
2855				dcp->sel_comp_alg = softc->saved_comp_algorithm;
2856			}
2857			break;
2858		}
2859		default:
2860			/*
2861			 * The drive doesn't seem to support compression,
2862			 * so turn off the set compression bit.
2863			 */
2864			params_to_set &= ~SA_PARAM_COMPRESSION;
2865			xpt_print_path(periph->path);
2866			printf("device does not seem to support compression\n");
2867
2868			/*
2869			 * If that was the only thing the user wanted us to set,
2870			 * clean up allocated resources and return with
2871			 * 'operation not supported'.
2872			 */
2873			if (params_to_set == SA_PARAM_NONE) {
2874				free(mode_buffer, M_TEMP);
2875				xpt_release_ccb(ccb);
2876				return (ENODEV);
2877			}
2878
2879			/*
2880			 * That wasn't the only thing the user wanted us to set.
2881			 * So, decrease the stated mode buffer length by the
2882			 * size of the compression mode page.
2883			 */
2884			mode_buffer_len -= sizeof(sa_comp_t);
2885		}
2886	}
2887
2888	/* It is safe to retry this operation */
2889	scsi_mode_select(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG,
2890	    (params_to_set & SA_PARAM_COMPRESSION)? TRUE : FALSE,
2891	    FALSE, mode_buffer, mode_buffer_len, SSD_FULL_SIZE, SCSIOP_TIMEOUT);
2892
2893	error = cam_periph_runccb(ccb, saerror, 0,
2894	    sense_flags, &softc->device_stats);
2895	QFRLS(ccb);
2896
2897	if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
2898		int idx;
2899		char *xyz = mode_buffer;
2900		xpt_print_path(periph->path);
2901		printf("Err%d, Mode Select Data=", error);
2902		for (idx = 0; idx < mode_buffer_len; idx++)
2903			printf(" 0x%02x", xyz[idx] & 0xff);
2904		printf("\n");
2905	}
2906
2907
2908	if (error) {
2909		/*
2910		 * If we can, try without setting density/blocksize.
2911		 */
2912		if (mode_blk) {
2913			if ((params_to_set &
2914			    (SA_PARAM_DENSITY|SA_PARAM_BLOCKSIZE)) == 0) {
2915				mode_blk = NULL;
2916				goto retry;
2917			}
2918		} else {
2919			mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
2920			cpage = (sa_comp_t *)&mode_blk[1];
2921		}
2922
2923		/*
2924		 * If we were setting the blocksize, and that failed, we
2925		 * want to set it to its original value.  If we weren't
2926		 * setting the blocksize, we don't want to change it.
2927		 */
2928		scsi_ulto3b(current_blocksize, mode_blk->blklen);
2929
2930		/*
2931		 * Set density if requested, else preserve old density.
2932		 * SCSI_SAME_DENSITY only applies to SCSI-2 or better
2933		 * devices, else density we've latched up in our softc.
2934		 */
2935		if (params_to_set & SA_PARAM_DENSITY) {
2936			mode_blk->density = current_density;
2937		} else if (softc->scsi_rev > SCSI_REV_CCS) {
2938			mode_blk->density = SCSI_SAME_DENSITY;
2939		} else {
2940			mode_blk->density = softc->media_density;
2941		}
2942
2943		if (params_to_set & SA_PARAM_COMPRESSION)
2944			bcopy(ccomp, cpage, sizeof (sa_comp_t));
2945
2946		/*
2947		 * The retry count is the only CCB field that might have been
2948		 * changed that we care about, so reset it back to 1.
2949		 */
2950		ccb->ccb_h.retry_count = 1;
2951		cam_periph_runccb(ccb, saerror, 0, sense_flags,
2952		    &softc->device_stats);
2953		QFRLS(ccb);
2954	}
2955
2956	xpt_release_ccb(ccb);
2957
2958	if (ccomp != NULL)
2959		free(ccomp, M_TEMP);
2960
2961	if (params_to_set & SA_PARAM_COMPRESSION) {
2962		if (error) {
2963			softc->flags &= ~SA_FLAG_COMP_ENABLED;
2964			/*
2965			 * Even if we get an error setting compression,
2966			 * do not say that we don't support it. We could
2967			 * have been wrong, or it may be media specific.
2968			 *	softc->flags &= ~SA_FLAG_COMP_SUPP;
2969			 */
2970			softc->saved_comp_algorithm = softc->comp_algorithm;
2971			softc->comp_algorithm = 0;
2972		} else {
2973			softc->flags |= SA_FLAG_COMP_ENABLED;
2974			softc->comp_algorithm = calg;
2975		}
2976	}
2977
2978	free(mode_buffer, M_TEMP);
2979	return (error);
2980}
2981
2982static void
2983saprevent(struct cam_periph *periph, int action)
2984{
2985	struct	sa_softc *softc;
2986	union	ccb *ccb;
2987	int	error, sf;
2988
2989	softc = (struct sa_softc *)periph->softc;
2990
2991	if ((action == PR_ALLOW) && (softc->flags & SA_FLAG_TAPE_LOCKED) == 0)
2992		return;
2993	if ((action == PR_PREVENT) && (softc->flags & SA_FLAG_TAPE_LOCKED) != 0)
2994		return;
2995
2996	/*
2997	 * We can be quiet about illegal requests.
2998	 */
2999	if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
3000		sf = 0;
3001	} else
3002		sf = SF_QUIET_IR;
3003
3004	ccb = cam_periph_getccb(periph, 1);
3005
3006	/* It is safe to retry this operation */
3007	scsi_prevent(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, action,
3008	    SSD_FULL_SIZE, SCSIOP_TIMEOUT);
3009
3010	error = cam_periph_runccb(ccb, saerror, 0, sf, &softc->device_stats);
3011	QFRLS(ccb);
3012	if (error == 0) {
3013		if (action == PR_ALLOW)
3014			softc->flags &= ~SA_FLAG_TAPE_LOCKED;
3015		else
3016			softc->flags |= SA_FLAG_TAPE_LOCKED;
3017	}
3018
3019	xpt_release_ccb(ccb);
3020}
3021
3022static int
3023sarewind(struct cam_periph *periph)
3024{
3025	union	ccb *ccb;
3026	struct	sa_softc *softc;
3027	int	error;
3028
3029	softc = (struct sa_softc *)periph->softc;
3030
3031	ccb = cam_periph_getccb(periph, 1);
3032
3033	/* It is safe to retry this operation */
3034	scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE,
3035	    SSD_FULL_SIZE, REWIND_TIMEOUT);
3036
3037	softc->dsreg = MTIO_DSREG_REW;
3038	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3039	softc->dsreg = MTIO_DSREG_REST;
3040
3041	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3042		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
3043
3044	xpt_release_ccb(ccb);
3045	if (error == 0)
3046		softc->fileno = softc->blkno = (daddr_t) 0;
3047	else
3048		softc->fileno = softc->blkno = (daddr_t) -1;
3049	return (error);
3050}
3051
3052static int
3053saspace(struct cam_periph *periph, int count, scsi_space_code code)
3054{
3055	union	ccb *ccb;
3056	struct	sa_softc *softc;
3057	int	error;
3058
3059	softc = (struct sa_softc *)periph->softc;
3060
3061	ccb = cam_periph_getccb(periph, 1);
3062
3063	/* This cannot be retried */
3064
3065	scsi_space(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, code, count,
3066	    SSD_FULL_SIZE, SPACE_TIMEOUT);
3067
3068	/*
3069	 * Clear residual because we will be using it.
3070	 */
3071	softc->last_ctl_resid = 0;
3072
3073	softc->dsreg = (count < 0)? MTIO_DSREG_REV : MTIO_DSREG_FWD;
3074	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3075	softc->dsreg = MTIO_DSREG_REST;
3076
3077	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3078		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
3079
3080	xpt_release_ccb(ccb);
3081
3082	/*
3083	 * If a spacing operation has failed, we need to invalidate
3084	 * this mount.
3085	 *
3086	 * If the spacing operation was setmarks or to end of recorded data,
3087	 * we no longer know our relative position.
3088	 *
3089	 * If the spacing operations was spacing files in reverse, we
3090	 * take account of the residual, but still check against less
3091	 * than zero- if we've gone negative, we must have hit BOT.
3092	 *
3093	 * If the spacing operations was spacing records in reverse and
3094	 * we have a residual, we've either hit BOT or hit a filemark.
3095	 * In the former case, we know our new record number (0). In
3096	 * the latter case, we have absolutely no idea what the real
3097	 * record number is- we've stopped between the end of the last
3098	 * record in the previous file and the filemark that stopped
3099	 * our spacing backwards.
3100	 */
3101	if (error) {
3102		softc->fileno = softc->blkno = (daddr_t) -1;
3103	} else if (code == SS_SETMARKS || code == SS_EOD) {
3104		softc->fileno = softc->blkno = (daddr_t) -1;
3105	} else if (code == SS_FILEMARKS && softc->fileno != (daddr_t) -1) {
3106		softc->fileno += (count - softc->last_ctl_resid);
3107		if (softc->fileno < 0)	/* we must of hit BOT */
3108			softc->fileno = 0;
3109		softc->blkno = 0;
3110	} else if (code == SS_BLOCKS && softc->blkno != (daddr_t) -1) {
3111		softc->blkno += (count - softc->last_ctl_resid);
3112		if (count < 0) {
3113			if (softc->last_ctl_resid || softc->blkno < 0) {
3114				if (softc->fileno == 0) {
3115					softc->blkno = 0;
3116				} else {
3117					softc->blkno = (daddr_t) -1;
3118				}
3119			}
3120		}
3121	}
3122	return (error);
3123}
3124
3125static int
3126sawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks)
3127{
3128	union	ccb *ccb;
3129	struct	sa_softc *softc;
3130	int	error, nwm = 0;
3131
3132	softc = (struct sa_softc *)periph->softc;
3133
3134	ccb = cam_periph_getccb(periph, 1);
3135	/*
3136	 * Clear residual because we will be using it.
3137	 */
3138	softc->last_ctl_resid = 0;
3139
3140	softc->dsreg = MTIO_DSREG_FMK;
3141	/* this *must* not be retried */
3142	scsi_write_filemarks(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG,
3143	    FALSE, setmarks, nmarks, SSD_FULL_SIZE, IO_TIMEOUT);
3144	softc->dsreg = MTIO_DSREG_REST;
3145
3146
3147	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3148
3149	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3150		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
3151
3152	if (error == 0 && nmarks) {
3153		struct sa_softc *softc = (struct sa_softc *)periph->softc;
3154		nwm = nmarks - softc->last_ctl_resid;
3155		softc->filemarks += nwm;
3156	}
3157
3158	xpt_release_ccb(ccb);
3159
3160	/*
3161	 * Update relative positions (if we're doing that).
3162	 */
3163	if (error) {
3164		softc->fileno = softc->blkno = (daddr_t) -1;
3165	} else if (softc->fileno != (daddr_t) -1) {
3166		softc->fileno += nwm;
3167		softc->blkno = 0;
3168	}
3169	return (error);
3170}
3171
3172static int
3173sardpos(struct cam_periph *periph, int hard, u_int32_t *blkptr)
3174{
3175	struct scsi_tape_position_data loc;
3176	union ccb *ccb;
3177	struct sa_softc *softc = (struct sa_softc *)periph->softc;
3178	int error;
3179
3180	/*
3181	 * We try and flush any buffered writes here if we were writing
3182	 * and we're trying to get hardware block position. It eats
3183	 * up performance substantially, but I'm wary of drive firmware.
3184	 *
3185	 * I think that *logical* block position is probably okay-
3186	 * but hardware block position might have to wait for data
3187	 * to hit media to be valid. Caveat Emptor.
3188	 */
3189
3190	if (hard && (softc->flags & SA_FLAG_TAPE_WRITTEN)) {
3191		error = sawritefilemarks(periph, 0, 0);
3192		if (error && error != EACCES)
3193			return (error);
3194	}
3195
3196	ccb = cam_periph_getccb(periph, 1);
3197	scsi_read_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
3198	    hard, &loc, SSD_FULL_SIZE, SCSIOP_TIMEOUT);
3199	softc->dsreg = MTIO_DSREG_RBSY;
3200	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3201	softc->dsreg = MTIO_DSREG_REST;
3202	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3203		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
3204
3205	if (error == 0) {
3206		if (loc.flags & SA_RPOS_UNCERTAIN) {
3207			error = EINVAL;		/* nothing is certain */
3208		} else {
3209			*blkptr = scsi_4btoul(loc.firstblk);
3210		}
3211	}
3212
3213	xpt_release_ccb(ccb);
3214	return (error);
3215}
3216
3217static int
3218sasetpos(struct cam_periph *periph, int hard, u_int32_t *blkptr)
3219{
3220	union ccb *ccb;
3221	struct sa_softc *softc;
3222	int error;
3223
3224	/*
3225	 * We used to try and flush any buffered writes here.
3226	 * Now we push this onto user applications to either
3227	 * flush the pending writes themselves (via a zero count
3228	 * WRITE FILEMARKS command) or they can trust their tape
3229	 * drive to do this correctly for them.
3230 	 */
3231
3232	softc = (struct sa_softc *)periph->softc;
3233	ccb = cam_periph_getccb(periph, 1);
3234
3235
3236	scsi_set_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
3237	    hard, *blkptr, SSD_FULL_SIZE, SPACE_TIMEOUT);
3238
3239
3240	softc->dsreg = MTIO_DSREG_POS;
3241	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3242	softc->dsreg = MTIO_DSREG_REST;
3243	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3244		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
3245	xpt_release_ccb(ccb);
3246	/*
3247	 * Note relative file && block number position as now unknown.
3248	 */
3249	softc->fileno = softc->blkno = (daddr_t) -1;
3250	return (error);
3251}
3252
3253static int
3254saretension(struct cam_periph *periph)
3255{
3256	union ccb *ccb;
3257	struct sa_softc *softc;
3258	int error;
3259
3260	softc = (struct sa_softc *)periph->softc;
3261
3262	ccb = cam_periph_getccb(periph, 1);
3263
3264	/* It is safe to retry this operation */
3265	scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
3266	    FALSE, TRUE,  TRUE, SSD_FULL_SIZE, ERASE_TIMEOUT);
3267
3268	softc->dsreg = MTIO_DSREG_TEN;
3269	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3270	softc->dsreg = MTIO_DSREG_REST;
3271
3272	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3273		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
3274	xpt_release_ccb(ccb);
3275	if (error == 0)
3276		softc->fileno = softc->blkno = (daddr_t) 0;
3277	else
3278		softc->fileno = softc->blkno = (daddr_t) -1;
3279	return (error);
3280}
3281
3282static int
3283sareservereleaseunit(struct cam_periph *periph, int reserve)
3284{
3285	union ccb *ccb;
3286	struct sa_softc *softc;
3287	int error;
3288
3289	softc = (struct sa_softc *)periph->softc;
3290	ccb = cam_periph_getccb(periph,  1);
3291
3292	/* It is safe to retry this operation */
3293	scsi_reserve_release_unit(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG,
3294	    FALSE,  0, SSD_FULL_SIZE,  SCSIOP_TIMEOUT, reserve);
3295	softc->dsreg = MTIO_DSREG_RBSY;
3296	error = cam_periph_runccb(ccb, saerror, 0,
3297	    SF_RETRY_UA | SF_NO_PRINT, &softc->device_stats);
3298	softc->dsreg = MTIO_DSREG_REST;
3299	QFRLS(ccb);
3300	xpt_release_ccb(ccb);
3301
3302	/*
3303	 * If the error was Illegal Request, then the device doesn't support
3304	 * RESERVE/RELEASE. This is not an error.
3305	 */
3306	if (error == EINVAL) {
3307		error = 0;
3308	}
3309
3310	return (error);
3311}
3312
3313static int
3314saloadunload(struct cam_periph *periph, int load)
3315{
3316	union	ccb *ccb;
3317	struct	sa_softc *softc;
3318	int	error;
3319
3320	softc = (struct sa_softc *)periph->softc;
3321
3322	ccb = cam_periph_getccb(periph, 1);
3323
3324	/* It is safe to retry this operation */
3325	scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
3326	    FALSE, FALSE, load, SSD_FULL_SIZE, REWIND_TIMEOUT);
3327
3328	softc->dsreg = (load)? MTIO_DSREG_LD : MTIO_DSREG_UNL;
3329	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3330	softc->dsreg = MTIO_DSREG_REST;
3331	QFRLS(ccb);
3332	xpt_release_ccb(ccb);
3333
3334	if (error || load == 0)
3335		softc->fileno = softc->blkno = (daddr_t) -1;
3336	else if (error == 0)
3337		softc->fileno = softc->blkno = (daddr_t) 0;
3338	return (error);
3339}
3340
3341static int
3342saerase(struct cam_periph *periph, int longerase)
3343{
3344
3345	union	ccb *ccb;
3346	struct	sa_softc *softc;
3347	int error;
3348
3349	softc = (struct sa_softc *)periph->softc;
3350
3351	ccb = cam_periph_getccb(periph, 1);
3352
3353	scsi_erase(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, FALSE, longerase,
3354	    SSD_FULL_SIZE, ERASE_TIMEOUT);
3355
3356	softc->dsreg = MTIO_DSREG_ZER;
3357	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3358	softc->dsreg = MTIO_DSREG_REST;
3359
3360	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3361		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
3362	xpt_release_ccb(ccb);
3363	return (error);
3364}
3365
3366#endif /* _KERNEL */
3367
3368/*
3369 * Read tape block limits command.
3370 */
3371void
3372scsi_read_block_limits(struct ccb_scsiio *csio, u_int32_t retries,
3373		   void (*cbfcnp)(struct cam_periph *, union ccb *),
3374		   u_int8_t tag_action,
3375		   struct scsi_read_block_limits_data *rlimit_buf,
3376		   u_int8_t sense_len, u_int32_t timeout)
3377{
3378	struct scsi_read_block_limits *scsi_cmd;
3379
3380	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action,
3381	     (u_int8_t *)rlimit_buf, sizeof(*rlimit_buf), sense_len,
3382	     sizeof(*scsi_cmd), timeout);
3383
3384	scsi_cmd = (struct scsi_read_block_limits *)&csio->cdb_io.cdb_bytes;
3385	bzero(scsi_cmd, sizeof(*scsi_cmd));
3386	scsi_cmd->opcode = READ_BLOCK_LIMITS;
3387}
3388
3389void
3390scsi_sa_read_write(struct ccb_scsiio *csio, u_int32_t retries,
3391		   void (*cbfcnp)(struct cam_periph *, union ccb *),
3392		   u_int8_t tag_action, int readop, int sli,
3393		   int fixed, u_int32_t length, u_int8_t *data_ptr,
3394		   u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout)
3395{
3396	struct scsi_sa_rw *scsi_cmd;
3397
3398	scsi_cmd = (struct scsi_sa_rw *)&csio->cdb_io.cdb_bytes;
3399	scsi_cmd->opcode = readop ? SA_READ : SA_WRITE;
3400	scsi_cmd->sli_fixed = 0;
3401	if (sli && readop)
3402		scsi_cmd->sli_fixed |= SAR_SLI;
3403	if (fixed)
3404		scsi_cmd->sli_fixed |= SARW_FIXED;
3405	scsi_ulto3b(length, scsi_cmd->length);
3406	scsi_cmd->control = 0;
3407
3408	cam_fill_csio(csio, retries, cbfcnp, readop ? CAM_DIR_IN : CAM_DIR_OUT,
3409	    tag_action, data_ptr, dxfer_len, sense_len,
3410	    sizeof(*scsi_cmd), timeout);
3411}
3412
3413void
3414scsi_load_unload(struct ccb_scsiio *csio, u_int32_t retries,
3415		 void (*cbfcnp)(struct cam_periph *, union ccb *),
3416		 u_int8_t tag_action, int immediate, int eot,
3417		 int reten, int load, u_int8_t sense_len,
3418		 u_int32_t timeout)
3419{
3420	struct scsi_load_unload *scsi_cmd;
3421
3422	scsi_cmd = (struct scsi_load_unload *)&csio->cdb_io.cdb_bytes;
3423	bzero(scsi_cmd, sizeof(*scsi_cmd));
3424	scsi_cmd->opcode = LOAD_UNLOAD;
3425	if (immediate)
3426		scsi_cmd->immediate = SLU_IMMED;
3427	if (eot)
3428		scsi_cmd->eot_reten_load |= SLU_EOT;
3429	if (reten)
3430		scsi_cmd->eot_reten_load |= SLU_RETEN;
3431	if (load)
3432		scsi_cmd->eot_reten_load |= SLU_LOAD;
3433
3434	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action,
3435	    NULL, 0, sense_len, sizeof(*scsi_cmd), timeout);
3436}
3437
3438void
3439scsi_rewind(struct ccb_scsiio *csio, u_int32_t retries,
3440	    void (*cbfcnp)(struct cam_periph *, union ccb *),
3441	    u_int8_t tag_action, int immediate, u_int8_t sense_len,
3442	    u_int32_t timeout)
3443{
3444	struct scsi_rewind *scsi_cmd;
3445
3446	scsi_cmd = (struct scsi_rewind *)&csio->cdb_io.cdb_bytes;
3447	bzero(scsi_cmd, sizeof(*scsi_cmd));
3448	scsi_cmd->opcode = REWIND;
3449	if (immediate)
3450		scsi_cmd->immediate = SREW_IMMED;
3451
3452	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3453	    0, sense_len, sizeof(*scsi_cmd), timeout);
3454}
3455
3456void
3457scsi_space(struct ccb_scsiio *csio, u_int32_t retries,
3458	   void (*cbfcnp)(struct cam_periph *, union ccb *),
3459	   u_int8_t tag_action, scsi_space_code code,
3460	   u_int32_t count, u_int8_t sense_len, u_int32_t timeout)
3461{
3462	struct scsi_space *scsi_cmd;
3463
3464	scsi_cmd = (struct scsi_space *)&csio->cdb_io.cdb_bytes;
3465	scsi_cmd->opcode = SPACE;
3466	scsi_cmd->code = code;
3467	scsi_ulto3b(count, scsi_cmd->count);
3468	scsi_cmd->control = 0;
3469
3470	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3471	    0, sense_len, sizeof(*scsi_cmd), timeout);
3472}
3473
3474void
3475scsi_write_filemarks(struct ccb_scsiio *csio, u_int32_t retries,
3476		     void (*cbfcnp)(struct cam_periph *, union ccb *),
3477		     u_int8_t tag_action, int immediate, int setmark,
3478		     u_int32_t num_marks, u_int8_t sense_len,
3479		     u_int32_t timeout)
3480{
3481	struct scsi_write_filemarks *scsi_cmd;
3482
3483	scsi_cmd = (struct scsi_write_filemarks *)&csio->cdb_io.cdb_bytes;
3484	bzero(scsi_cmd, sizeof(*scsi_cmd));
3485	scsi_cmd->opcode = WRITE_FILEMARKS;
3486	if (immediate)
3487		scsi_cmd->byte2 |= SWFMRK_IMMED;
3488	if (setmark)
3489		scsi_cmd->byte2 |= SWFMRK_WSMK;
3490
3491	scsi_ulto3b(num_marks, scsi_cmd->num_marks);
3492
3493	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3494	    0, sense_len, sizeof(*scsi_cmd), timeout);
3495}
3496
3497/*
3498 * The reserve and release unit commands differ only by their opcodes.
3499 */
3500void
3501scsi_reserve_release_unit(struct ccb_scsiio *csio, u_int32_t retries,
3502			  void (*cbfcnp)(struct cam_periph *, union ccb *),
3503			  u_int8_t tag_action, int third_party,
3504			  int third_party_id, u_int8_t sense_len,
3505			  u_int32_t timeout, int reserve)
3506{
3507	struct scsi_reserve_release_unit *scsi_cmd;
3508
3509	scsi_cmd = (struct scsi_reserve_release_unit *)&csio->cdb_io.cdb_bytes;
3510	bzero(scsi_cmd, sizeof(*scsi_cmd));
3511
3512	if (reserve)
3513		scsi_cmd->opcode = RESERVE_UNIT;
3514	else
3515		scsi_cmd->opcode = RELEASE_UNIT;
3516
3517	if (third_party) {
3518		scsi_cmd->lun_thirdparty |= SRRU_3RD_PARTY;
3519		scsi_cmd->lun_thirdparty |=
3520			((third_party_id << SRRU_3RD_SHAMT) & SRRU_3RD_MASK);
3521	}
3522
3523	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3524	    0, sense_len, sizeof(*scsi_cmd), timeout);
3525}
3526
3527void
3528scsi_erase(struct ccb_scsiio *csio, u_int32_t retries,
3529	   void (*cbfcnp)(struct cam_periph *, union ccb *),
3530	   u_int8_t tag_action, int immediate, int long_erase,
3531	   u_int8_t sense_len, u_int32_t timeout)
3532{
3533	struct scsi_erase *scsi_cmd;
3534
3535	scsi_cmd = (struct scsi_erase *)&csio->cdb_io.cdb_bytes;
3536	bzero(scsi_cmd, sizeof(*scsi_cmd));
3537
3538	scsi_cmd->opcode = ERASE;
3539
3540	if (immediate)
3541		scsi_cmd->lun_imm_long |= SE_IMMED;
3542
3543	if (long_erase)
3544		scsi_cmd->lun_imm_long |= SE_LONG;
3545
3546	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3547	    0, sense_len, sizeof(*scsi_cmd), timeout);
3548}
3549
3550/*
3551 * Read Tape Position command.
3552 */
3553void
3554scsi_read_position(struct ccb_scsiio *csio, u_int32_t retries,
3555		   void (*cbfcnp)(struct cam_periph *, union ccb *),
3556		   u_int8_t tag_action, int hardsoft,
3557		   struct scsi_tape_position_data *sbp,
3558		   u_int8_t sense_len, u_int32_t timeout)
3559{
3560	struct scsi_tape_read_position *scmd;
3561
3562	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action,
3563	    (u_int8_t *)sbp, sizeof (*sbp), sense_len, sizeof(*scmd), timeout);
3564	scmd = (struct scsi_tape_read_position *)&csio->cdb_io.cdb_bytes;
3565	bzero(scmd, sizeof(*scmd));
3566	scmd->opcode = READ_POSITION;
3567	scmd->byte1 = hardsoft;
3568}
3569
3570/*
3571 * Set Tape Position command.
3572 */
3573void
3574scsi_set_position(struct ccb_scsiio *csio, u_int32_t retries,
3575		   void (*cbfcnp)(struct cam_periph *, union ccb *),
3576		   u_int8_t tag_action, int hardsoft, u_int32_t blkno,
3577		   u_int8_t sense_len, u_int32_t timeout)
3578{
3579	struct scsi_tape_locate *scmd;
3580
3581	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action,
3582	    (u_int8_t *)NULL, 0, sense_len, sizeof(*scmd), timeout);
3583	scmd = (struct scsi_tape_locate *)&csio->cdb_io.cdb_bytes;
3584	bzero(scmd, sizeof(*scmd));
3585	scmd->opcode = LOCATE;
3586	if (hardsoft)
3587		scmd->byte1 |= SA_SPOS_BT;
3588	scsi_ulto4b(blkno, scmd->blkaddr);
3589}
3590