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