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 + -
显示快捷键?