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