scsi_sa.c revision 56148
1/*
2 * $FreeBSD: head/sys/cam/scsi/scsi_sa.c 56148 2000-01-17 06:27:37Z mjacob $
3 *
4 * Implementation of SCSI Sequential Access Peripheral driver for CAM.
5 *
6 * Copyright (c) 1997 Justin T. Gibbs
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions, and the following disclaimer,
14 *    without modification, immediately at the beginning of the file.
15 * 2. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 *
31 * Substantial subsequent modifications
32 * Copyright (c) 1999 Matthew Jacob
33 *  NASA Ames Research Center,
34 *  Feral Software
35 */
36
37#include <sys/param.h>
38#include <sys/queue.h>
39#ifdef _KERNEL
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#endif
43#include <sys/types.h>
44#include <sys/buf.h>
45#include <sys/malloc.h>
46#include <sys/mtio.h>
47#include <sys/conf.h>
48#include <sys/buf.h>
49#include <sys/devicestat.h>
50#include <machine/limits.h>
51
52#ifndef _KERNEL
53#include <stdio.h>
54#include <string.h>
55#endif
56
57#include <cam/cam.h>
58#include <cam/cam_ccb.h>
59#include <cam/cam_extend.h>
60#include <cam/cam_periph.h>
61#include <cam/cam_xpt_periph.h>
62#include <cam/cam_debug.h>
63
64#include <cam/scsi/scsi_all.h>
65#include <cam/scsi/scsi_message.h>
66#include <cam/scsi/scsi_sa.h>
67
68#ifdef _KERNEL
69
70#include <opt_sa.h>
71
72#ifndef SA_SPACE_TIMEOUT
73#define SA_SPACE_TIMEOUT	1 * 60
74#endif
75#ifndef SA_REWIND_TIMEOUT
76#define SA_REWIND_TIMEOUT	2 * 60
77#endif
78#ifndef SA_ERASE_TIMEOUT
79#define SA_ERASE_TIMEOUT	4 * 60
80#endif
81
82#define	REWIND_TIMEOUT		(SA_REWIND_TIMEOUT * 60 * 1000)
83#define	ERASE_TIMEOUT		(SA_ERASE_TIMEOUT * 60 * 1000)
84#define	SPACE_TIMEOUT		(SA_SPACE_TIMEOUT * 60 * 1000)
85
86/*
87 * Additional options that can be set for config: SA_1FM_AT_EOT
88 */
89
90#ifndef	UNUSED_PARAMETER
91#define	UNUSED_PARAMETER(x)	x = x
92#endif
93
94#define	QFRLS(ccb)	\
95	if (((ccb)->ccb_h.status & CAM_DEV_QFRZN) != 0)	\
96		cam_release_devq((ccb)->ccb_h.path, 0, 0, 0, FALSE)
97
98/*
99 * Driver states
100 */
101
102
103typedef enum {
104	SA_STATE_NORMAL, SA_STATE_ABNORMAL
105} sa_state;
106
107typedef enum {
108	SA_CCB_BUFFER_IO,
109	SA_CCB_WAITING
110} sa_ccb_types;
111
112#define ccb_type ppriv_field0
113#define ccb_bp	 ppriv_ptr1
114
115typedef enum {
116	SA_FLAG_OPEN		= 0x0001,
117	SA_FLAG_FIXED		= 0x0002,
118	SA_FLAG_TAPE_LOCKED	= 0x0004,
119	SA_FLAG_TAPE_MOUNTED	= 0x0008,
120	SA_FLAG_TAPE_WP		= 0x0010,
121	SA_FLAG_TAPE_WRITTEN	= 0x0020,
122	SA_FLAG_EOM_PENDING	= 0x0040,
123	SA_FLAG_EIO_PENDING	= 0x0080,
124	SA_FLAG_EOF_PENDING	= 0x0100,
125	SA_FLAG_ERR_PENDING	= (SA_FLAG_EOM_PENDING|SA_FLAG_EIO_PENDING|
126				   SA_FLAG_EOF_PENDING),
127	SA_FLAG_INVALID		= 0x0200,
128	SA_FLAG_COMP_ENABLED	= 0x0400,
129	SA_FLAG_COMP_SUPP	= 0x0800,
130	SA_FLAG_COMP_UNSUPP	= 0x1000,
131	SA_FLAG_TAPE_FROZEN	= 0x2000
132} sa_flags;
133
134typedef enum {
135	SA_MODE_REWIND		= 0x00,
136	SA_MODE_NOREWIND	= 0x01,
137	SA_MODE_OFFLINE		= 0x02
138} sa_mode;
139
140typedef enum {
141	SA_PARAM_NONE		= 0x00,
142	SA_PARAM_BLOCKSIZE	= 0x01,
143	SA_PARAM_DENSITY	= 0x02,
144	SA_PARAM_COMPRESSION	= 0x04,
145	SA_PARAM_BUFF_MODE	= 0x08,
146	SA_PARAM_NUMBLOCKS	= 0x10,
147	SA_PARAM_WP		= 0x20,
148	SA_PARAM_SPEED		= 0x40,
149	SA_PARAM_ALL		= 0x7f
150} sa_params;
151
152typedef enum {
153	SA_QUIRK_NONE		= 0x00,
154	SA_QUIRK_NOCOMP		= 0x01,	/* can't deal with compression at all */
155	SA_QUIRK_FIXED		= 0x02,	/* force fixed mode */
156	SA_QUIRK_VARIABLE	= 0x04,	/* force variable mode */
157	SA_QUIRK_2FM		= 0x08,	/* Needs Two File Marks at EOD */
158	SA_QUIRK_1FM		= 0x10	/* No more than 1 File Mark at EOD */
159} sa_quirks;
160
161/* units are bits 4-7, 16-21 (1024 units) */
162#define SAUNIT(DEV) \
163	(((minor(DEV) & 0xF0) >> 4) |  ((minor(DEV) & 0x3f0000) >> 16))
164
165#define SAMODE(z) ((minor(z) & 0x3))
166#define SADENSITY(z) (((minor(z) >> 2) & 0x3))
167#define	SA_IS_CTRL(z) (minor(z) & (1 << 29))
168
169#define SA_NOT_CTLDEV	0
170#define SA_CTLDEV	1
171
172#define SA_ATYPE_R	0
173#define SA_ATYPE_NR	1
174#define SA_ATYPE_ER	2
175
176#define SAMINOR(ctl, unit, mode, access) \
177	((ctl << 29) | ((unit & 0x3f0) << 16) | ((unit & 0xf) << 4) | \
178	(mode << 0x2) | (access & 0x3))
179
180#define SA_NUM_MODES	4
181struct sa_devs {
182	dev_t	ctl_dev;
183	struct sa_mode_devs {
184		dev_t	r_dev;
185		dev_t	nr_dev;
186		dev_t	er_dev;
187	} mode_devs[SA_NUM_MODES];
188	dev_t	r_dev;
189	dev_t	nr_dev;
190	dev_t	er_dev;
191};
192
193struct sa_softc {
194	sa_state	state;
195	sa_flags	flags;
196	sa_quirks	quirks;
197	struct		buf_queue_head buf_queue;
198	int		queue_count;
199	struct		devstat device_stats;
200	struct sa_devs	devs;
201	int		blk_gran;
202	int		blk_mask;
203	int		blk_shift;
204	u_int32_t	max_blk;
205	u_int32_t	min_blk;
206	u_int32_t	comp_algorithm;
207	u_int32_t	saved_comp_algorithm;
208	u_int32_t	media_blksize;
209	u_int32_t	last_media_blksize;
210	u_int32_t	media_numblks;
211	u_int8_t	media_density;
212	u_int8_t	speed;
213	u_int8_t	scsi_rev;
214	u_int8_t	dsreg;		/* mtio mt_dsreg, redux */
215	int		buffer_mode;
216	int		filemarks;
217	union		ccb saved_ccb;
218
219	/*
220	 * Relative to BOT Location.
221	 */
222	daddr_t		fileno;
223	daddr_t		blkno;
224
225	/*
226	 * Latched Error Info
227	 */
228	struct {
229		struct scsi_sense_data _last_io_sense;
230		u_int32_t _last_io_resid;
231		u_int8_t _last_io_cdb[CAM_MAX_CDBLEN];
232		struct scsi_sense_data _last_ctl_sense;
233		u_int32_t _last_ctl_resid;
234		u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN];
235#define	last_io_sense	errinfo._last_io_sense
236#define	last_io_resid	errinfo._last_io_resid
237#define	last_io_cdb	errinfo._last_io_cdb
238#define	last_ctl_sense	errinfo._last_ctl_sense
239#define	last_ctl_resid	errinfo._last_ctl_resid
240#define	last_ctl_cdb	errinfo._last_ctl_cdb
241	} errinfo;
242	/*
243	 * Misc other flags/state
244	 */
245	u_int32_t
246				: 31,
247		ctrl_mode	: 1;	/* control device open */
248};
249
250struct sa_quirk_entry {
251	struct scsi_inquiry_pattern inq_pat;	/* matching pattern */
252	sa_quirks quirks;	/* specific quirk type */
253	u_int32_t prefblk;	/* preferred blocksize when in fixed mode */
254};
255
256static struct sa_quirk_entry sa_quirk_table[] =
257{
258	{
259		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
260		  "Python 25601*", "*"}, SA_QUIRK_NOCOMP, 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_flags & B_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_flags & B_READ) == 0)
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_flags & B_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_flags & B_READ) != 0,
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_flags & B_READ) == 0) {
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		scsi_sa_read_write(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, 1,
1832		    FALSE, 0, 8192, (void *) rblim, 8192, SSD_FULL_SIZE,
1833		    120 * 60 * 1000);
1834		(void) cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
1835		    &softc->device_stats);
1836		QFRLS(ccb);
1837		scsi_rewind(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
1838		    FALSE, SSD_FULL_SIZE, REWIND_TIMEOUT);
1839		error = cam_periph_runccb(ccb, saerror, 0,
1840		    SF_NO_PRINT | SF_RETRY_SELTO | SF_RETRY_UA,
1841		    &softc->device_stats);
1842		QFRLS(ccb);
1843		if (error) {
1844			xpt_print_path(ccb->ccb_h.path);
1845			printf("unable to rewind after test read\n");
1846			xpt_release_ccb(ccb);
1847			goto exit;
1848		}
1849
1850		/*
1851		 * Next off, determine block limits.
1852		 */
1853		scsi_read_block_limits(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG,
1854		    rblim, SSD_FULL_SIZE, 5000);
1855
1856		error = cam_periph_runccb(ccb, saerror, 0,
1857		    SF_NO_PRINT | SF_RETRY_UA | SF_RETRY_SELTO,
1858		    &softc->device_stats);
1859		QFRLS(ccb);
1860		xpt_release_ccb(ccb);
1861
1862		if (error != 0) {
1863			/*
1864			 * If it's less than SCSI-2, READ BLOCK LIMITS is not
1865			 * a MANDATORY command. Anyway- it doesn't matter-
1866			 * we can proceed anyway.
1867			 */
1868			softc->blk_gran = 0;
1869			softc->max_blk = ~0;
1870			softc->min_blk = 0;
1871		} else {
1872			if (softc->scsi_rev >= SCSI_REV_3) {
1873				softc->blk_gran = RBL_GRAN(rblim);
1874			} else {
1875				softc->blk_gran = 0;
1876			}
1877			/*
1878			 * We take max_blk == min_blk to mean a default to
1879			 * fixed mode- but note that whatever we get out of
1880			 * sagetparams below will actually determine whether
1881			 * we are actually *in* fixed mode.
1882			 */
1883			softc->max_blk = scsi_3btoul(rblim->maximum);
1884			softc->min_blk = scsi_2btoul(rblim->minimum);
1885
1886
1887		}
1888		/*
1889		 * Next, perform a mode sense to determine
1890		 * current density, blocksize, compression etc.
1891		 */
1892		error = sagetparams(periph, SA_PARAM_ALL,
1893				    &softc->media_blksize,
1894				    &softc->media_density,
1895				    &softc->media_numblks,
1896				    &softc->buffer_mode, &write_protect,
1897				    &softc->speed, &comp_supported,
1898				    &comp_enabled, &softc->comp_algorithm,
1899				    NULL);
1900
1901		if (error != 0) {
1902			/*
1903			 * We could work a little harder here. We could
1904			 * adjust our attempts to get information. It
1905			 * might be an ancient tape drive. If someone
1906			 * nudges us, we'll do that.
1907			 */
1908			goto exit;
1909		}
1910
1911		/*
1912		 * If no quirk has determined that this is a device that is
1913		 * preferred to be in fixed or variable mode, now is the time
1914		 * to find out.
1915	 	 */
1916		if ((softc->quirks & (SA_QUIRK_FIXED|SA_QUIRK_VARIABLE)) == 0) {
1917			guessing = 1;
1918			/*
1919			 * This could be expensive to find out. Luckily we
1920			 * only need to do this once. If we start out in
1921			 * 'default' mode, try and set ourselves to one
1922			 * of the densities that would determine a wad
1923			 * of other stuff. Go from highest to lowest.
1924			 */
1925			if (softc->media_density == SCSI_DEFAULT_DENSITY) {
1926				int i;
1927				static u_int8_t ctry[] = {
1928					SCSI_DENSITY_HALFINCH_PE,
1929					SCSI_DENSITY_HALFINCH_6250C,
1930					SCSI_DENSITY_HALFINCH_6250,
1931					SCSI_DENSITY_HALFINCH_1600,
1932					SCSI_DENSITY_HALFINCH_800,
1933					SCSI_DENSITY_QIC_4GB,
1934					SCSI_DENSITY_QIC_2GB,
1935					SCSI_DENSITY_QIC_525_320,
1936					SCSI_DENSITY_QIC_150,
1937					SCSI_DENSITY_QIC_120,
1938					SCSI_DENSITY_QIC_24,
1939					SCSI_DENSITY_QIC_11_9TRK,
1940					SCSI_DENSITY_QIC_11_4TRK,
1941					SCSI_DENSITY_QIC_1320,
1942					SCSI_DENSITY_QIC_3080,
1943					0
1944				};
1945				for (i = 0; ctry[i]; i++) {
1946					error = sasetparams(periph,
1947					    SA_PARAM_DENSITY, 0, ctry[i],
1948					    0, SF_NO_PRINT);
1949					if (error == 0) {
1950						softc->media_density = ctry[i];
1951						break;
1952					}
1953				}
1954			}
1955			switch (softc->media_density) {
1956			case SCSI_DENSITY_QIC_11_4TRK:
1957			case SCSI_DENSITY_QIC_11_9TRK:
1958			case SCSI_DENSITY_QIC_24:
1959			case SCSI_DENSITY_QIC_120:
1960			case SCSI_DENSITY_QIC_150:
1961			case SCSI_DENSITY_QIC_1320:
1962			case SCSI_DENSITY_QIC_3080:
1963				softc->quirks &= ~SA_QUIRK_2FM;
1964				softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM;
1965				softc->last_media_blksize = 512;
1966				break;
1967			case SCSI_DENSITY_QIC_4GB:
1968			case SCSI_DENSITY_QIC_2GB:
1969			case SCSI_DENSITY_QIC_525_320:
1970				softc->quirks &= ~SA_QUIRK_2FM;
1971				softc->quirks |= SA_QUIRK_FIXED|SA_QUIRK_1FM;
1972				softc->last_media_blksize = 1024;
1973				break;
1974			default:
1975				softc->last_media_blksize =
1976				    softc->media_blksize;
1977				softc->quirks |= SA_QUIRK_VARIABLE;
1978				break;
1979			}
1980		}
1981
1982		/*
1983		 * If no quirk has determined that this is a device that needs
1984		 * to have 2 Filemarks at EOD, now is the time to find out.
1985		 */
1986
1987		if ((softc->quirks & SA_QUIRK_2FM) == 0) {
1988			switch (softc->media_density) {
1989			case SCSI_DENSITY_HALFINCH_800:
1990			case SCSI_DENSITY_HALFINCH_1600:
1991			case SCSI_DENSITY_HALFINCH_6250:
1992			case SCSI_DENSITY_HALFINCH_6250C:
1993			case SCSI_DENSITY_HALFINCH_PE:
1994				softc->quirks &= ~SA_QUIRK_1FM;
1995				softc->quirks |= SA_QUIRK_2FM;
1996				break;
1997			default:
1998				break;
1999			}
2000		}
2001
2002		/*
2003		 * Now validate that some info we got makes sense.
2004		 */
2005		if ((softc->max_blk < softc->media_blksize) ||
2006		    (softc->min_blk > softc->media_blksize &&
2007		    softc->media_blksize)) {
2008			xpt_print_path(ccb->ccb_h.path);
2009			printf("BLOCK LIMITS (%d..%d) could not match current "
2010			    "block settings (%d)- adjusting\n", softc->min_blk,
2011			    softc->max_blk, softc->media_blksize);
2012			softc->max_blk = softc->min_blk =
2013			    softc->media_blksize;
2014		}
2015
2016		/*
2017		 * Now put ourselves into the right frame of mind based
2018		 * upon quirks...
2019		 */
2020tryagain:
2021		/*
2022		 * If we want to be in FIXED mode and our current blocksize
2023		 * is not equal to our last blocksize (if nonzero), try and
2024		 * set ourselves to this last blocksize (as the 'preferred'
2025		 * block size).  The initial quirkmatch at registry sets the
2026		 * initial 'last' blocksize. If, for whatever reason, this
2027		 * 'last' blocksize is zero, set the blocksize to 512,
2028		 * or min_blk if that's larger.
2029		 */
2030		if ((softc->quirks & SA_QUIRK_FIXED) &&
2031		    (softc->media_blksize != softc->last_media_blksize)) {
2032			softc->media_blksize = softc->last_media_blksize;
2033			if (softc->media_blksize == 0) {
2034				softc->media_blksize = 512;
2035				if (softc->media_blksize < softc->min_blk) {
2036					softc->media_blksize = softc->min_blk;
2037				}
2038			}
2039			error = sasetparams(periph, SA_PARAM_BLOCKSIZE,
2040			    softc->media_blksize, 0, 0, SF_NO_PRINT);
2041			if (error) {
2042				xpt_print_path(ccb->ccb_h.path);
2043				printf("unable to set fixed blocksize to %d\n",
2044				     softc->media_blksize);
2045				goto exit;
2046			}
2047		}
2048
2049		if ((softc->quirks & SA_QUIRK_VARIABLE) &&
2050		    (softc->media_blksize != 0)) {
2051			softc->last_media_blksize = softc->media_blksize;
2052			softc->media_blksize = 0;
2053			error = sasetparams(periph, SA_PARAM_BLOCKSIZE,
2054			    0, 0, 0, SF_NO_PRINT);
2055			if (error) {
2056				/*
2057				 * If this fails and we were guessing, just
2058				 * assume that we got it wrong and go try
2059				 * fixed block mode. Don't even check against
2060				 * density code at this point.
2061				 */
2062				if (guessing) {
2063					softc->quirks &= ~SA_QUIRK_VARIABLE;
2064					softc->quirks |= SA_QUIRK_FIXED;
2065					if (softc->last_media_blksize == 0)
2066						softc->last_media_blksize = 512;
2067					goto tryagain;
2068				}
2069				xpt_print_path(ccb->ccb_h.path);
2070				printf("unable to set variable blocksize\n");
2071				goto exit;
2072			}
2073		}
2074
2075		/*
2076		 * Now that we have the current block size,
2077		 * set up some parameters for sastart's usage.
2078		 */
2079		if (softc->media_blksize) {
2080			softc->flags |= SA_FLAG_FIXED;
2081			if (powerof2(softc->media_blksize)) {
2082				softc->blk_shift =
2083				    ffs(softc->media_blksize) - 1;
2084				softc->blk_mask = softc->media_blksize - 1;
2085			} else {
2086				softc->blk_mask = ~0;
2087				softc->blk_shift = 0;
2088			}
2089		} else {
2090			/*
2091			 * The SCSI-3 spec allows 0 to mean "unspecified".
2092			 * The SCSI-1 spec allows 0 to mean 'infinite'.
2093			 *
2094			 * Either works here.
2095			 */
2096			if (softc->max_blk == 0) {
2097				softc->max_blk = ~0;
2098			}
2099			softc->blk_shift = 0;
2100			if (softc->blk_gran != 0) {
2101				softc->blk_mask = softc->blk_gran - 1;
2102			} else {
2103				softc->blk_mask = 0;
2104			}
2105		}
2106
2107		if (write_protect)
2108			softc->flags |= SA_FLAG_TAPE_WP;
2109
2110		if (comp_supported) {
2111			if (softc->saved_comp_algorithm == 0)
2112				softc->saved_comp_algorithm =
2113				    softc->comp_algorithm;
2114			softc->flags |= SA_FLAG_COMP_SUPP;
2115			if (comp_enabled)
2116				softc->flags |= SA_FLAG_COMP_ENABLED;
2117		} else
2118			softc->flags |= SA_FLAG_COMP_UNSUPP;
2119
2120		if (softc->buffer_mode == SMH_SA_BUF_MODE_NOBUF) {
2121			error = sasetparams(periph, SA_PARAM_BUFF_MODE, 0,
2122			    0, 0, SF_NO_PRINT);
2123			if (error == 0)
2124				softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF;
2125		}
2126
2127
2128		if (error == 0) {
2129			softc->flags |= SA_FLAG_TAPE_MOUNTED;
2130		}
2131exit:
2132		if (rblim != NULL)
2133			free(rblim, M_TEMP);
2134
2135		if (error != 0) {
2136			softc->dsreg = MTIO_DSREG_NIL;
2137		} else {
2138			softc->fileno = softc->blkno = 0;
2139			softc->dsreg = MTIO_DSREG_REST;
2140		}
2141#ifdef	SA_1FM_AT_EOD
2142		if ((softc->quirks & SA_QUIRK_2FM) == 0)
2143			softc->quirks |= SA_QUIRK_1FM;
2144#else
2145		if ((softc->quirks & SA_QUIRK_1FM) == 0)
2146			softc->quirks |= SA_QUIRK_2FM;
2147#endif
2148	} else
2149		xpt_release_ccb(ccb);
2150
2151	/*
2152	 * If we return an error, we're not mounted any more,
2153	 * so release any device reservation.
2154	 */
2155	if (error != 0) {
2156		(void) sareservereleaseunit(periph, FALSE);
2157	}
2158	return (error);
2159}
2160
2161static int
2162sacheckeod(struct cam_periph *periph)
2163{
2164	int	error;
2165	int	markswanted;
2166	struct	sa_softc *softc;
2167
2168	softc = (struct sa_softc *)periph->softc;
2169	markswanted = 0;
2170
2171	if ((softc->flags & SA_FLAG_TAPE_WRITTEN) != 0) {
2172		markswanted++;
2173		if (softc->quirks & SA_QUIRK_2FM)
2174			markswanted++;
2175	}
2176
2177	if (softc->filemarks < markswanted) {
2178		markswanted -= softc->filemarks;
2179		error = sawritefilemarks(periph, markswanted, FALSE);
2180	} else {
2181		error = 0;
2182	}
2183	return (error);
2184}
2185
2186static int
2187saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs)
2188{
2189	static const char *toobig =
2190	    "%d-byte tape record bigger than suplied buffer\n";
2191	struct	cam_periph *periph;
2192	struct	sa_softc *softc;
2193	struct	ccb_scsiio *csio;
2194	struct	scsi_sense_data *sense;
2195	u_int32_t resid = 0;
2196	int32_t	info = 0;
2197	int	error_code, sense_key, asc, ascq;
2198	int	error, defer_action;
2199
2200	periph = xpt_path_periph(ccb->ccb_h.path);
2201	softc = (struct sa_softc *)periph->softc;
2202	csio = &ccb->csio;
2203	sense = &csio->sense_data;
2204	scsi_extract_sense(sense, &error_code, &sense_key, &asc, &ascq);
2205	error = 0;
2206
2207	/*
2208	 * Calculate/latch up, any residuals...
2209	 */
2210	if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) {
2211		if ((sense->error_code & SSD_ERRCODE_VALID) != 0) {
2212			info = (int32_t) scsi_4btoul(sense->info);
2213			resid = info;
2214			if ((softc->flags & SA_FLAG_FIXED) != 0)
2215				resid *= softc->media_blksize;
2216		} else {
2217			resid = csio->dxfer_len;
2218			info = resid;
2219			if ((softc->flags & SA_FLAG_FIXED) != 0) {
2220				if (softc->media_blksize)
2221					info /= softc->media_blksize;
2222			}
2223		}
2224		if (csio->ccb_h.ccb_type == SA_CCB_BUFFER_IO) {
2225			bcopy((caddr_t) sense, (caddr_t) &softc->last_io_sense,
2226			    sizeof (struct scsi_sense_data));
2227			bcopy(csio->cdb_io.cdb_bytes, softc->last_io_cdb,
2228			    (int) csio->cdb_len);
2229			softc->last_io_resid = resid;
2230		} else {
2231			bcopy((caddr_t) sense, (caddr_t) &softc->last_ctl_sense,
2232			    sizeof (struct scsi_sense_data));
2233			bcopy(csio->cdb_io.cdb_bytes, softc->last_ctl_cdb,
2234			    (int) csio->cdb_len);
2235			softc->last_ctl_resid = resid;
2236		}
2237		CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Key 0x%x ASC/ASCQ
2238		    0x%x 0x%x flags 0x%x resid %d dxfer_len %d\n", sense_key,
2239		    asc, ascq, sense->flags & ~SSD_KEY_RESERVED, resid,
2240		    csio->dxfer_len));
2241	} else {
2242		CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("Cam Status 0x%x\n",
2243		    csio->ccb_h.status & CAM_STATUS_MASK));
2244	}
2245
2246	/*
2247	 * If it's neither a SCSI Check Condition Error nor a non-read/write
2248	 * command, let the common code deal with it the error setting.
2249	 */
2250	if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR ||
2251	    (csio->ccb_h.ccb_type == SA_CCB_WAITING)) {
2252		return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb));
2253	}
2254
2255	/*
2256	 * Calculate whether we'll defer action.
2257	 */
2258
2259	if (resid > 0 && resid < csio->dxfer_len &&
2260	    (softc->flags & SA_FLAG_FIXED) != 0) {
2261		defer_action = TRUE;
2262	} else {
2263		defer_action = FALSE;
2264	}
2265
2266	/*
2267	 * Handle filemark, end of tape, mismatched record sizes....
2268	 * From this point out, we're only handling read/write cases.
2269	 * Handle writes && reads differently.
2270	 */
2271
2272	if (csio->cdb_io.cdb_bytes[0] == SA_WRITE) {
2273		if (sense->flags & SSD_FILEMARK) {
2274			xpt_print_path(csio->ccb_h.path);
2275			printf("filemark detected on write?\n");
2276			if (softc->fileno != (daddr_t) -1) {
2277				softc->fileno++;
2278				softc->blkno = 0;
2279			}
2280		}
2281		if (sense->flags & SSD_EOM) {
2282			csio->resid = resid;
2283			if (defer_action) {
2284				error = -1;
2285				softc->flags |= SA_FLAG_EOM_PENDING;
2286			} else {
2287				error = ENOSPC;
2288			}
2289		}
2290	} else {
2291		if (sense_key == SSD_KEY_BLANK_CHECK) {
2292			csio->resid = resid;
2293			if (defer_action) {
2294				error = -1;
2295				softc->flags |= SA_FLAG_EOM_PENDING;
2296			} else {
2297				error = EIO;
2298			}
2299		}
2300		if (sense->flags & SSD_FILEMARK) {
2301			csio->resid = resid;
2302			if (defer_action) {
2303				error = -1;
2304				softc->flags |= SA_FLAG_EOF_PENDING;
2305			}
2306			/*
2307			 * Unconditionally, if we detected a filemark on a read,
2308			 * mark that we've run moved a file ahead.
2309			 */
2310			if (softc->fileno != (daddr_t) -1) {
2311				softc->fileno++;
2312				softc->blkno = 0;
2313			}
2314		}
2315	}
2316	/*
2317	 * Incorrect Length usually applies to read, but can apply to writes.
2318	 */
2319	if (error == 0 && (sense->flags & SSD_ILI)) {
2320		if (info < 0) {
2321			xpt_print_path(csio->ccb_h.path);
2322			printf(toobig, csio->dxfer_len - info);
2323			csio->resid = csio->dxfer_len;
2324			error = EIO;
2325		} else {
2326			csio->resid = resid;
2327			if ((softc->flags & SA_FLAG_FIXED) != 0) {
2328				if (defer_action)
2329					softc->flags |= SA_FLAG_EIO_PENDING;
2330				else
2331					error = EIO;
2332			}
2333			/*
2334			 * Bump the block number if we hadn't seen a filemark.
2335			 * Do this independent of errors (we've moved anyway).
2336			 */
2337			if ((sense->flags & SSD_FILEMARK) == 0) {
2338				if (softc->blkno != (daddr_t) -1) {
2339					softc->blkno++;
2340				}
2341			}
2342		}
2343	}
2344	if (error == 0)
2345		return (cam_periph_error(ccb, cflgs, sflgs, &softc->saved_ccb));
2346
2347	if (error == -1)
2348		return (0);
2349	else
2350		return (error);
2351}
2352
2353static int
2354sagetparams(struct cam_periph *periph, sa_params params_to_get,
2355	    u_int32_t *blocksize, u_int8_t *density, u_int32_t *numblocks,
2356	    int *buff_mode, u_int8_t *write_protect, u_int8_t *speed,
2357	    int *comp_supported, int *comp_enabled, u_int32_t *comp_algorithm,
2358	    sa_comp_t *tcs)
2359{
2360	union ccb *ccb;
2361	void *mode_buffer;
2362	struct scsi_mode_header_6 *mode_hdr;
2363	struct scsi_mode_blk_desc *mode_blk;
2364	int mode_buffer_len;
2365	struct sa_softc *softc;
2366	u_int8_t cpage;
2367	int error;
2368	cam_status status;
2369
2370	softc = (struct sa_softc *)periph->softc;
2371	ccb = cam_periph_getccb(periph, 1);
2372	cpage = SA_DATA_COMPRESSION_PAGE;
2373
2374retry:
2375	mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk);
2376
2377	if (params_to_get & SA_PARAM_COMPRESSION) {
2378		if (softc->quirks & SA_QUIRK_NOCOMP) {
2379			*comp_supported = FALSE;
2380			params_to_get &= ~SA_PARAM_COMPRESSION;
2381		} else
2382			mode_buffer_len += sizeof (sa_comp_t);
2383	}
2384
2385	mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK);
2386	bzero(mode_buffer, mode_buffer_len);
2387	mode_hdr = (struct scsi_mode_header_6 *)mode_buffer;
2388	mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
2389
2390	/* it is safe to retry this */
2391	scsi_mode_sense(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
2392	    SMS_PAGE_CTRL_CURRENT, (params_to_get & SA_PARAM_COMPRESSION) ?
2393	    cpage : SMS_VENDOR_SPECIFIC_PAGE, mode_buffer, mode_buffer_len,
2394	    SSD_FULL_SIZE, 5000);
2395
2396	error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
2397	    &softc->device_stats);
2398	QFRLS(ccb);
2399
2400	status = ccb->ccb_h.status & CAM_STATUS_MASK;
2401
2402	if (error == EINVAL && (params_to_get & SA_PARAM_COMPRESSION) != 0) {
2403		/*
2404		 * Hmm. Let's see if we can try another page...
2405		 * If we've already done that, give up on compression
2406		 * for this device and remember this for the future
2407		 * and attempt the request without asking for compression
2408		 * info.
2409		 */
2410		if (cpage == SA_DATA_COMPRESSION_PAGE) {
2411			cpage = SA_DEVICE_CONFIGURATION_PAGE;
2412			goto retry;
2413		}
2414		softc->quirks |= SA_QUIRK_NOCOMP;
2415		free(mode_buffer, M_TEMP);
2416		goto retry;
2417	} else if (status == CAM_SCSI_STATUS_ERROR) {
2418		/* Tell the user about the fatal error. */
2419		scsi_sense_print(&ccb->csio);
2420		goto sagetparamsexit;
2421	}
2422
2423	/*
2424	 * If the user only wants the compression information, and
2425	 * the device doesn't send back the block descriptor, it's
2426	 * no big deal.  If the user wants more than just
2427	 * compression, though, and the device doesn't pass back the
2428	 * block descriptor, we need to send another mode sense to
2429	 * get the block descriptor.
2430	 */
2431	if ((mode_hdr->blk_desc_len == 0) &&
2432	    (params_to_get & SA_PARAM_COMPRESSION) &&
2433	    (params_to_get & ~(SA_PARAM_COMPRESSION))) {
2434
2435		/*
2436		 * Decrease the mode buffer length by the size of
2437		 * the compression page, to make sure the data
2438		 * there doesn't get overwritten.
2439		 */
2440		mode_buffer_len -= sizeof (sa_comp_t);
2441
2442		/*
2443		 * Now move the compression page that we presumably
2444		 * got back down the memory chunk a little bit so
2445		 * it doesn't get spammed.
2446		 */
2447		bcopy(&mode_hdr[0], &mode_hdr[1], sizeof (sa_comp_t));
2448		bzero(&mode_hdr[0], sizeof (mode_hdr[0]));
2449
2450		/*
2451		 * Now, we issue another mode sense and just ask
2452		 * for the block descriptor, etc.
2453		 */
2454
2455		scsi_mode_sense(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE,
2456		    SMS_PAGE_CTRL_CURRENT, SMS_VENDOR_SPECIFIC_PAGE,
2457		    mode_buffer, mode_buffer_len, SSD_FULL_SIZE, 5000);
2458
2459		error = cam_periph_runccb(ccb, saerror, 0, SF_NO_PRINT,
2460		    &softc->device_stats);
2461		QFRLS(ccb);
2462
2463		if (error != 0)
2464			goto sagetparamsexit;
2465	}
2466
2467	if (params_to_get & SA_PARAM_BLOCKSIZE)
2468		*blocksize = scsi_3btoul(mode_blk->blklen);
2469
2470	if (params_to_get & SA_PARAM_NUMBLOCKS)
2471		*numblocks = scsi_3btoul(mode_blk->nblocks);
2472
2473	if (params_to_get & SA_PARAM_BUFF_MODE)
2474		*buff_mode = mode_hdr->dev_spec & SMH_SA_BUF_MODE_MASK;
2475
2476	if (params_to_get & SA_PARAM_DENSITY)
2477		*density = mode_blk->density;
2478
2479	if (params_to_get & SA_PARAM_WP)
2480		*write_protect = (mode_hdr->dev_spec & SMH_SA_WP)? TRUE : FALSE;
2481
2482	if (params_to_get & SA_PARAM_SPEED)
2483		*speed = mode_hdr->dev_spec & SMH_SA_SPEED_MASK;
2484
2485	if (params_to_get & SA_PARAM_COMPRESSION) {
2486		sa_comp_t *ntcs = (sa_comp_t *) &mode_blk[1];
2487		if (cpage == SA_DATA_COMPRESSION_PAGE) {
2488			struct scsi_data_compression_page *cp = &ntcs->dcomp;
2489			*comp_supported =
2490			    (cp->dce_and_dcc & SA_DCP_DCC)? TRUE : FALSE;
2491			*comp_enabled =
2492			    (cp->dce_and_dcc & SA_DCP_DCE)? TRUE : FALSE;
2493			*comp_algorithm = scsi_4btoul(cp->comp_algorithm);
2494		} else {
2495			struct scsi_dev_conf_page *cp = &ntcs->dconf;
2496			/*
2497			 * We don't really know whether this device supports
2498			 * Data Compression if the the algorithm field is
2499			 * zero. Just say we do.
2500			 */
2501			*comp_supported = TRUE;
2502			*comp_enabled =
2503			    (cp->sel_comp_alg != SA_COMP_NONE)? TRUE : FALSE;
2504			*comp_algorithm = cp->sel_comp_alg;
2505		}
2506		if (tcs != NULL)
2507			bcopy(ntcs, tcs, sizeof (sa_comp_t));
2508	}
2509
2510	if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
2511		int idx;
2512		char *xyz = mode_buffer;
2513		xpt_print_path(periph->path);
2514		printf("Mode Sense Data=");
2515		for (idx = 0; idx < mode_buffer_len; idx++)
2516			printf(" 0x%02x", xyz[idx] & 0xff);
2517		printf("\n");
2518	}
2519
2520sagetparamsexit:
2521
2522	xpt_release_ccb(ccb);
2523	free(mode_buffer, M_TEMP);
2524	return (error);
2525}
2526
2527/*
2528 * The purpose of this function is to set one of four different parameters
2529 * for a tape drive:
2530 *	- blocksize
2531 *	- density
2532 *	- compression / compression algorithm
2533 *	- buffering mode
2534 *
2535 * The assumption is that this will be called from saioctl(), and therefore
2536 * from a process context.  Thus the waiting malloc calls below.  If that
2537 * assumption ever changes, the malloc calls should be changed to be
2538 * NOWAIT mallocs.
2539 *
2540 * Any or all of the four parameters may be set when this function is
2541 * called.  It should handle setting more than one parameter at once.
2542 */
2543static int
2544sasetparams(struct cam_periph *periph, sa_params params_to_set,
2545	    u_int32_t blocksize, u_int8_t density, u_int32_t calg,
2546	    u_int32_t sense_flags)
2547{
2548	struct sa_softc *softc;
2549	u_int32_t current_blocksize;
2550	u_int32_t current_calg;
2551	u_int8_t current_density;
2552	u_int8_t current_speed;
2553	int comp_enabled, comp_supported;
2554	void *mode_buffer;
2555	int mode_buffer_len;
2556	struct scsi_mode_header_6 *mode_hdr;
2557	struct scsi_mode_blk_desc *mode_blk;
2558	sa_comp_t *ccomp, *cpage;
2559	int buff_mode;
2560	union ccb *ccb = NULL;
2561	int error;
2562
2563	softc = (struct sa_softc *)periph->softc;
2564
2565	ccomp = malloc(sizeof (sa_comp_t), M_TEMP, M_WAITOK);
2566
2567	/*
2568	 * Since it doesn't make sense to set the number of blocks, or
2569	 * write protection, we won't try to get the current value.  We
2570	 * always want to get the blocksize, so we can set it back to the
2571	 * proper value.
2572	 */
2573	error = sagetparams(periph,
2574	    params_to_set | SA_PARAM_BLOCKSIZE | SA_PARAM_SPEED,
2575	    &current_blocksize, &current_density, NULL, &buff_mode, NULL,
2576	    &current_speed, &comp_supported, &comp_enabled,
2577	    &current_calg, ccomp);
2578
2579	if (error != 0) {
2580		free(ccomp, M_TEMP);
2581		return (error);
2582	}
2583
2584	mode_buffer_len = sizeof(*mode_hdr) + sizeof(*mode_blk);
2585	if (params_to_set & SA_PARAM_COMPRESSION)
2586		mode_buffer_len += sizeof (sa_comp_t);
2587
2588	mode_buffer = malloc(mode_buffer_len, M_TEMP, M_WAITOK);
2589	bzero(mode_buffer, mode_buffer_len);
2590
2591	mode_hdr = (struct scsi_mode_header_6 *)mode_buffer;
2592	mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
2593
2594	ccb = cam_periph_getccb(periph, 1);
2595
2596retry:
2597
2598	if (params_to_set & SA_PARAM_COMPRESSION) {
2599		if (mode_blk) {
2600			cpage = (sa_comp_t *)&mode_blk[1];
2601		} else {
2602			cpage = (sa_comp_t *)&mode_hdr[1];
2603		}
2604		bcopy(ccomp, cpage, sizeof (sa_comp_t));
2605		cpage->hdr.pagecode &= ~0x80;
2606	} else
2607		cpage = NULL;
2608
2609	/*
2610	 * If the caller wants us to set the blocksize, use the one they
2611	 * pass in.  Otherwise, use the blocksize we got back from the
2612	 * mode select above.
2613	 */
2614	if (mode_blk) {
2615		if (params_to_set & SA_PARAM_BLOCKSIZE)
2616			scsi_ulto3b(blocksize, mode_blk->blklen);
2617		else
2618			scsi_ulto3b(current_blocksize, mode_blk->blklen);
2619
2620		/*
2621		 * Set density if requested, else preserve old density.
2622		 * SCSI_SAME_DENSITY only applies to SCSI-2 or better
2623		 * devices, else density we've latched up in our softc.
2624		 */
2625		if (params_to_set & SA_PARAM_DENSITY) {
2626			mode_blk->density = density;
2627		} else if (softc->scsi_rev > SCSI_REV_CCS) {
2628			mode_blk->density = SCSI_SAME_DENSITY;
2629		} else {
2630			mode_blk->density = softc->media_density;
2631		}
2632	}
2633
2634	/*
2635	 * For mode selects, these two fields must be zero.
2636	 */
2637	mode_hdr->data_length = 0;
2638	mode_hdr->medium_type = 0;
2639
2640	/* set the speed to the current value */
2641	mode_hdr->dev_spec = current_speed;
2642
2643	/* set single-initiator buffering mode */
2644	mode_hdr->dev_spec |= SMH_SA_BUF_MODE_SIBUF;
2645
2646	if (mode_blk)
2647		mode_hdr->blk_desc_len = sizeof(struct scsi_mode_blk_desc);
2648	else
2649		mode_hdr->blk_desc_len = 0;
2650
2651	/*
2652	 * First, if the user wants us to set the compression algorithm or
2653	 * just turn compression on, check to make sure that this drive
2654	 * supports compression.
2655	 */
2656	if (params_to_set & SA_PARAM_COMPRESSION) {
2657		/*
2658		 * If the compression algorithm is 0, disable compression.
2659		 * If the compression algorithm is non-zero, enable
2660		 * compression and set the compression type to the
2661		 * specified compression algorithm, unless the algorithm is
2662		 * MT_COMP_ENABLE.  In that case, we look at the
2663		 * compression algorithm that is currently set and if it is
2664		 * non-zero, we leave it as-is.  If it is zero, and we have
2665		 * saved a compression algorithm from a time when
2666		 * compression was enabled before, set the compression to
2667		 * the saved value.
2668		 */
2669		switch (ccomp->hdr.pagecode & ~0x80) {
2670		case SA_DATA_COMPRESSION_PAGE:
2671		if (ccomp->dcomp.dce_and_dcc & SA_DCP_DCC) {
2672			struct scsi_data_compression_page *dcp = &cpage->dcomp;
2673			if (calg == 0) {
2674				/*
2675				 * Disable compression, but leave the
2676				 * decompression and the capability bit
2677				 * alone.
2678				 */
2679				dcp->dce_and_dcc = SA_DCP_DCC;
2680				dcp->dde_and_red |= SA_DCP_DDE;
2681				break;
2682			}
2683			/* enable compression && decompression */
2684			dcp->dce_and_dcc = SA_DCP_DCE | SA_DCP_DCC;
2685			dcp->dde_and_red |= SA_DCP_DDE;
2686			/*
2687			 * If there, use compression algorithm from caller.
2688			 * Otherwise, if there's a saved compression algorithm
2689			 * and there is no current algorithm, use the saved
2690			 * algorithm. Else parrot back what we got and hope
2691			 * for the best.
2692			 */
2693			if (calg != MT_COMP_ENABLE) {
2694				scsi_ulto4b(calg, dcp->comp_algorithm);
2695				scsi_ulto4b(calg, dcp->decomp_algorithm);
2696			} else if (scsi_4btoul(dcp->comp_algorithm) == 0 &&
2697			    softc->saved_comp_algorithm != 0) {
2698				scsi_ulto4b(softc->saved_comp_algorithm,
2699				    dcp->comp_algorithm);
2700				scsi_ulto4b(softc->saved_comp_algorithm,
2701				    dcp->decomp_algorithm);
2702			}
2703			break;
2704		}
2705		case SA_DEVICE_CONFIGURATION_PAGE:
2706		{
2707			struct scsi_dev_conf_page *dcp = &cpage->dconf;
2708			if (calg == 0) {
2709				dcp->sel_comp_alg = SA_COMP_NONE;
2710				break;
2711			}
2712			if (calg != MT_COMP_ENABLE) {
2713				dcp->sel_comp_alg = calg;
2714			} else if (dcp->sel_comp_alg == SA_COMP_NONE &&
2715			    softc->saved_comp_algorithm != 0) {
2716				dcp->sel_comp_alg = softc->saved_comp_algorithm;
2717			}
2718			break;
2719		}
2720		default:
2721			/*
2722			 * The drive doesn't seem to support compression,
2723			 * so turn off the set compression bit.
2724			 */
2725			params_to_set &= ~SA_PARAM_COMPRESSION;
2726			xpt_print_path(periph->path);
2727			printf("device does not seem to support compression\n");
2728
2729			/*
2730			 * If that was the only thing the user wanted us to set,
2731			 * clean up allocated resources and return with
2732			 * 'operation not supported'.
2733			 */
2734			if (params_to_set == SA_PARAM_NONE) {
2735				free(mode_buffer, M_TEMP);
2736				xpt_release_ccb(ccb);
2737				return (ENODEV);
2738			}
2739
2740			/*
2741			 * That wasn't the only thing the user wanted us to set.
2742			 * So, decrease the stated mode buffer length by the
2743			 * size of the compression mode page.
2744			 */
2745			mode_buffer_len -= sizeof(sa_comp_t);
2746		}
2747	}
2748
2749	/* It is safe to retry this operation */
2750	scsi_mode_select(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG,
2751	    (params_to_set & SA_PARAM_COMPRESSION)? TRUE : FALSE,
2752	    FALSE, mode_buffer, mode_buffer_len, SSD_FULL_SIZE, 5000);
2753
2754	error = cam_periph_runccb(ccb, saerror, 0,
2755	    sense_flags, &softc->device_stats);
2756	QFRLS(ccb);
2757
2758	if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) {
2759		int idx;
2760		char *xyz = mode_buffer;
2761		xpt_print_path(periph->path);
2762		printf("Err%d, Mode Select Data=", error);
2763		for (idx = 0; idx < mode_buffer_len; idx++)
2764			printf(" 0x%02x", xyz[idx] & 0xff);
2765		printf("\n");
2766	}
2767
2768
2769	if (error) {
2770		/*
2771		 * If we can, try without setting density/blocksize.
2772		 */
2773		if (mode_blk) {
2774			if ((params_to_set &
2775			    (SA_PARAM_DENSITY|SA_PARAM_BLOCKSIZE)) == 0) {
2776				mode_blk = NULL;
2777				goto retry;
2778			}
2779		} else {
2780			mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1];
2781			cpage = (sa_comp_t *)&mode_blk[1];
2782		}
2783
2784		/*
2785		 * If we were setting the blocksize, and that failed, we
2786		 * want to set it to its original value.  If we weren't
2787		 * setting the blocksize, we don't want to change it.
2788		 */
2789		scsi_ulto3b(current_blocksize, mode_blk->blklen);
2790
2791		/*
2792		 * Set density if requested, else preserve old density.
2793		 * SCSI_SAME_DENSITY only applies to SCSI-2 or better
2794		 * devices, else density we've latched up in our softc.
2795		 */
2796		if (params_to_set & SA_PARAM_DENSITY) {
2797			mode_blk->density = current_density;
2798		} else if (softc->scsi_rev > SCSI_REV_CCS) {
2799			mode_blk->density = SCSI_SAME_DENSITY;
2800		} else {
2801			mode_blk->density = softc->media_density;
2802		}
2803
2804		if (params_to_set & SA_PARAM_COMPRESSION)
2805			bcopy(ccomp, cpage, sizeof (sa_comp_t));
2806
2807		/*
2808		 * The retry count is the only CCB field that might have been
2809		 * changed that we care about, so reset it back to 1.
2810		 */
2811		ccb->ccb_h.retry_count = 1;
2812		cam_periph_runccb(ccb, saerror, 0, sense_flags,
2813		    &softc->device_stats);
2814		QFRLS(ccb);
2815	}
2816
2817	xpt_release_ccb(ccb);
2818
2819	if (ccomp != NULL)
2820		free(ccomp, M_TEMP);
2821
2822	if (params_to_set & SA_PARAM_COMPRESSION) {
2823		if (error) {
2824			softc->flags &= ~SA_FLAG_COMP_ENABLED;
2825			/*
2826			 * Even if we get an error setting compression,
2827			 * do not say that we don't support it. We could
2828			 * have been wrong, or it may be media specific.
2829			 *	softc->flags &= ~SA_FLAG_COMP_SUPP;
2830			 */
2831			softc->saved_comp_algorithm = softc->comp_algorithm;
2832			softc->comp_algorithm = 0;
2833		} else {
2834			softc->flags |= SA_FLAG_COMP_ENABLED;
2835			softc->comp_algorithm = calg;
2836		}
2837	}
2838
2839	free(mode_buffer, M_TEMP);
2840	return (error);
2841}
2842
2843static void
2844saprevent(struct cam_periph *periph, int action)
2845{
2846	struct	sa_softc *softc;
2847	union	ccb *ccb;
2848	int	error, sf;
2849
2850	softc = (struct sa_softc *)periph->softc;
2851
2852	if ((action == PR_ALLOW) && (softc->flags & SA_FLAG_TAPE_LOCKED) == 0)
2853		return;
2854	if ((action == PR_PREVENT) && (softc->flags & SA_FLAG_TAPE_LOCKED) != 0)
2855		return;
2856
2857	if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO))
2858		sf = 0;
2859	else
2860		sf = SF_QUIET_IR;
2861
2862	ccb = cam_periph_getccb(periph, 1);
2863
2864	/* It is safe to retry this operation */
2865	scsi_prevent(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, action,
2866	    SSD_FULL_SIZE, 100000);
2867
2868	/*
2869	 * We can be quiet about illegal requests.
2870	 */
2871	error = cam_periph_runccb(ccb, saerror, 0, sf, &softc->device_stats);
2872	QFRLS(ccb);
2873	if (error == 0) {
2874		if (action == PR_ALLOW)
2875			softc->flags &= ~SA_FLAG_TAPE_LOCKED;
2876		else
2877			softc->flags |= SA_FLAG_TAPE_LOCKED;
2878	}
2879
2880	xpt_release_ccb(ccb);
2881}
2882
2883static int
2884sarewind(struct cam_periph *periph)
2885{
2886	union	ccb *ccb;
2887	struct	sa_softc *softc;
2888	int	error;
2889
2890	softc = (struct sa_softc *)periph->softc;
2891
2892	ccb = cam_periph_getccb(periph, 1);
2893
2894	/* It is safe to retry this operation */
2895	scsi_rewind(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG, FALSE,
2896	    SSD_FULL_SIZE, REWIND_TIMEOUT);
2897
2898	softc->dsreg = MTIO_DSREG_REW;
2899	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
2900	softc->dsreg = MTIO_DSREG_REST;
2901
2902	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
2903		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
2904
2905	xpt_release_ccb(ccb);
2906	if (error == 0)
2907		softc->fileno = softc->blkno = (daddr_t) 0;
2908	else
2909		softc->fileno = softc->blkno = (daddr_t) -1;
2910	return (error);
2911}
2912
2913static int
2914saspace(struct cam_periph *periph, int count, scsi_space_code code)
2915{
2916	union	ccb *ccb;
2917	struct	sa_softc *softc;
2918	int	error;
2919
2920	softc = (struct sa_softc *)periph->softc;
2921
2922	ccb = cam_periph_getccb(periph, 1);
2923
2924	/* This cannot be retried */
2925
2926	scsi_space(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG, code, count,
2927	    SSD_FULL_SIZE, SPACE_TIMEOUT);
2928
2929	softc->dsreg = (count < 0)? MTIO_DSREG_REV : MTIO_DSREG_FWD;
2930	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
2931	softc->dsreg = MTIO_DSREG_REST;
2932
2933	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
2934		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
2935
2936	xpt_release_ccb(ccb);
2937
2938	/*
2939	 * If a spacing operation has failed, we need to invalidate
2940	 * this mount.
2941	 *
2942	 * If the spacing operation was setmarks or to end of recorded data,
2943	 * we no longer know our relative position.
2944	 *
2945	 * We are not managing residuals here (really).
2946	 */
2947	if (error) {
2948		softc->fileno = softc->blkno = (daddr_t) -1;
2949	} else if (code == SS_SETMARKS || code == SS_EOD) {
2950		softc->fileno = softc->blkno = (daddr_t) -1;
2951	} else if (code == SS_FILEMARKS && softc->fileno != (daddr_t) -1) {
2952		softc->fileno += count;
2953		softc->blkno = 0;
2954	} else if (code == SS_BLOCKS && softc->blkno != (daddr_t) -1) {
2955		softc->blkno += count;
2956	}
2957	return (error);
2958}
2959
2960static int
2961sawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks)
2962{
2963	union	ccb *ccb;
2964	struct	sa_softc *softc;
2965	int	error;
2966
2967	softc = (struct sa_softc *)periph->softc;
2968
2969	ccb = cam_periph_getccb(periph, 1);
2970
2971	softc->dsreg = MTIO_DSREG_FMK;
2972	/* this *must* not be retried */
2973	scsi_write_filemarks(&ccb->csio, 0, sadone, MSG_SIMPLE_Q_TAG,
2974	    FALSE, setmarks, nmarks, SSD_FULL_SIZE, 60000);
2975	softc->dsreg = MTIO_DSREG_REST;
2976
2977
2978	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
2979
2980	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
2981		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
2982
2983	/*
2984	 * XXXX: Get back the actual number of filemarks written
2985	 * XXXX: (there can be a residual).
2986	 */
2987	if (error == 0 && nmarks) {
2988		struct sa_softc *softc = (struct sa_softc *)periph->softc;
2989		softc->filemarks += nmarks;
2990	}
2991	xpt_release_ccb(ccb);
2992
2993	/*
2994	 * Update relative positions (if we're doing that).
2995	 */
2996	if (error) {
2997		softc->fileno = softc->blkno = (daddr_t) -1;
2998	} else if (softc->fileno != (daddr_t) -1) {
2999		softc->fileno += nmarks;
3000		softc->blkno = 0;
3001	}
3002	return (error);
3003}
3004
3005static int
3006sardpos(struct cam_periph *periph, int hard, u_int32_t *blkptr)
3007{
3008	struct scsi_tape_position_data loc;
3009	union ccb *ccb;
3010	struct sa_softc *softc = (struct sa_softc *)periph->softc;
3011	int error;
3012
3013	/*
3014	 * We have to try and flush any buffered writes here if we were writing.
3015	 *
3016	 * The SCSI specification is vague enough about situations like
3017	 * different sized blocks in a tape drive buffer as to make one
3018	 * wary about trying to figure out the actual block location value
3019	 * if data is in the tape drive buffer.
3020	 */
3021	ccb = cam_periph_getccb(periph, 1);
3022
3023	if (softc->flags & SA_FLAG_TAPE_WRITTEN) {
3024		error = sawritefilemarks(periph, 0, 0);
3025		if (error && error != EACCES)
3026			return (error);
3027	}
3028
3029	scsi_read_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
3030	    hard, &loc, SSD_FULL_SIZE, 5000);
3031	softc->dsreg = MTIO_DSREG_RBSY;
3032	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3033	softc->dsreg = MTIO_DSREG_REST;
3034	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3035		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
3036
3037	if (error == 0) {
3038		if (loc.flags & SA_RPOS_UNCERTAIN) {
3039			error = EINVAL;		/* nothing is certain */
3040		} else {
3041#if	0
3042			u_int32_t firstblk, lastblk, nbufblk, nbufbyte;
3043
3044			firstblk = scsi_4btoul(loc.firstblk);
3045			lastblk = scsi_4btoul(loc.lastblk);
3046			nbufblk = scsi_4btoul(loc.nbufblk);
3047			nbufbyte = scsi_4btoul(loc.nbufbyte);
3048			if (lastblk || nbufblk || nbufbyte) {
3049				xpt_print_path(periph->path);
3050				printf("rdpos firstblk 0x%x lastblk 0x%x bufblk"
3051				    " 0x%x bufbyte 0x%x\n", firstblk, lastblk,
3052				    nbufblk, nbufbyte);
3053			}
3054			*blkptr = firstblk;
3055#else
3056			*blkptr = scsi_4btoul(loc.firstblk);
3057#endif
3058		}
3059	}
3060
3061	xpt_release_ccb(ccb);
3062	return (error);
3063}
3064
3065static int
3066sasetpos(struct cam_periph *periph, int hard, u_int32_t *blkptr)
3067{
3068	union ccb *ccb;
3069	struct sa_softc *softc;
3070	int error;
3071
3072	/*
3073	 * We used to try and flush any buffered writes here.
3074	 * Now we push this onto user applications to either
3075	 * flush the pending writes themselves (via a zero count
3076	 * WRITE FILEMARKS command) or they can trust their tape
3077	 * drive to do this correctly for them.
3078 	 */
3079
3080	softc = (struct sa_softc *)periph->softc;
3081	ccb = cam_periph_getccb(periph, 1);
3082
3083
3084	scsi_set_position(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG,
3085	    hard, *blkptr, SSD_FULL_SIZE, 60 * 60 * 1000);
3086
3087	softc->dsreg = MTIO_DSREG_POS;
3088	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3089	softc->dsreg = MTIO_DSREG_REST;
3090	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3091		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, 0);
3092	xpt_release_ccb(ccb);
3093	/*
3094	 * Note relative file && block number position as now unknown.
3095	 */
3096	softc->fileno = softc->blkno = (daddr_t) -1;
3097	return (error);
3098}
3099
3100static int
3101saretension(struct cam_periph *periph)
3102{
3103	union ccb *ccb;
3104	struct sa_softc *softc;
3105	int error;
3106
3107	softc = (struct sa_softc *)periph->softc;
3108
3109	ccb = cam_periph_getccb(periph, 1);
3110
3111	/* It is safe to retry this operation */
3112	scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
3113	    FALSE, TRUE,  TRUE, SSD_FULL_SIZE, ERASE_TIMEOUT);
3114
3115	softc->dsreg = MTIO_DSREG_TEN;
3116	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3117	softc->dsreg = MTIO_DSREG_REST;
3118
3119	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3120		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
3121	xpt_release_ccb(ccb);
3122	if (error == 0)
3123		softc->fileno = softc->blkno = (daddr_t) 0;
3124	else
3125		softc->fileno = softc->blkno = (daddr_t) -1;
3126	return (error);
3127}
3128
3129static int
3130sareservereleaseunit(struct cam_periph *periph, int reserve)
3131{
3132	union ccb *ccb;
3133	struct sa_softc *softc;
3134	int error;
3135
3136	softc = (struct sa_softc *)periph->softc;
3137	ccb = cam_periph_getccb(periph,  1);
3138
3139	/* It is safe to retry this operation */
3140	scsi_reserve_release_unit(&ccb->csio, 2, sadone, MSG_SIMPLE_Q_TAG,
3141	    FALSE,  0, SSD_FULL_SIZE,  5000, reserve);
3142	softc->dsreg = MTIO_DSREG_RBSY;
3143	error = cam_periph_runccb(ccb, saerror, 0,
3144	    SF_RETRY_UA | SF_NO_PRINT, &softc->device_stats);
3145	softc->dsreg = MTIO_DSREG_REST;
3146	QFRLS(ccb);
3147	xpt_release_ccb(ccb);
3148
3149	/*
3150	 * If the error was Illegal Request, then the device doesn't support
3151	 * RESERVE/RELEASE. This is not an error.
3152	 */
3153	if (error == EINVAL) {
3154		error = 0;
3155	}
3156
3157	return (error);
3158}
3159
3160static int
3161saloadunload(struct cam_periph *periph, int load)
3162{
3163	union	ccb *ccb;
3164	struct	sa_softc *softc;
3165	int	error;
3166
3167	softc = (struct sa_softc *)periph->softc;
3168
3169	ccb = cam_periph_getccb(periph, 1);
3170
3171	/* It is safe to retry this operation */
3172	scsi_load_unload(&ccb->csio, 5, sadone, MSG_SIMPLE_Q_TAG, FALSE,
3173	    FALSE, FALSE, load, SSD_FULL_SIZE, REWIND_TIMEOUT);
3174
3175	softc->dsreg = (load)? MTIO_DSREG_LD : MTIO_DSREG_UNL;
3176	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3177	softc->dsreg = MTIO_DSREG_REST;
3178	QFRLS(ccb);
3179	xpt_release_ccb(ccb);
3180
3181	if (error || load == 0)
3182		softc->fileno = softc->blkno = (daddr_t) -1;
3183	else if (error == 0)
3184		softc->fileno = softc->blkno = (daddr_t) 0;
3185	return (error);
3186}
3187
3188static int
3189saerase(struct cam_periph *periph, int longerase)
3190{
3191
3192	union	ccb *ccb;
3193	struct	sa_softc *softc;
3194	int error;
3195
3196	softc = (struct sa_softc *)periph->softc;
3197
3198	ccb = cam_periph_getccb(periph, 1);
3199
3200	scsi_erase(&ccb->csio, 1, sadone, MSG_SIMPLE_Q_TAG, FALSE, longerase,
3201	    SSD_FULL_SIZE, ERASE_TIMEOUT);
3202
3203	softc->dsreg = MTIO_DSREG_ZER;
3204	error = cam_periph_runccb(ccb, saerror, 0, 0, &softc->device_stats);
3205	softc->dsreg = MTIO_DSREG_REST;
3206
3207	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
3208		cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE);
3209	xpt_release_ccb(ccb);
3210	return (error);
3211}
3212
3213#endif /* _KERNEL */
3214
3215/*
3216 * Read tape block limits command.
3217 */
3218void
3219scsi_read_block_limits(struct ccb_scsiio *csio, u_int32_t retries,
3220		   void (*cbfcnp)(struct cam_periph *, union ccb *),
3221		   u_int8_t tag_action,
3222		   struct scsi_read_block_limits_data *rlimit_buf,
3223		   u_int8_t sense_len, u_int32_t timeout)
3224{
3225	struct scsi_read_block_limits *scsi_cmd;
3226
3227	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action,
3228	     (u_int8_t *)rlimit_buf, sizeof(*rlimit_buf), sense_len,
3229	     sizeof(*scsi_cmd), timeout);
3230
3231	scsi_cmd = (struct scsi_read_block_limits *)&csio->cdb_io.cdb_bytes;
3232	bzero(scsi_cmd, sizeof(*scsi_cmd));
3233	scsi_cmd->opcode = READ_BLOCK_LIMITS;
3234}
3235
3236void
3237scsi_sa_read_write(struct ccb_scsiio *csio, u_int32_t retries,
3238		   void (*cbfcnp)(struct cam_periph *, union ccb *),
3239		   u_int8_t tag_action, int readop, int sli,
3240		   int fixed, u_int32_t length, u_int8_t *data_ptr,
3241		   u_int32_t dxfer_len, u_int8_t sense_len, u_int32_t timeout)
3242{
3243	struct scsi_sa_rw *scsi_cmd;
3244
3245	scsi_cmd = (struct scsi_sa_rw *)&csio->cdb_io.cdb_bytes;
3246	scsi_cmd->opcode = readop ? SA_READ : SA_WRITE;
3247	scsi_cmd->sli_fixed = 0;
3248	if (sli && readop)
3249		scsi_cmd->sli_fixed |= SAR_SLI;
3250	if (fixed)
3251		scsi_cmd->sli_fixed |= SARW_FIXED;
3252	scsi_ulto3b(length, scsi_cmd->length);
3253	scsi_cmd->control = 0;
3254
3255	cam_fill_csio(csio, retries, cbfcnp, readop ? CAM_DIR_IN : CAM_DIR_OUT,
3256	    tag_action, data_ptr, dxfer_len, sense_len,
3257	    sizeof(*scsi_cmd), timeout);
3258}
3259
3260void
3261scsi_load_unload(struct ccb_scsiio *csio, u_int32_t retries,
3262		 void (*cbfcnp)(struct cam_periph *, union ccb *),
3263		 u_int8_t tag_action, int immediate, int eot,
3264		 int reten, int load, u_int8_t sense_len,
3265		 u_int32_t timeout)
3266{
3267	struct scsi_load_unload *scsi_cmd;
3268
3269	scsi_cmd = (struct scsi_load_unload *)&csio->cdb_io.cdb_bytes;
3270	bzero(scsi_cmd, sizeof(*scsi_cmd));
3271	scsi_cmd->opcode = LOAD_UNLOAD;
3272	if (immediate)
3273		scsi_cmd->immediate = SLU_IMMED;
3274	if (eot)
3275		scsi_cmd->eot_reten_load |= SLU_EOT;
3276	if (reten)
3277		scsi_cmd->eot_reten_load |= SLU_RETEN;
3278	if (load)
3279		scsi_cmd->eot_reten_load |= SLU_LOAD;
3280
3281	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action,
3282	    NULL, 0, sense_len, sizeof(*scsi_cmd), timeout);
3283}
3284
3285void
3286scsi_rewind(struct ccb_scsiio *csio, u_int32_t retries,
3287	    void (*cbfcnp)(struct cam_periph *, union ccb *),
3288	    u_int8_t tag_action, int immediate, u_int8_t sense_len,
3289	    u_int32_t timeout)
3290{
3291	struct scsi_rewind *scsi_cmd;
3292
3293	scsi_cmd = (struct scsi_rewind *)&csio->cdb_io.cdb_bytes;
3294	bzero(scsi_cmd, sizeof(*scsi_cmd));
3295	scsi_cmd->opcode = REWIND;
3296	if (immediate)
3297		scsi_cmd->immediate = SREW_IMMED;
3298
3299	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3300	    0, sense_len, sizeof(*scsi_cmd), timeout);
3301}
3302
3303void
3304scsi_space(struct ccb_scsiio *csio, u_int32_t retries,
3305	   void (*cbfcnp)(struct cam_periph *, union ccb *),
3306	   u_int8_t tag_action, scsi_space_code code,
3307	   u_int32_t count, u_int8_t sense_len, u_int32_t timeout)
3308{
3309	struct scsi_space *scsi_cmd;
3310
3311	scsi_cmd = (struct scsi_space *)&csio->cdb_io.cdb_bytes;
3312	scsi_cmd->opcode = SPACE;
3313	scsi_cmd->code = code;
3314	scsi_ulto3b(count, scsi_cmd->count);
3315	scsi_cmd->control = 0;
3316
3317	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3318	    0, sense_len, sizeof(*scsi_cmd), timeout);
3319}
3320
3321void
3322scsi_write_filemarks(struct ccb_scsiio *csio, u_int32_t retries,
3323		     void (*cbfcnp)(struct cam_periph *, union ccb *),
3324		     u_int8_t tag_action, int immediate, int setmark,
3325		     u_int32_t num_marks, u_int8_t sense_len,
3326		     u_int32_t timeout)
3327{
3328	struct scsi_write_filemarks *scsi_cmd;
3329
3330	scsi_cmd = (struct scsi_write_filemarks *)&csio->cdb_io.cdb_bytes;
3331	bzero(scsi_cmd, sizeof(*scsi_cmd));
3332	scsi_cmd->opcode = WRITE_FILEMARKS;
3333	if (immediate)
3334		scsi_cmd->byte2 |= SWFMRK_IMMED;
3335	if (setmark)
3336		scsi_cmd->byte2 |= SWFMRK_WSMK;
3337
3338	scsi_ulto3b(num_marks, scsi_cmd->num_marks);
3339
3340	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3341	    0, sense_len, sizeof(*scsi_cmd), timeout);
3342}
3343
3344/*
3345 * The reserve and release unit commands differ only by their opcodes.
3346 */
3347void
3348scsi_reserve_release_unit(struct ccb_scsiio *csio, u_int32_t retries,
3349			  void (*cbfcnp)(struct cam_periph *, union ccb *),
3350			  u_int8_t tag_action, int third_party,
3351			  int third_party_id, u_int8_t sense_len,
3352			  u_int32_t timeout, int reserve)
3353{
3354	struct scsi_reserve_release_unit *scsi_cmd;
3355
3356	scsi_cmd = (struct scsi_reserve_release_unit *)&csio->cdb_io.cdb_bytes;
3357	bzero(scsi_cmd, sizeof(*scsi_cmd));
3358
3359	if (reserve)
3360		scsi_cmd->opcode = RESERVE_UNIT;
3361	else
3362		scsi_cmd->opcode = RELEASE_UNIT;
3363
3364	if (third_party) {
3365		scsi_cmd->lun_thirdparty |= SRRU_3RD_PARTY;
3366		scsi_cmd->lun_thirdparty |=
3367			((third_party_id << SRRU_3RD_SHAMT) & SRRU_3RD_MASK);
3368	}
3369
3370	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3371	    0, sense_len, sizeof(*scsi_cmd), timeout);
3372}
3373
3374void
3375scsi_erase(struct ccb_scsiio *csio, u_int32_t retries,
3376	   void (*cbfcnp)(struct cam_periph *, union ccb *),
3377	   u_int8_t tag_action, int immediate, int long_erase,
3378	   u_int8_t sense_len, u_int32_t timeout)
3379{
3380	struct scsi_erase *scsi_cmd;
3381
3382	scsi_cmd = (struct scsi_erase *)&csio->cdb_io.cdb_bytes;
3383	bzero(scsi_cmd, sizeof(*scsi_cmd));
3384
3385	scsi_cmd->opcode = ERASE;
3386
3387	if (immediate)
3388		scsi_cmd->lun_imm_long |= SE_IMMED;
3389
3390	if (long_erase)
3391		scsi_cmd->lun_imm_long |= SE_LONG;
3392
3393	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action, NULL,
3394	    0, sense_len, sizeof(*scsi_cmd), timeout);
3395}
3396
3397/*
3398 * Read Tape Position command.
3399 */
3400void
3401scsi_read_position(struct ccb_scsiio *csio, u_int32_t retries,
3402		   void (*cbfcnp)(struct cam_periph *, union ccb *),
3403		   u_int8_t tag_action, int hardsoft,
3404		   struct scsi_tape_position_data *sbp,
3405		   u_int8_t sense_len, u_int32_t timeout)
3406{
3407	struct scsi_tape_read_position *scmd;
3408
3409	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_IN, tag_action,
3410	    (u_int8_t *)sbp, sizeof (*sbp), sense_len, sizeof(*scmd), timeout);
3411	scmd = (struct scsi_tape_read_position *)&csio->cdb_io.cdb_bytes;
3412	bzero(scmd, sizeof(*scmd));
3413	scmd->opcode = READ_POSITION;
3414	scmd->byte1 = hardsoft;
3415}
3416
3417/*
3418 * Set Tape Position command.
3419 */
3420void
3421scsi_set_position(struct ccb_scsiio *csio, u_int32_t retries,
3422		   void (*cbfcnp)(struct cam_periph *, union ccb *),
3423		   u_int8_t tag_action, int hardsoft, u_int32_t blkno,
3424		   u_int8_t sense_len, u_int32_t timeout)
3425{
3426	struct scsi_tape_locate *scmd;
3427
3428	cam_fill_csio(csio, retries, cbfcnp, CAM_DIR_NONE, tag_action,
3429	    (u_int8_t *)NULL, 0, sense_len, sizeof(*scmd), timeout);
3430	scmd = (struct scsi_tape_locate *)&csio->cdb_io.cdb_bytes;
3431	bzero(scmd, sizeof(*scmd));
3432	scmd->opcode = LOCATE;
3433	if (hardsoft)
3434		scmd->byte1 |= SA_SPOS_BT;
3435	scsi_ulto4b(blkno, scmd->blkaddr);
3436}
3437