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