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