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