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