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