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