⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 st.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
/*   SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying   file README.st for more information.   History:   Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.   Contribution and ideas from several people including (in alphabetical   order) Klaus Ehrenfried, Eric Lee Green, Wolfgang Denk, Steve Hirsch,   Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer,   J"org Weule, and Eric Youngdale.   Copyright 1992 - 2000 Kai Makisara   email Kai.Makisara@metla.fi   Last modified: Mon Nov 13 21:01:09 2000 by makisara@kai.makisara.local   Some small formal changes - aeb, 950809   Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support   Reminder: write_lock_irqsave() can be replaced by write_lock() when the old SCSI   error handling will be discarded. */#include <linux/module.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/mtio.h>#include <linux/ioctl.h>#include <linux/fcntl.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <asm/dma.h>#include <asm/system.h>/* The driver prints some debugging information on the console if DEBUG   is defined and non-zero. */#define DEBUG 0#if DEBUG/* The message level for the debug messages is currently set to KERN_NOTICE   so that people can easily see the messages. Later when the debugging messages   in the drivers are more widely classified, this may be changed to KERN_DEBUG. */#define ST_DEB_MSG  KERN_NOTICE#define DEB(a) a#define DEBC(a) if (debugging) { a ; }#else#define DEB(a)#define DEBC(a)#endif#define MAJOR_NR SCSI_TAPE_MAJOR#include <linux/blk.h>#include "scsi.h"#include "hosts.h"#include <scsi/scsi_ioctl.h>#define ST_KILOBYTE 1024#include "st_options.h"#include "st.h"#include "constants.h"static int buffer_kbs;static int write_threshold_kbs;static int max_buffers = (-1);static int max_sg_segs;MODULE_AUTHOR("Kai Makisara");MODULE_DESCRIPTION("SCSI Tape Driver");MODULE_PARM(buffer_kbs, "i");MODULE_PARM(write_threshold_kbs, "i");MODULE_PARM(max_buffers, "i");MODULE_PARM(max_sg_segs, "i");#ifndef MODULEstatic struct st_dev_parm {	char *name;	int *val;} parms[] __initdata = {	{		"buffer_kbs", &buffer_kbs	},	{		"write_threshold_kbs", &write_threshold_kbs	},	{		"max_buffers", &max_buffers	},	{		"max_sg_segs", &max_sg_segs	}};#endif/* The default definitions have been moved to st_options.h */#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_KILOBYTE)#define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)/* The buffer size should fit into the 24 bits for length in the   6-byte SCSI read and write commands. */#if ST_BUFFER_SIZE >= (2 << 24 - 1)#error "Buffer size should not exceed (2 << 24 - 1) bytes!"#endifDEB( static int debugging = DEBUG; )#define MAX_RETRIES 0#define MAX_WRITE_RETRIES 0#define MAX_READY_RETRIES 5#define NO_TAPE  NOT_READY#define ST_TIMEOUT (900 * HZ)#define ST_LONG_TIMEOUT (14000 * HZ)#define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK))#define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower   24 bits) */#define SET_DENS_AND_BLK 0x10001#define ST_DEV_ARR_LUMP  6static rwlock_t st_dev_arr_lock = RW_LOCK_UNLOCKED;static int st_nbr_buffers;static ST_buffer **st_buffers = NULL;static int st_buffer_size = ST_BUFFER_SIZE;static int st_write_threshold = ST_WRITE_THRESHOLD;static int st_max_buffers = ST_MAX_BUFFERS;static int st_max_sg_segs = ST_MAX_SG;static Scsi_Tape **scsi_tapes = NULL;static int modes_defined;static ST_buffer *new_tape_buffer(int, int, int);static int enlarge_buffer(ST_buffer *, int, int);static void normalize_buffer(ST_buffer *);static int append_to_buffer(const char *, ST_buffer *, int);static int from_buffer(ST_buffer *, char *, int);static int st_init(void);static int st_attach(Scsi_Device *);static int st_detect(Scsi_Device *);static void st_detach(Scsi_Device *);static struct Scsi_Device_Template st_template ={	name:"tape", 	tag:"st", 	scsi_type:TYPE_TAPE,	major:SCSI_TAPE_MAJOR, 	detect:st_detect, 	init:st_init,	attach:st_attach, 	detach:st_detach};static int st_compression(Scsi_Tape *, int);static int find_partition(Scsi_Tape *);static int update_partition(Scsi_Tape *);static int st_int_ioctl(Scsi_Tape *, unsigned int, unsigned long);#include "osst_detect.h"#ifndef SIGS_FROM_OSST#define SIGS_FROM_OSST \	{"OnStream", "SC-", "", "osst"}, \	{"OnStream", "DI-", "", "osst"}, \	{"OnStream", "DP-", "", "osst"}, \	{"OnStream", "USB", "", "osst"}, \	{"OnStream", "FW-", "", "osst"}#endifstruct st_reject_data {	char *vendor;	char *model;	char *rev;	char *driver_hint; /* Name of the correct driver, NULL if unknown */};static struct st_reject_data reject_list[] = {	/* {"XXX", "Yy-", "", NULL},  example */	SIGS_FROM_OSST,	{NULL, }};/* If the device signature is on the list of incompatible drives, the   function returns a pointer to the name of the correct driver (if known) */static char * st_incompatible(Scsi_Device* SDp){	struct st_reject_data *rp;	for (rp=&(reject_list[0]); rp->vendor != NULL; rp++)		if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&		    !strncmp(rp->model, SDp->model, strlen(rp->model)) &&		    !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) {			if (rp->driver_hint)				return rp->driver_hint;			else				return "unknown";		}	return NULL;}/* Convert the result to success code */static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt){	int dev;	int result = SRpnt->sr_result;	unsigned char *sense = SRpnt->sr_sense_buffer, scode;	DEB(const char *stp;)	if (!result) {		sense[0] = 0;	/* We don't have sense data if this byte is zero */		return 0;	}	if (driver_byte(result) & DRIVER_SENSE)		scode = sense[2] & 0x0f;	else {		sense[0] = 0;		scode = 0;	}	dev = TAPE_NR(SRpnt->sr_request.rq_dev);        DEB(        if (debugging) {                printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",		       dev, result,		       SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],		       SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],		       SRpnt->sr_bufflen);		if (driver_byte(result) & DRIVER_SENSE)			print_req_sense("st", SRpnt);	} else ) /* end DEB */		if (!(driver_byte(result) & DRIVER_SENSE) ||		    ((sense[0] & 0x70) == 0x70 &&		     scode != NO_SENSE &&		     scode != RECOVERED_ERROR &&                     /* scode != UNIT_ATTENTION && */		     scode != BLANK_CHECK &&		     scode != VOLUME_OVERFLOW &&		     SRpnt->sr_cmnd[0] != MODE_SENSE &&		     SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) {	/* Abnormal conditions for tape */		if (driver_byte(result) & DRIVER_SENSE) {			printk(KERN_WARNING "st%d: Error with sense data: ", dev);			print_req_sense("st", SRpnt);		} else			printk(KERN_WARNING			       "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",			       dev, result, suggestion(result),                               driver_byte(result) & DRIVER_MASK, host_byte(result));	}	if ((sense[0] & 0x70) == 0x70 &&	    scode == RECOVERED_ERROR#if ST_RECOVERED_WRITE_FATAL	    && SRpnt->sr_cmnd[0] != WRITE_6	    && SRpnt->sr_cmnd[0] != WRITE_FILEMARKS#endif	    ) {		STp->recover_count++;		STp->recover_reg++;                DEB(		if (debugging) {			if (SRpnt->sr_cmnd[0] == READ_6)				stp = "read";			else if (SRpnt->sr_cmnd[0] == WRITE_6)				stp = "write";			else				stp = "ioctl";			printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp,			       STp->recover_count);		} ) /* end DEB */		if ((sense[2] & 0xe0) == 0)			return 0;	}	return (-EIO);}/* Wakeup from interrupt */static void st_sleep_done(Scsi_Cmnd * SCpnt){	unsigned int st_nbr;	int remainder;	Scsi_Tape *STp;	if ((st_nbr = TAPE_NR(SCpnt->request.rq_dev)) < st_template.nr_dev) {		read_lock(&st_dev_arr_lock);		STp = scsi_tapes[st_nbr];		read_unlock(&st_dev_arr_lock);		if ((STp->buffer)->writing &&		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&		    (SCpnt->sense_buffer[2] & 0x40)) {			/* EOM at write-behind, has all been written? */			if ((SCpnt->sense_buffer[0] & 0x80) != 0)				remainder = (SCpnt->sense_buffer[3] << 24) |                                    (SCpnt->sense_buffer[4] << 16) |				    (SCpnt->sense_buffer[5] << 8) |                                    SCpnt->sense_buffer[6];			else				remainder = 0;			if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||			    remainder > 0)				(STp->buffer)->midlevel_result = SCpnt->result; /* Error */			else				(STp->buffer)->midlevel_result = INT_MAX;	/* OK */		} else			(STp->buffer)->midlevel_result = SCpnt->result;		SCpnt->request.rq_status = RQ_SCSI_DONE;		(STp->buffer)->last_SRpnt = SCpnt->sc_request;		DEB( STp->write_pending = 0; )		up(SCpnt->request.sem);	}        DEB(	else if (debugging)		printk(KERN_ERR "st?: Illegal interrupt device %x\n", st_nbr);	) /* end DEB */}/* Do the scsi command. Waits until command performed if do_wait is true.   Otherwise write_behind_check() is used to check that the command   has finished. */static Scsi_Request * st_do_scsi(Scsi_Request * SRpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,	    int direction, int timeout, int retries, int do_wait){	unsigned char *bp;	if (SRpnt == NULL) {		SRpnt = scsi_allocate_request(STp->device);		if (SRpnt == NULL) {			DEBC( printk(KERN_ERR "st%d: Can't get SCSI request.\n",				     TAPE_NR(STp->devt)); );			if (signal_pending(current))				(STp->buffer)->syscall_result = (-EINTR);			else				(STp->buffer)->syscall_result = (-EBUSY);			return NULL;		}	}	cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0;	init_MUTEX_LOCKED(&STp->sem);	SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?	    (STp->buffer)->use_sg : 0;	if (SRpnt->sr_use_sg) {		bp = (char *) &((STp->buffer)->sg[0]);		if ((STp->buffer)->sg_segs < SRpnt->sr_use_sg)			SRpnt->sr_use_sg = (STp->buffer)->sg_segs;	} else		bp = (STp->buffer)->b_data;	SRpnt->sr_data_direction = direction;	SRpnt->sr_cmd_len = 0;	SRpnt->sr_request.sem = &(STp->sem);	SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;	SRpnt->sr_request.rq_dev = STp->devt;	scsi_do_req(SRpnt, (void *) cmd, bp, bytes,		    st_sleep_done, timeout, retries);	if (do_wait) {		down(SRpnt->sr_request.sem);		SRpnt->sr_request.sem = NULL;		(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);	}	return SRpnt;}/* Handle the write-behind checking (downs the semaphore) */static void write_behind_check(Scsi_Tape * STp){	ST_buffer *STbuffer;	ST_partstat *STps;	STbuffer = STp->buffer;        DEB(	if (STp->write_pending)		STp->nbr_waits++;	else		STp->nbr_finished++;        ) /* end DEB */	down(&(STp->sem));	(STp->buffer)->last_SRpnt->sr_request.sem = NULL;	(STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt);	scsi_release_request((STp->buffer)->last_SRpnt);	if (STbuffer->writing < STbuffer->buffer_bytes)#if 0		memcpy(STbuffer->b_data,		       STbuffer->b_data + STbuffer->writing,		       STbuffer->buffer_bytes - STbuffer->writing);#else		printk(KERN_WARNING                       "st: write_behind_check: something left in buffer!\n");#endif	STbuffer->buffer_bytes -= STbuffer->writing;	STps = &(STp->ps[STp->partition]);	if (STps->drv_block >= 0) {		if (STp->block_size == 0)			STps->drv_block++;		else			STps->drv_block += STbuffer->writing / STp->block_size;	}	STbuffer->writing = 0;	return;}/* Step over EOF if it has been inadvertently crossed (ioctl not used because   it messes up the block number). */static int cross_eof(Scsi_Tape * STp, int forward){	Scsi_Request *SRpnt;	unsigned char cmd[MAX_COMMAND_SIZE];	cmd[0] = SPACE;	cmd[1] = 0x01;		/* Space FileMarks */	if (forward) {		cmd[2] = cmd[3] = 0;		cmd[4] = 1;	} else		cmd[2] = cmd[3] = cmd[4] = 0xff;	/* -1 filemarks */	cmd[5] = 0;        DEBC(printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n",		   TAPE_NR(STp->devt), forward ? "forward" : "backward"));	SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE,			   STp->timeout, MAX_RETRIES, TRUE);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -