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