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