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