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