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