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