[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cam/scsi/scsi_sa.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Implementation of SCSI Sequential Access Peripheral driver for CAM.
  3  *
  4  * Copyright (c) 1999, 2000 Matthew Jacob
  5  * All rights reserved.
  6  *
  7  * Redistribution and use in source and binary forms, with or without
  8  * modification, are permitted provided that the following conditions
  9  * are met:
 10  * 1. Redistributions of source code must retain the above copyright
 11  *    notice, this list of conditions, and the following disclaimer,
 12  *    without modification, immediately at the beginning of the file.
 13  * 2. The name of the author may not be used to endorse or promote products
 14  *    derived from this software without specific prior written permission.
 15  *
 16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 26  * SUCH DAMAGE.
 27  */
 28 
 29 #include <sys/cdefs.h>
 30 __FBSDID("$FreeBSD: src/sys/cam/scsi/scsi_sa.c,v 1.114 2008/09/27 08:51:18 ed Exp $");
 31 
 32 #include <sys/param.h>
 33 #include <sys/queue.h>
 34 #ifdef _KERNEL
 35 #include <sys/systm.h>
 36 #include <sys/kernel.h>
 37 #endif
 38 #include <sys/types.h>
 39 #include <sys/time.h>
 40 #include <sys/bio.h>
 41 #include <sys/limits.h>
 42 #include <sys/malloc.h>
 43 #include <sys/mtio.h>
 44 #ifdef _KERNEL
 45 #include <sys/conf.h>
 46 #endif
 47 #include <sys/fcntl.h>
 48 #include <sys/devicestat.h>
 49 
 50 #ifndef _KERNEL
 51 #include <stdio.h>
 52 #include <string.h>
 53 #endif
 54 
 55 #include <cam/cam.h>
 56 #include <cam/cam_ccb.h>
 57 #include <cam/cam_periph.h>
 58 #include <cam/cam_xpt_periph.h>
 59 #include <cam/cam_debug.h>
 60 
 61 #include <cam/scsi/scsi_all.h>
 62 #include <cam/scsi/scsi_message.h>
 63 #include <cam/scsi/scsi_sa.h>
 64 
 65 #ifdef _KERNEL
 66 
 67 #include <opt_sa.h>
 68 
 69 #ifndef SA_IO_TIMEOUT
 70 #define SA_IO_TIMEOUT           4
 71 #endif
 72 #ifndef SA_SPACE_TIMEOUT
 73 #define SA_SPACE_TIMEOUT        1 * 60
 74 #endif
 75 #ifndef SA_REWIND_TIMEOUT
 76 #define SA_REWIND_TIMEOUT       2 * 60
 77 #endif
 78 #ifndef SA_ERASE_TIMEOUT
 79 #define SA_ERASE_TIMEOUT        4 * 60
 80 #endif
 81 
 82 #define SCSIOP_TIMEOUT          (60 * 1000)     /* not an option */
 83 
 84 #define IO_TIMEOUT              (SA_IO_TIMEOUT * 60 * 1000)
 85 #define REWIND_TIMEOUT          (SA_REWIND_TIMEOUT * 60 * 1000)
 86 #define ERASE_TIMEOUT           (SA_ERASE_TIMEOUT * 60 * 1000)
 87 #define SPACE_TIMEOUT           (SA_SPACE_TIMEOUT * 60 * 1000)
 88 
 89 /*
 90  * Additional options that can be set for config: SA_1FM_AT_EOT
 91  */
 92 
 93 #ifndef UNUSED_PARAMETER
 94 #define UNUSED_PARAMETER(x)     x = x
 95 #endif
 96 
 97 #define QFRLS(ccb)      \
 98         if (((ccb)->ccb_h.status & CAM_DEV_QFRZN) != 0) \
 99                 cam_release_devq((ccb)->ccb_h.path, 0, 0, 0, FALSE)
100 
101 /*
102  * Driver states
103  */
104 
105 MALLOC_DEFINE(M_SCSISA, "SCSI sa", "SCSI sequential access buffers");
106 
107 typedef enum {
108         SA_STATE_NORMAL, SA_STATE_ABNORMAL
109 } sa_state;
110 
111 #define ccb_pflags      ppriv_field0
112 #define ccb_bp          ppriv_ptr1
113 
114 #define SA_CCB_BUFFER_IO        0x0
115 #define SA_CCB_WAITING          0x1
116 #define SA_CCB_TYPEMASK         0x1
117 #define SA_POSITION_UPDATED     0x2
118 
119 #define Set_CCB_Type(x, type)                           \
120         x->ccb_h.ccb_pflags &= ~SA_CCB_TYPEMASK;        \
121         x->ccb_h.ccb_pflags |= type
122 
123 #define CCB_Type(x)     (x->ccb_h.ccb_pflags & SA_CCB_TYPEMASK)
124 
125 
126 
127 typedef enum {
128         SA_FLAG_OPEN            = 0x0001,
129         SA_FLAG_FIXED           = 0x0002,
130         SA_FLAG_TAPE_LOCKED     = 0x0004,
131         SA_FLAG_TAPE_MOUNTED    = 0x0008,
132         SA_FLAG_TAPE_WP         = 0x0010,
133         SA_FLAG_TAPE_WRITTEN    = 0x0020,
134         SA_FLAG_EOM_PENDING     = 0x0040,
135         SA_FLAG_EIO_PENDING     = 0x0080,
136         SA_FLAG_EOF_PENDING     = 0x0100,
137         SA_FLAG_ERR_PENDING     = (SA_FLAG_EOM_PENDING|SA_FLAG_EIO_PENDING|
138                                    SA_FLAG_EOF_PENDING),
139         SA_FLAG_INVALID         = 0x0200,
140         SA_FLAG_COMP_ENABLED    = 0x0400,
141         SA_FLAG_COMP_SUPP       = 0x0800,
142         SA_FLAG_COMP_UNSUPP     = 0x1000,
143         SA_FLAG_TAPE_FROZEN     = 0x2000
144 } sa_flags;
145 
146 typedef enum {
147         SA_MODE_REWIND          = 0x00,
148         SA_MODE_NOREWIND        = 0x01,
149         SA_MODE_OFFLINE         = 0x02
150 } sa_mode;
151 
152 typedef enum {
153         SA_PARAM_NONE           = 0x00,
154         SA_PARAM_BLOCKSIZE      = 0x01,
155         SA_PARAM_DENSITY        = 0x02,
156         SA_PARAM_COMPRESSION    = 0x04,
157         SA_PARAM_BUFF_MODE      = 0x08,
158         SA_PARAM_NUMBLOCKS      = 0x10,
159         SA_PARAM_WP             = 0x20,
160         SA_PARAM_SPEED          = 0x40,
161         SA_PARAM_ALL            = 0x7f
162 } sa_params;
163 
164 typedef enum {
165         SA_QUIRK_NONE           = 0x00,
166         SA_QUIRK_NOCOMP         = 0x01, /* Can't deal with compression at all */
167         SA_QUIRK_FIXED          = 0x02, /* Force fixed mode */
168         SA_QUIRK_VARIABLE       = 0x04, /* Force variable mode */
169         SA_QUIRK_2FM            = 0x08, /* Needs Two File Marks at EOD */
170         SA_QUIRK_1FM            = 0x10, /* No more than 1 File Mark at EOD */
171         SA_QUIRK_NODREAD        = 0x20, /* Don't try and dummy read density */
172         SA_QUIRK_NO_MODESEL     = 0x40, /* Don't do mode select at all */
173         SA_QUIRK_NO_CPAGE       = 0x80  /* Don't use DEVICE COMPRESSION page */
174 } sa_quirks;
175 
176 /* units are bits 4-7, 16-21 (1024 units) */
177 #define SAUNIT(DEV) \
178         (((dev2unit(DEV) & 0xF0) >> 4) |  ((dev2unit(DEV) & 0x3f0000) >> 16))
179 
180 #define SAMODE(z) ((dev2unit(z) & 0x3))
181 #define SADENSITY(z) (((dev2unit(z) >> 2) & 0x3))
182 #define SA_IS_CTRL(z) (dev2unit(z) & (1 << 29))
183 
184 #define SA_NOT_CTLDEV   0
185 #define SA_CTLDEV       1
186 
187 #define SA_ATYPE_R      0
188 #define SA_ATYPE_NR     1
189 #define SA_ATYPE_ER     2
190 
191 #define SAMINOR(ctl, unit, mode, access) \
192         ((ctl << 29) | ((unit & 0x3f0) << 16) | ((unit & 0xf) << 4) | \
193         (mode << 0x2) | (access & 0x3))
194 
195 #define SA_NUM_MODES    4
196 struct sa_devs {
197         struct cdev *ctl_dev;
198         struct sa_mode_devs {
199                 struct cdev *r_dev;
200                 struct cdev *nr_dev;
201                 struct cdev *er_dev;
202         } mode_devs[SA_NUM_MODES];
203 };
204 
205 struct sa_softc {
206         sa_state        state;
207         sa_flags        flags;
208         sa_quirks       quirks;
209         struct          bio_queue_head bio_queue;
210         int             queue_count;
211         struct          devstat *device_stats;
212         struct sa_devs  devs;
213         int             blk_gran;
214         int             blk_mask;
215         int             blk_shift;
216         u_int32_t       max_blk;
217         u_int32_t       min_blk;
218         u_int32_t       comp_algorithm;
219         u_int32_t       saved_comp_algorithm;
220         u_int32_t       media_blksize;
221         u_int32_t       last_media_blksize;
222         u_int32_t       media_numblks;
223         u_int8_t        media_density;
224         u_int8_t        speed;
225         u_int8_t        scsi_rev;
226         u_int8_t        dsreg;          /* mtio mt_dsreg, redux */
227         int             buffer_mode;
228         int             filemarks;
229         union           ccb saved_ccb;
230         int             last_resid_was_io;
231 
232         /*
233          * Relative to BOT Location.
234          */
235         daddr_t         fileno;
236         daddr_t         blkno;
237 
238         /*
239          * Latched Error Info
240          */
241         struct {
242                 struct scsi_sense_data _last_io_sense;
243                 u_int32_t _last_io_resid;
244                 u_int8_t _last_io_cdb[CAM_MAX_CDBLEN];
245                 struct scsi_sense_data _last_ctl_sense;
246                 u_int32_t _last_ctl_resid;
247                 u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN];
248 #define last_io_sense   errinfo._last_io_sense
249 #define last_io_resid   errinfo._last_io_resid
250 #define last_io_cdb     errinfo._last_io_cdb
251 #define last_ctl_sense  errinfo._last_ctl_sense
252 #define last_ctl_resid  errinfo._last_ctl_resid
253 #define last_ctl_cdb    errinfo._last_ctl_cdb
254         } errinfo;
255         /*
256          * Misc other flags/state
257          */
258         u_int32_t
259                                         : 29,
260                 open_rdonly             : 1,    /* open read-only */
261                 open_pending_mount      : 1,    /* open pending mount */
262                 ctrl_mode               : 1;    /* control device open */
263 };
264 
265 struct sa_quirk_entry {
266         struct scsi_inquiry_pattern inq_pat;    /* matching pattern */
267         sa_quirks quirks;       /* specific quirk type */
268         u_int32_t prefblk;      /* preferred blocksize when in fixed mode */
269 };
270 
271 static struct sa_quirk_entry sa_quirk_table[] =
272 {
273         {
274                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "OnStream",
275                   "ADR*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_NODREAD |
276                    SA_QUIRK_1FM|SA_QUIRK_NO_MODESEL, 32768
277         },
278         {
279                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
280                   "Python 06408*", "*"}, SA_QUIRK_NODREAD, 0
281         },
282         {
283                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
284                   "Python 25601*", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_NODREAD, 0
285         },
286         {
287                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
288                   "Python*", "*"}, SA_QUIRK_NODREAD, 0
289         },
290         {
291                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
292                   "VIPER 150*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
293         },
294         {
295                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
296                   "VIPER 2525 25462", "-011"},
297                   SA_QUIRK_NOCOMP|SA_QUIRK_1FM|SA_QUIRK_NODREAD, 0
298         },
299         {
300                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE",
301                   "VIPER 2525*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024
302         },
303 #if     0
304         {
305                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
306                   "C15*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_NO_CPAGE, 0,
307         },
308 #endif
309         {
310                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
311                   "C56*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
312         },
313         {
314                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
315                   "T20*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
316         },
317         {
318                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
319                   "T4000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
320         },
321         {
322                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP",
323                   "HP-88780*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
324         },
325         {
326                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY",
327                   "*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
328         },
329         {
330                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "M4 DATA",
331                   "123107 SCSI*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0
332         },
333         {       /* jreynold@primenet.com */
334                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate",
335                 "STT8000N*", "*"}, SA_QUIRK_1FM, 0
336         },
337         {       /* mike@sentex.net */
338                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "Seagate",
339                 "STT20000*", "*"}, SA_QUIRK_1FM, 0
340         },
341         {
342                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
343                   " TDC 3600", "U07:"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
344         },
345         {
346                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
347                   " TDC 3800", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
348         },
349         {
350                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
351                   " TDC 4100", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
352         },
353         {
354                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
355                   " TDC 4200", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512
356         },
357         {
358                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG",
359                   " SLR*", "*"}, SA_QUIRK_1FM, 0
360         },
361         {
362                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK",
363                   "5525ES*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512
364         },
365         {
366                 { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK",
367                   "51000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024
368         }
369 };
370 
371 static  d_open_t        saopen;
372 static  d_close_t       saclose;
373 static  d_strategy_t    sastrategy;
374 static  d_ioctl_t       saioctl;
375 static  periph_init_t   sainit;
376 static  periph_ctor_t   saregister;
377 static  periph_oninv_t  saoninvalidate;
378 static  periph_dtor_t   sacleanup;
379 static  periph_start_t  sastart;
380 static  void            saasync(void *callback_arg, u_int32_t code,
381                                 struct cam_path *path, void *arg);
382 static  void            sadone(struct cam_periph *periph,
383                                union ccb *start_ccb);
384 static  int             saerror(union ccb *ccb, u_int32_t cam_flags,
385                                 u_int32_t sense_flags);
386 static int              samarkswanted(struct cam_periph *);
387 static int              sacheckeod(struct cam_periph *periph);
388 static int              sagetparams(struct cam_periph *periph,
389                                     sa_params params_to_get,
390                                     u_int32_t *blocksize, u_int8_t *density,
391                                     u_int32_t *numblocks, int *buff_mode,
392                                     u_int8_t *write_protect, u_int8_t *speed,
393                                     int *comp_supported, int *comp_enabled,
394                                     u_int32_t *comp_algorithm,
395                                     sa_comp_t *comp_page);
396 static int              sasetparams(struct cam_periph *periph,
397                                     sa_params params_to_set,
398                                     u_int32_t blocksize, u_int8_t density,
399                                     u_int32_t comp_algorithm,
400                                     u_int32_t sense_flags);
401 static void             saprevent(struct cam_periph *periph, int action);
402 static int              sarewind(struct cam_periph *periph);
403 static int              saspace(struct cam_periph *periph, int count,
404                                 scsi_space_code code);
405 static int              samount(struct cam_periph *, int, struct cdev *);
406 static int              saretension(struct cam_periph *periph);
407 static int              sareservereleaseunit(struct cam_periph *periph,
408                                              int reserve);
409 static int              saloadunload(struct cam_periph *periph, int load);
410 static int              saerase(struct cam_periph *periph, int longerase);
411 static int              sawritefilemarks(struct cam_periph *periph,
412                                          int nmarks, int setmarks);
413 static int              sardpos(struct cam_periph *periph, int, u_int32_t *);
414 static int              sasetpos(struct cam_periph *periph, int, u_int32_t *);
415 
416 
417 static struct periph_driver sadriver =
418 {
419         sainit, "sa",
420         TAILQ_HEAD_INITIALIZER(sadriver.units), /* generation */ 0
421 };
422 
423 PERIPHDRIVER_DECLARE(sa, sadriver);
424 
425 /* For 2.2-stable support */
426 #ifndef D_TAPE
427 #define D_TAPE 0
428 #endif
429 
430 
431 static struct cdevsw sa_cdevsw = {
432         .d_version =    D_VERSION,
433         .d_open =       saopen,
434         .d_close =      saclose,
435         .d_read =       physread,
436         .d_write =      physwrite,
437         .d_ioctl =      saioctl,
438         .d_strategy =   sastrategy,
439         .d_name =       "sa",
440         .d_flags =      D_TAPE | D_NEEDGIANT,
441 };
442 
443 static int
444 saopen(struct cdev *dev, int flags, int fmt, struct thread *td)
445 {
446         struct cam_periph *periph;
447         struct sa_softc *softc;
448         int unit;
449         int error;
450 
451         unit = SAUNIT(dev);
452 
453         periph = (struct cam_periph *)dev->si_drv1;
454         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
455                 return (ENXIO);
456         }
457 
458         cam_periph_lock(periph);
459 
460         softc = (struct sa_softc *)periph->softc;
461 
462         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO,
463             ("saopen(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
464 
465         if (SA_IS_CTRL(dev)) {
466                 softc->ctrl_mode = 1;
467                 cam_periph_unlock(periph);
468                 return (0);
469         }
470 
471         if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) {
472                 cam_periph_unlock(periph);
473                 cam_periph_release(periph);
474                 return (error);
475         }
476 
477         if (softc->flags & SA_FLAG_OPEN) {
478                 error = EBUSY;
479         } else if (softc->flags & SA_FLAG_INVALID) {
480                 error = ENXIO;
481         } else {
482                 /*
483                  * Preserve whether this is a read_only open.
484                  */
485                 softc->open_rdonly = (flags & O_RDWR) == O_RDONLY;
486 
487                 /*
488                  * The function samount ensures media is loaded and ready.
489                  * It also does a device RESERVE if the tape isn't yet mounted.
490                  *
491                  * If the mount fails and this was a non-blocking open,
492                  * make this a 'open_pending_mount' action.
493                  */
494                 error = samount(periph, flags, dev);
495                 if (error && (flags & O_NONBLOCK)) {
496                         softc->flags |= SA_FLAG_OPEN;
497                         softc->open_pending_mount = 1;
498                         cam_periph_unhold(periph);
499                         cam_periph_unlock(periph);
500                         return (0);
501                 }
502         }
503 
504         if (error) {
505                 cam_periph_unhold(periph);
506                 cam_periph_unlock(periph);
507                 cam_periph_release(periph);
508                 return (error);
509         }
510 
511         saprevent(periph, PR_PREVENT);
512         softc->flags |= SA_FLAG_OPEN;
513 
514         cam_periph_unhold(periph);
515         cam_periph_unlock(periph);
516         return (error);
517 }
518 
519 static int
520 saclose(struct cdev *dev, int flag, int fmt, struct thread *td)
521 {
522         struct  cam_periph *periph;
523         struct  sa_softc *softc;
524         int     unit, mode, error, writing, tmp;
525         int     closedbits = SA_FLAG_OPEN;
526 
527         unit = SAUNIT(dev);
528         mode = SAMODE(dev);
529         periph = (struct cam_periph *)dev->si_drv1;
530         if (periph == NULL)
531                 return (ENXIO); 
532 
533         cam_periph_lock(periph);
534 
535         softc = (struct sa_softc *)periph->softc;
536 
537         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO,
538             ("saclose(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags));
539 
540 
541         softc->open_rdonly = 0; 
542         if (SA_IS_CTRL(dev)) {
543                 softc->ctrl_mode = 0;
544                 cam_periph_unlock(periph);
545                 cam_periph_release(periph);
546                 return (0);
547         }
548 
549         if (softc->open_pending_mount) {
550                 softc->flags &= ~SA_FLAG_OPEN;
551                 softc->open_pending_mount = 0; 
552                 cam_periph_unlock(periph);
553                 cam_periph_release(periph);
554                 return (0);
555         }
556 
557         if ((error = cam_periph_hold(periph, PRIBIO)) != 0) {
558                 cam_periph_unlock(periph);
559                 return (error);
560         }
561 
562         /*
563          * Were we writing the tape?
564          */
565         writing = (softc->flags & SA_FLAG_TAPE_WRITTEN) != 0;
566 
567         /*
568          * See whether or not we need to write filemarks. If this
569          * fails, we probably have to assume we've lost tape
570          * position.
571          */
572         error = sacheckeod(periph);
573         if (error) {
574                 xpt_print(periph->path,
575                     "failed to write terminating filemark(s)\n");
576                 softc->flags |= SA_FLAG_TAPE_FROZEN;
577         }
578 
579         /*
580          * Whatever we end up doing, allow users to eject tapes from here on.
581          */
582         saprevent(periph, PR_ALLOW);
583 
584         /*
585          * Decide how to end...
586          */
587         if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) {
588                 closedbits |= SA_FLAG_TAPE_FROZEN;
589         } else switch (mode) {
590         case SA_MODE_OFFLINE:
591                 /*
592                  * An 'offline' close is an unconditional release of
593                  * frozen && mount conditions, irrespective of whether
594                  * these operations succeeded. The reason for this is
595                  * to allow at least some kind of programmatic way
596                  * around our state getting all fouled up. If somebody
597                  * issues an 'offline' command, that will be allowed
598                  * to clear state.
599                  */
600                 (void) sarewind(periph);
601                 (void) saloadunload(periph, FALSE);
602                 closedbits |= SA_FLAG_TAPE_MOUNTED|SA_FLAG_TAPE_FROZEN;
603                 break;
604         case SA_MODE_REWIND:
605                 /*
606                  * If the rewind fails, return an error- if anyone cares,
607                  * but not overwriting any previous error.
608                  *
609                  * We don't clear the notion of mounted here, but we do
610                  * clear the notion of frozen if we successfully rewound.
611                  */
612                 tmp = sarewind(periph);
613                 if (tmp) {
614                         if (error != 0)
615                                 error = tmp;
616                 } else {
617                         closedbits |= SA_FLAG_TAPE_FROZEN;
618                 }
619                 break;
620         case SA_MODE_NOREWIND:
621                 /*
622                  * If we're not rewinding/unloading the tape, find out
623                  * whether we need to back up over one of two filemarks
624                  * we wrote (if we wrote two filemarks) so that appends
625                  * from this point on will be sane.
626                  */
627                 if (error == 0 && writing && (softc->quirks & SA_QUIRK_2FM)) {
628                         tmp = saspace(periph, -1, SS_FILEMARKS);
629                         if (tmp) {
630                                 xpt_print(periph->path, "unable to backspace "
631                                     "over one of double filemarks at end of "
632                                     "tape\n");
633                                 xpt_print(periph->path, "it is possible that "
634                                     "this device needs a SA_QUIRK_1FM quirk set"
635                                     "for it\n");
636                                 softc->flags |= SA_FLAG_TAPE_FROZEN;
637                         }
638                 }
639                 break;
640         default:
641                 xpt_print(periph->path, "unknown mode 0x%x in saclose\n", mode);
642                 /* NOTREACHED */
643                 break;
644         }
645 
646         /*
647          * We wish to note here that there are no more filemarks to be written.
648          */
649         softc->filemarks = 0;
650         softc->flags &= ~SA_FLAG_TAPE_WRITTEN;
651 
652         /*
653          * And we are no longer open for business.
654          */
655         softc->flags &= ~closedbits;
656 
657         /*
658          * Inform users if tape state if frozen....
659          */
660         if (softc->flags & SA_FLAG_TAPE_FROZEN) {
661                 xpt_print(periph->path, "tape is now frozen- use an OFFLINE, "
662                     "REWIND or MTEOM command to clear this state.\n");
663         }
664         
665         /* release the device if it is no longer mounted */
666         if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0)
667                 sareservereleaseunit(periph, FALSE);
668 
669         cam_periph_unhold(periph);
670         cam_periph_unlock(periph);
671         cam_periph_release(periph);
672 
673         return (error); 
674 }
675 
676 /*
677  * Actually translate the requested transfer into one the physical driver
678  * can understand.  The transfer is described by a buf and will include
679  * only one physical transfer.
680  */
681 static void
682 sastrategy(struct bio *bp)
683 {
684         struct cam_periph *periph;
685         struct sa_softc *softc;
686         
687         bp->bio_resid = bp->bio_bcount;
688         if (SA_IS_CTRL(bp->bio_dev)) {
689                 biofinish(bp, NULL, EINVAL);
690                 return;
691         }
692         periph = (struct cam_periph *)bp->bio_dev->si_drv1;
693         if (periph == NULL) {
694                 biofinish(bp, NULL, ENXIO);
695                 return;
696         }
697         cam_periph_lock(periph);
698 
699         softc = (struct sa_softc *)periph->softc;
700 
701         if (softc->flags & SA_FLAG_INVALID) {
702                 cam_periph_unlock(periph);
703                 biofinish(bp, NULL, ENXIO);
704                 return;
705         }
706 
707         if (softc->flags & SA_FLAG_TAPE_FROZEN) {
708                 cam_periph_unlock(periph);
709                 biofinish(bp, NULL, EPERM);
710                 return;
711         }
712 
713         /*
714          * This should actually never occur as the write(2)
715          * system call traps attempts to write to a read-only
716          * file descriptor.
717          */
718         if (bp->bio_cmd == BIO_WRITE && softc->open_rdonly) {
719                 cam_periph_unlock(periph);
720                 biofinish(bp, NULL, EBADF);
721                 return;
722         }
723 
724         if (softc->open_pending_mount) {
725                 int error = samount(periph, 0, bp->bio_dev);
726                 if (error) {
727                         cam_periph_unlock(periph);
728                         biofinish(bp, NULL, ENXIO);
729                         return;
730                 }
731                 saprevent(periph, PR_PREVENT);
732                 softc->open_pending_mount = 0;
733         }
734 
735 
736         /*
737          * If it's a null transfer, return immediately
738          */
739         if (bp->bio_bcount == 0) {
740                 cam_periph_unlock(periph);
741                 biodone(bp);
742                 return;
743         }
744 
745         /* valid request?  */
746         if (softc->flags & SA_FLAG_FIXED) {
747                 /*
748                  * Fixed block device.  The byte count must
749                  * be a multiple of our block size.
750                  */
751                 if (((softc->blk_mask != ~0) &&
752                     ((bp->bio_bcount & softc->blk_mask) != 0)) ||
753                     ((softc->blk_mask == ~0) &&
754                     ((bp->bio_bcount % softc->min_blk) != 0))) {
755                         xpt_print(periph->path, "Invalid request.  Fixed block "
756                             "device requests must be a multiple of %d bytes\n",
757                             softc->min_blk);
758                         cam_periph_unlock(periph);
759                         biofinish(bp, NULL, EINVAL);
760                         return;
761                 }
762         } else if ((bp->bio_bcount > softc->max_blk) ||
763                    (bp->bio_bcount < softc->min_blk) ||
764                    (bp->bio_bcount & softc->blk_mask) != 0) {
765 
766                 xpt_print_path(periph->path);
767                 printf("Invalid request.  Variable block "
768                     "device requests must be ");
769                 if (softc->blk_mask != 0) {
770                         printf("a multiple of %d ", (0x1 << softc->blk_gran));
771                 }
772                 printf("between %d and %d bytes\n", softc->min_blk,
773                     softc->max_blk);
774                 cam_periph_unlock(periph);
775                 biofinish(bp, NULL, EINVAL);
776                 return;
777         }
778         
779         /*
780          * Place it at the end of the queue.
781          */
782         bioq_insert_tail(&softc->bio_queue, bp);
783         softc->queue_count++;
784 #if     0
785         CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
786             ("sastrategy: queuing a %ld %s byte %s\n", bp->bio_bcount,
787             (softc->flags & SA_FLAG_FIXED)?  "fixed" : "variable",
788             (bp->bio_cmd == BIO_READ)? "read" : "write"));
789 #endif
790         if (softc->queue_count > 1) {
791                 CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
792                     ("sastrategy: queue count now %d\n", softc->queue_count));
793         }
794         
795         /*
796          * Schedule ourselves for performing the work.
797          */
798         xpt_schedule(periph, 1);
799         cam_periph_unlock(periph);
800 
801         return;
802 }
803 
804 
805 #define PENDING_MOUNT_CHECK(softc, periph, dev)         \
806         if (softc->open_pending_mount) {                \
807                 error = samount(periph, 0, dev);        \
808                 if (error) {                            \
809                         break;                          \
810                 }                                       \
811                 saprevent(periph, PR_PREVENT);          \
812                 softc->open_pending_mount = 0;          \
813         }
814 
815 static int
816 saioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
817 {
818         struct cam_periph *periph;
819         struct sa_softc *softc;
820         scsi_space_code spaceop;
821         int didlockperiph = 0;
822         int mode;
823         int error = 0;
824 
825         mode = SAMODE(dev);
826         error = 0;              /* shut up gcc */
827         spaceop = 0;            /* shut up gcc */
828 
829         periph = (struct cam_periph *)dev->si_drv1;
830         if (periph == NULL)
831                 return (ENXIO); 
832 
833         cam_periph_lock(periph);
834         softc = (struct sa_softc *)periph->softc;
835 
836         /*
837          * Check for control mode accesses. We allow MTIOCGET and
838          * MTIOCERRSTAT (but need to be the only one open in order
839          * to clear latched status), and MTSETBSIZE, MTSETDNSTY
840          * and MTCOMP (but need to be the only one accessing this
841          * device to run those).
842          */
843 
844         if (SA_IS_CTRL(dev)) {
845                 switch (cmd) {
846                 case MTIOCGETEOTMODEL:
847                 case MTIOCGET:
848                         break;
849                 case MTIOCERRSTAT:
850                         /*
851                          * If the periph isn't already locked, lock it
852                          * so our MTIOCERRSTAT can reset latched error stats.
853                          *
854                          * If the periph is already locked, skip it because
855                          * we're just getting status and it'll be up to the
856                          * other thread that has this device open to do
857                          * an MTIOCERRSTAT that would clear latched status.
858                          */
859                         if ((periph->flags & CAM_PERIPH_LOCKED) == 0) {
860                                 error = cam_periph_hold(periph, PRIBIO|PCATCH);
861                                  if (error != 0)
862                                         return (error);
863                                 didlockperiph = 1;
864                         }
865                         break;
866 
867                 case MTIOCTOP:
868                 {
869                         struct mtop *mt = (struct mtop *) arg;
870 
871                         /*
872                          * Check to make sure it's an OP we can perform
873                          * with no media inserted.
874                          */
875                         switch (mt->mt_op) {
876                         case MTSETBSIZ:
877                         case MTSETDNSTY:
878                         case MTCOMP:
879                                 mt = NULL;
880                                 /* FALLTHROUGH */
881                         default:
882                                 break;
883                         }
884                         if (mt != NULL) {
885                                 break;
886                         }
887                         /* FALLTHROUGH */
888                 }
889                 case MTIOCSETEOTMODEL:
890                         /*
891                          * We need to acquire the peripheral here rather
892                          * than at open time because we are sharing writable
893                          * access to data structures.
894                          */
895                         error = cam_periph_hold(periph, PRIBIO|PCATCH);
896                         if (error != 0)
897                                 return (error);
898                         didlockperiph = 1;
899                         break;
900 
901                 default:
902                         return (EINVAL);
903                 }
904         }
905 
906         /*
907          * Find the device that the user is talking about
908          */
909         switch (cmd) {
910         case MTIOCGET:
911         {
912                 struct mtget *g = (struct mtget *)arg;
913 
914                 /*
915                  * If this isn't the control mode device, actually go out
916                  * and ask the drive again what it's set to.
917                  */
918                 if (!SA_IS_CTRL(dev) && !softc->open_pending_mount) {
919                         u_int8_t write_protect;
920                         int comp_enabled, comp_supported;
921                         error = sagetparams(periph, SA_PARAM_ALL,
922                             &softc->media_blksize, &softc->media_density,
923                             &softc->media_numblks, &softc->buffer_mode,
924                             &write_protect, &softc->speed, &comp_supported,
925                             &comp_enabled, &softc->comp_algorithm, NULL);
926                         if (error)
927                                 break;
928                         if (write_protect)
929                                 softc->flags |= SA_FLAG_TAPE_WP;
930                         else
931                                 softc->flags &= ~SA_FLAG_TAPE_WP;
932                         softc->flags &= ~(SA_FLAG_COMP_SUPP|
933                             SA_FLAG_COMP_ENABLED|SA_FLAG_COMP_UNSUPP);
934                         if (comp_supported) {
935                                 if (softc->saved_comp_algorithm == 0)
936                                         softc->saved_comp_algorithm =
937                                             softc->comp_algorithm;
938                                 softc->flags |= SA_FLAG_COMP_SUPP;
939                                 if (comp_enabled)
940                                         softc->flags |= SA_FLAG_COMP_ENABLED;
941                         } else  
942                                 softc->flags |= SA_FLAG_COMP_UNSUPP;
943                 }
944                 bzero(g, sizeof(struct mtget));
945                 g->mt_type = MT_ISAR;
946                 if (softc->flags & SA_FLAG_COMP_UNSUPP) {
947                         g->mt_comp = MT_COMP_UNSUPP;
948                         g->mt_comp0 = MT_COMP_UNSUPP;
949                         g->mt_comp1 = MT_COMP_UNSUPP;
950                         g->mt_comp2 = MT_COMP_UNSUPP;
951                         g->mt_comp3 = MT_COMP_UNSUPP;
952                 } else {
953                         if ((softc->flags & SA_FLAG_COMP_ENABLED) == 0) {
954                                 g->mt_comp = MT_COMP_DISABLED;
955                         } else {
956                                 g->mt_comp = softc->comp_algorithm;
957                         }
958                         g->mt_comp0 = softc->comp_algorithm;
959                         g->mt_comp1 = softc->comp_algorithm;
960                         g->mt_comp2 = softc->comp_algorithm;
961                         g->mt_comp3 = softc->comp_algorithm;
962                 }
963                 g->mt_density = softc->media_density;
964                 g->mt_density0 = softc->media_density;
965                 g->mt_density1 = softc->media_density;
966                 g->mt_density2 = softc->media_density;
967                 g->mt_density3 = softc->media_density;
968                 g->mt_blksiz = softc->media_blksize;
969                 g->mt_blksiz0 = softc->media_blksize;
970                 g->mt_blksiz1 = softc->media_blksize;
971                 g->mt_blksiz2 = softc->media_blksize;
972                 g->mt_blksiz3 = softc->media_blksize;
973                 g->mt_fileno = softc->fileno;
974                 g->mt_blkno = softc->blkno;
975                 g->mt_dsreg = (short) softc->dsreg;
976                 /*
977                  * Yes, we know that this is likely to overflow
978                  */
979                 if (softc->last_resid_was_io) {
980                         if ((g->mt_resid = (short) softc->last_io_resid) != 0) {
981                                 if (SA_IS_CTRL(dev) == 0 || didlockperiph) {
982                                         softc->last_io_resid = 0;
983                                 }
984                         }
985                 } else {
986                         if ((g->mt_resid = (short)softc->last_ctl_resid) != 0) {
987                                 if (SA_IS_CTRL(dev) == 0 || didlockperiph) {
988                                         softc->last_ctl_resid = 0;
989                                 }
990                         }
991                 }
992