scsi_sa.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,514 行 · 第 1/5 页
C
2,514 行
/* * $Id: scsi_sa.c,v 1.16.2.4 1999/05/11 05:40:43 mjacob Exp $ * * Implementation of SCSI Sequential Access Peripheral driver for CAM. * * Copyright (c) 1997 Justin T. Gibbs * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Substantial subsequent modifications * Copyright (c) 1999 Matthew Jacob * NASA Ames Research Center, * Feral Software */#include <sys/param.h>#include <sys/queue.h>#ifdef KERNEL#include <sys/systm.h>#include <sys/kernel.h>#endif#include <sys/types.h>#include <sys/buf.h>#include <sys/malloc.h>#include <sys/mtio.h>#include <sys/conf.h>#include <sys/buf.h>#include <sys/devicestat.h>#include <machine/limits.h>#ifndef KERNEL#include <stdio.h>#include <string.h>#endif#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/cam_extend.h>#include <cam/cam_periph.h>#include <cam/cam_xpt_periph.h>#include <cam/cam_debug.h>#include <cam/scsi/scsi_all.h>#include <cam/scsi/scsi_message.h>#include <cam/scsi/scsi_sa.h>#ifdef KERNEL#include <opt_sa.h>#ifndef SA_SPACE_TIMEOUT#define SA_SPACE_TIMEOUT 1 * 60#endif#ifndef SA_REWIND_TIMEOUT#define SA_REWIND_TIMEOUT 2 * 60#endif#ifndef SA_ERASE_TIMEOUT#define SA_ERASE_TIMEOUT 4 * 60#endif/* * Default to old FreeBSD behaviour of 2 filemarks * at EOD for all (except QIC) devices. */#ifndef SA_2FM_AT_EOD#define SA_2FM_AT_EOD 1#endif#ifndef UNUSED_PARAMETER#define UNUSED_PARAMETER(x) x = x#endiftypedef enum { SA_STATE_NORMAL, SA_STATE_ABNORMAL} sa_state;typedef enum { SA_CCB_BUFFER_IO, SA_CCB_WAITING} sa_ccb_types;#define ccb_type ppriv_field0#define ccb_bp ppriv_ptr1typedef enum { SA_FLAG_OPEN = 0x0001, SA_FLAG_FIXED = 0x0002, SA_FLAG_TAPE_LOCKED = 0x0004, SA_FLAG_TAPE_MOUNTED = 0x0008, SA_FLAG_TAPE_WP = 0x0010, SA_FLAG_TAPE_WRITTEN = 0x0020, SA_FLAG_EOM_PENDING = 0x0040, SA_FLAG_EIO_PENDING = 0x0080, SA_FLAG_EOF_PENDING = 0x0100, SA_FLAG_ERR_PENDING = (SA_FLAG_EOM_PENDING|SA_FLAG_EIO_PENDING| SA_FLAG_EOF_PENDING), SA_FLAG_INVALID = 0x0200, SA_FLAG_COMP_ENABLED = 0x0400, SA_FLAG_COMP_SUPP = 0x0800, SA_FLAG_COMP_UNSUPP = 0x1000, SA_FLAG_TAPE_FROZEN = 0x2000} sa_flags;typedef enum { SA_MODE_REWIND = 0x00, SA_MODE_NOREWIND = 0x01, SA_MODE_OFFLINE = 0x02} sa_mode;typedef enum { SA_PARAM_NONE = 0x00, SA_PARAM_BLOCKSIZE = 0x01, SA_PARAM_DENSITY = 0x02, SA_PARAM_COMPRESSION = 0x04, SA_PARAM_BUFF_MODE = 0x08, SA_PARAM_NUMBLOCKS = 0x10, SA_PARAM_WP = 0x20, SA_PARAM_SPEED = 0x40, SA_PARAM_ALL = 0x7f} sa_params;typedef enum { SA_QUIRK_NONE = 0x00, SA_QUIRK_NOCOMP = 0x01, /* can't deal with compression at all */ SA_QUIRK_FIXED = 0x02, /* force fixed mode */ SA_QUIRK_VARIABLE = 0x04, /* force variable mode */ SA_QUIRK_2FM = 0x08, /* Needs Two File Marks at EOD */ SA_QUIRK_1FM = 0x10 /* No more than 1 File Mark at EOD */} sa_quirks;struct sa_softc { sa_state state; sa_flags flags; sa_quirks quirks; struct buf_queue_head buf_queue; int queue_count; struct devstat device_stats; int blk_gran; int blk_mask; int blk_shift; u_int32_t max_blk; u_int32_t min_blk; u_int32_t comp_algorithm; u_int32_t saved_comp_algorithm; u_int32_t media_blksize; u_int32_t last_media_blksize; u_int32_t media_numblks; u_int8_t media_density; u_int8_t speed; u_int8_t scsi_rev; u_int8_t dsreg; /* mtio mt_dsreg, redux */ int buffer_mode; int filemarks; union ccb saved_ccb; /* * Relative to BOT Location. */ daddr_t fileno; daddr_t blkno; /* * Latched Error Info */ struct { struct scsi_sense_data _last_io_sense; u_int32_t _last_io_resid; u_int8_t _last_io_cdb[CAM_MAX_CDBLEN]; struct scsi_sense_data _last_ctl_sense; u_int32_t _last_ctl_resid; u_int8_t _last_ctl_cdb[CAM_MAX_CDBLEN];#define last_io_sense errinfo._last_io_sense#define last_io_resid errinfo._last_io_resid#define last_io_cdb errinfo._last_io_cdb#define last_ctl_sense errinfo._last_ctl_sense#define last_ctl_resid errinfo._last_ctl_resid#define last_ctl_cdb errinfo._last_ctl_cdb } errinfo; /* * Misc other flags/state */ u_int32_t : 31, ctrl_mode : 1; /* control device open */};struct sa_quirk_entry { struct scsi_inquiry_pattern inq_pat; /* matching pattern */ sa_quirks quirks; /* specific quirk type */ u_int32_t prefblk; /* preferred blocksize when in fixed mode */};static struct sa_quirk_entry sa_quirk_table[] ={ { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", "Python 25601*", "*"}, SA_QUIRK_NOCOMP, 0 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", "VIPER 150*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "ARCHIVE", "VIPER 2525*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", "T20*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", "T4000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "HP", "HP-88780*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY", "*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "M4 DATA", "123107 SCSI*", "*"}, SA_QUIRK_VARIABLE|SA_QUIRK_2FM, 0 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", " TDC 3600", "U07:"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", " TDC 4200", "*"}, SA_QUIRK_NOCOMP|SA_QUIRK_1FM, 512 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", " SLR*", "*"}, SA_QUIRK_1FM, 0 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "5525ES*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 512 }, { { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "51000*", "*"}, SA_QUIRK_FIXED|SA_QUIRK_1FM, 1024 }};static d_open_t saopen;static d_read_t saread;static d_write_t sawrite;static d_close_t saclose;static d_strategy_t sastrategy;static d_ioctl_t saioctl;static periph_init_t sainit;static periph_ctor_t saregister;static periph_oninv_t saoninvalidate;static periph_dtor_t sacleanup;static periph_start_t sastart;static void saasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg);static void sadone(struct cam_periph *periph, union ccb *start_ccb);static int saerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags);static int sacheckeod(struct cam_periph *periph);static int sagetparams(struct cam_periph *periph, sa_params params_to_get, u_int32_t *blocksize, u_int8_t *density, u_int32_t *numblocks, int *buff_mode, u_int8_t *write_protect, u_int8_t *speed, int *comp_supported, int *comp_enabled, u_int32_t *comp_algorithm, sa_comp_t *comp_page);static int sasetparams(struct cam_periph *periph, sa_params params_to_set, u_int32_t blocksize, u_int8_t density, u_int32_t comp_algorithm, u_int32_t sense_flags);static void saprevent(struct cam_periph *periph, int action);static int sarewind(struct cam_periph *periph);static int saspace(struct cam_periph *periph, int count, scsi_space_code code);static int samount(struct cam_periph *, int, dev_t);static int saretension(struct cam_periph *periph);static int sareservereleaseunit(struct cam_periph *periph, int reserve);static int saloadunload(struct cam_periph *periph, int load);static int saerase(struct cam_periph *periph, int longerase);static int sawritefilemarks(struct cam_periph *periph, int nmarks, int setmarks);static int sardpos(struct cam_periph *periph, int, u_int32_t *);static int sasetpos(struct cam_periph *periph, int, u_int32_t *);static struct periph_driver sadriver ={ sainit, "sa", TAILQ_HEAD_INITIALIZER(sadriver.units), /* generation */ 0};DATA_SET(periphdriver_set, sadriver);/* units are bits 4-7, 16-21 (1024 units) */#define SAUNIT(DEV) \ (((minor(DEV) & 0xF0) >> 4) | ((minor(DEV) & 0x3f0000) >> 16))#define SAMODE(z) ((minor(z) & 0x3))#define SADENSITY(z) (((minor(z) >> 2) & 0x3))#define SA_IS_CTRL(z) (minor(z) & (1 << 29))/* For 2.2-stable support */#ifndef D_TAPE#define D_TAPE 0#endif#define SA_CDEV_MAJOR 14#define SA_BDEV_MAJOR 5static struct cdevsw sa_cdevsw = { /*d_open*/ saopen, /*d_close*/ saclose, /*d_read*/ saread, /*d_write*/ sawrite, /*d_ioctl*/ saioctl, /*d_stop*/ nostop, /*d_reset*/ noreset, /*d_devtotty*/ nodevtotty, /*d_poll*/ seltrue, /*d_mmap*/ nommap, /*d_strategy*/ sastrategy, /*d_name*/ "sa", /*d_spare*/ NULL, /*d_maj*/ -1, /*d_dump*/ nodump, /*d_psize*/ nopsize, /*d_flags*/ D_TAPE, /*d_maxio*/ 0, /*b_maj*/ -1};static struct extend_array *saperiphs;static intsaopen(dev_t dev, int flags, int fmt, struct proc *p){ struct cam_periph *periph; struct sa_softc *softc; int unit; int mode; int density; int error; int s; unit = SAUNIT(dev); mode = SAMODE(dev); density = SADENSITY(dev); periph = cam_extend_get(saperiphs, unit); if (periph == NULL) return (ENXIO); softc = (struct sa_softc *)periph->softc; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, ("saopen(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags)); s = splsoftcam(); if (SA_IS_CTRL(dev)) { softc->ctrl_mode = 1; (void) splx(s); return (0); } if (softc->flags & SA_FLAG_INVALID) { splx(s); return(ENXIO); } if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { splx(s); return (error); /* error code from tsleep */ } splx(s); if ((softc->flags & SA_FLAG_OPEN) == 0) { if (cam_periph_acquire(periph) != CAM_REQ_CMP) return(ENXIO); if ((error = sareservereleaseunit(periph, TRUE)) != 0) { cam_periph_unlock(periph); cam_periph_release(periph); return(error); } } if (error == 0) { if ((softc->flags & SA_FLAG_OPEN) != 0) { error = EBUSY; } if (error == 0) error = samount(periph, flags, dev); /* Perform other checking... */ } if (error == 0) { saprevent(periph, PR_PREVENT); softc->flags |= SA_FLAG_OPEN; } cam_periph_unlock(periph); return (error);}static intsaclose(dev_t dev, int flag, int fmt, struct proc *p){ struct cam_periph *periph; struct sa_softc *softc; int unit, mode, error, writing, tmp; int closedbits = SA_FLAG_OPEN; unit = SAUNIT(dev); mode = SAMODE(dev); periph = cam_extend_get(saperiphs, unit); if (periph == NULL) return (ENXIO); softc = (struct sa_softc *)periph->softc; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, ("saclose(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags)); if (SA_IS_CTRL(dev)) { softc->ctrl_mode = 0; return (0); } if ((error = cam_periph_lock(periph, PRIBIO)) != 0) { return (error); } /* * Were we writing the tape? */ writing = (softc->flags & SA_FLAG_TAPE_WRITTEN) != 0; /* * See whether or not we need to write filemarks. If this * fails, we probably have to assume we've lost tape * position. */ error = sacheckeod(periph); if (error) { xpt_print_path(periph->path); printf("failed to write terminating filemark(s)\n"); softc->flags |= SA_FLAG_TAPE_FROZEN; } /* * Whatever we end up doing, allow users to eject tapes from here on. */ saprevent(periph, PR_ALLOW); /* * Decide how to end... */ switch (mode) { case SA_MODE_OFFLINE: /* * An 'offline' close is an unconditional release of * frozen && mount conditions, irrespective of whether * these operations succeeded. The reason for this is * to allow at least some kind of programmatic way * around our state getting all fouled up. If somebody * issues an 'offline' command, that will be allowed * to clear state.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?