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