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

📄 st.c

📁 linux0.99源代码用于研究linux操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  SCSI Tape Driver for Linux  Version 0.02 for Linux 0.98.4 and Eric Youngdale's new scsi driver  History:  Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.  Features:  - support for different block sizes and internal buffering  - *nix-style ioctl with codes from mtio.h from the QIC-02 driver by    Hennus Bergman (command MTSETBLK added)  - character device  - rewind and non-rewind devices  - capability to handle several tape drives simultaneously  - one buffer if one drive, two buffers if more than one drive (limits the    number of simultaneously open drives to two)  - write behind  - seek and tell (Tandberg compatible and SCSI-2)  Devices:  Autorewind devices have minor numbers equal to the tape numbers (0 > ).  Nonrewind device has the minor number equal to tape number + 128.  Problems:  The end of media detection may not work correctly because of the buffering.  If you want to do multiple tape backups relying on end of tape detection,  you should disable write behind and in addition to that check that the  tapes are readable.  Kai Makisara, Nov 9, 1992  email makisara@vtinsx.ins.vtt.fi or                                    Kai.Makisara@vtt.fi  Last changes Dec 6, 1992.*/#include <linux/fs.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/mtio.h>#include <linux/ioctl.h>#include <linux/fcntl.h>#include <asm/segment.h>#include <asm/system.h>#define MAJOR_NR 9#include "../blk.h"#include "scsi.h"#include "st.h"#define MAX_RETRIES 5#define NO_TAPE  NOT_READY/* Uncomment the following if you want the rewind, etc. commands return   before command completion. *//* #define ST_NOWAIT *//* #define DEBUG */#define ST_TIMEOUT 2000#define ST_LONG_TIMEOUT 200000/* Number of ST_BLOCK_SIZE blocks in the buffers */#define ST_BUFFER_BLOCKS 64/* Write-behind can be disabled by setting ST_WRITE_THRESHOLD_BLOCKS equal to or   larger than ST_BUFFER_BLOCKS */#define ST_WRITE_THRESHOLD_BLOCKS 60#define ST_BLOCK_SIZE 512#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_BLOCK_SIZE)#define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_BLOCK_SIZE)static int st_nbr_buffers;static ST_buffer *st_buffers[2];static Scsi_Tape * scsi_tapes;int NR_ST=0;int MAX_ST=0;static int st_int_ioctl(struct inode * inode,struct file * file,	     unsigned int cmd_in, unsigned int arg);/* Wakeup from interrupt */static void st_sleep_done (Scsi_Cmnd * SCpnt){  int st_nbr;  if ((st_nbr = SCpnt->request.dev) < NR_ST && st_nbr >= 0) {    if (scsi_tapes[st_nbr].buffer->writing &&	(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&	(SCpnt->sense_buffer[2] & 0x40))      scsi_tapes[st_nbr].buffer->last_result = 0x7fffffff;    else      scsi_tapes[st_nbr].buffer->last_result = SCpnt->result;    if (scsi_tapes[st_nbr].buffer->writing)      SCpnt->request.dev = -1;    else      SCpnt->request.dev = 0xffff;    if (scsi_tapes[st_nbr].buffer->writing <= 0)      wake_up( &scsi_tapes[st_nbr].waiting );  }#ifdef DEBUG  else    printk("st?: Illegal interrupt device %x\n", st_nbr);#endif}#ifdef DEBUG/* Print sense information */static void decode_sns(int dev, char *sense_buffer){   static char *snstext[] = {   "None","Recovered Error","Not Ready","Medium Error","Hardware Error",   "Illegal Request","Unit Attention","Data Protect","Blank Check",   "Key=E","Key=F","Filemark","End-Of-Medium","Incorrect Block Length",   "14","15"};   if (sense_buffer[0]!=0) {      if ((sense_buffer[0] & 0x70) == 0x70) {         if (sense_buffer[2] & 0x80) printk( "FMK ");         if (sense_buffer[2] & 0x40) printk( "EOM ");         if (sense_buffer[2] & 0x20) printk( "ILI ");        printk( "st%d: sense key %s\n", dev, snstext[sense_buffer[2] & 0x0f]);      } else {      if (sense_buffer[0] < 15)	printk("st%d: old sense key %s\n", dev, snstext[sense_buffer[0] & 0x0f]);      else	printk("st%d: sns = %2x %2x\n", dev, sense_buffer[0], sense_buffer[2]);      }   }   return;}#endif/* Convert the result to success code */static int st_chk_result(int dev, int result, char *sense){  if (!result)    return 0;#ifdef DEBUG  printk("st%d: Error: %x\n", dev, result);  decode_sns(dev, sense);#endif  if ((sense[0] & 0x70) == 0x70 &&       ((sense[2] & 0x80) /* || ((sense[2] & 0x0f) == 8) */ ))    return 0;  return (-EIO);}#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS/* Handle the write-behind checking */static void write_behind_check(int dev){  cli();  if (scsi_tapes[dev].buffer->last_result < 0) {    scsi_tapes[dev].buffer->writing = (- scsi_tapes[dev].buffer->writing);    sleep_on( &scsi_tapes[dev].waiting );    scsi_tapes[dev].buffer->writing = (- scsi_tapes[dev].buffer->writing);  }  sti();  if (scsi_tapes[dev].buffer->writing < scsi_tapes[dev].buffer->buffer_bytes)    memcpy(scsi_tapes[dev].buffer->b_data,	   scsi_tapes[dev].buffer->b_data + scsi_tapes[dev].buffer->writing,	   scsi_tapes[dev].buffer->buffer_bytes -	   scsi_tapes[dev].buffer->writing);  scsi_tapes[dev].buffer->buffer_bytes -= scsi_tapes[dev].buffer->writing;  scsi_tapes[dev].buffer->writing = 0;  return;}#endif/* Flush the write buffer */static int flush_write_buffer(int dev){  int offset, transfer, blks;  int result;  unsigned char cmd[10];  Scsi_Cmnd *SCpnt;#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS  if (scsi_tapes[dev].buffer->writing) {    write_behind_check(dev);    if (scsi_tapes[dev].buffer->last_result) {#ifdef DEBUG      printk("st%d: Async write error %x.\n", dev,	     scsi_tapes[dev].buffer->last_result);#endif      return (-EIO);    }  }#endif  result = 0;  if (scsi_tapes[dev].dirty==1) {    SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1);    offset = scsi_tapes[dev].buffer->buffer_bytes;    transfer = ((offset + scsi_tapes[dev].block_size - 1) /		scsi_tapes[dev].block_size) * scsi_tapes[dev].block_size;#ifdef DEBUG    printk("st%d: Flushing %d bytes.\n", dev, transfer);#endif    memset(scsi_tapes[dev].buffer->b_data + offset, 0, transfer - offset);    SCpnt->sense_buffer[0] = 0;    memset(cmd, 0, 10);    cmd[0] = WRITE_6;    cmd[1] = 1;    blks = transfer / scsi_tapes[dev].block_size;    cmd[2] = blks >> 16;    cmd[3] = blks >> 8;    cmd[4] = blks;    SCpnt->request.dev = dev;    scsi_do_cmd (SCpnt,		 (void *) cmd, scsi_tapes[dev].buffer->b_data, transfer,		 st_sleep_done, ST_TIMEOUT, MAX_RETRIES);    if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting );    if (SCpnt->result != 0) {      printk("st%d: Error on flush:\n", dev);#ifdef DEBUG      st_chk_result(dev, SCpnt->result, SCpnt->sense_buffer);#endif      result = (-EIO);    }    else {      scsi_tapes[dev].dirty = 0;      scsi_tapes[dev].buffer->buffer_bytes = 0;    }    SCpnt->request.dev = -1;  /* Mark as not busy */  }  return result;}/* Flush the tape buffer. The tape will be positioned correctly unless   seek_next is true. */static int flush_buffer(struct inode * inode, struct file * filp,			int seek_next){  int dev;  int backspace, result;  dev = inode->i_rdev & 127;  if (scsi_tapes[dev].rw == 2)  /* Writing */    return flush_write_buffer(dev);  backspace = (scsi_tapes[dev].buffer->buffer_bytes +    scsi_tapes[dev].buffer->read_pointer) / scsi_tapes[dev].block_size -      (scsi_tapes[dev].buffer->read_pointer + scsi_tapes[dev].block_size - 1) /	scsi_tapes[dev].block_size;  scsi_tapes[dev].buffer->buffer_bytes = 0;  scsi_tapes[dev].buffer->read_pointer = 0;  result = 0;  if (!seek_next && backspace > 0) {    result = st_int_ioctl(inode, filp, MTBSR, backspace);    if (!result) {      scsi_tapes[dev].eof = 0;      scsi_tapes[dev].eof_hit = 0;    }  }  return result;}/* Open the device */static int scsi_tape_open(struct inode * inode, struct file * filp){    int dev;    unsigned short flags;    int i;    unsigned char cmd[10];    Scsi_Cmnd * SCpnt;    dev = inode->i_rdev & 127;    if (dev >= NR_ST)      return (-ENXIO);    if (scsi_tapes[dev].in_use) {      printk("st%d: Device already in use.\n", dev);      return (-EBUSY);    }    /* Allocate buffer for this user */    for (i=0; i < st_nbr_buffers; i++)      if (!st_buffers[i]->in_use)	break;    if (i >= st_nbr_buffers) {      printk("st%d: No free buffers.\n", dev);      return (-EBUSY);    }    st_buffers[i]->in_use = 1;    st_buffers[i]->writing = 0;    scsi_tapes[dev].buffer = st_buffers[i];    scsi_tapes[dev].in_use = 1;    flags = filp->f_flags;    scsi_tapes[dev].write_prot = ((flags & O_ACCMODE) == O_RDONLY);    scsi_tapes[dev].dirty = 0;    scsi_tapes[dev].rw = 0;    scsi_tapes[dev].eof = 0;    scsi_tapes[dev].eof_hit = 0;    SCpnt = allocate_device(NULL, scsi_tapes[dev].device->index, 1);    if (!SCpnt) {      printk("st%d: Tape request not allocated", dev);      return (-EBUSY);    }    SCpnt->sense_buffer[0]=0;    memset ((void *) &cmd[0], 0, 10);    cmd[0] = TEST_UNIT_READY;    SCpnt->request.dev = dev;    scsi_do_cmd(SCpnt,                (void *) cmd, (void *) scsi_tapes[dev].buffer->b_data,                ST_BLOCK_SIZE, st_sleep_done, ST_LONG_TIMEOUT, MAX_RETRIES);    if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting );    if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&	(SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */#ifdef DEBUG      decode_sns(dev, SCpnt->sense_buffer);#endif      SCpnt->sense_buffer[0]=0;      memset ((void *) &cmd[0], 0, 10);      cmd[0] = TEST_UNIT_READY;      SCpnt->request.dev = dev;      scsi_do_cmd(SCpnt,		  (void *) cmd, (void *) scsi_tapes[dev].buffer->b_data,		  ST_BLOCK_SIZE, st_sleep_done, ST_LONG_TIMEOUT, MAX_RETRIES);      if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting );    }    if (SCpnt->result != 0) {#ifdef DEBUG      decode_sns(dev, SCpnt->sense_buffer);#endif      if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&	  (SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE)	printk("st%d: No tape.\n", dev);      else	printk("st%d: Error %x.\n", dev, SCpnt->result);      scsi_tapes[dev].buffer->in_use = 0;      scsi_tapes[dev].in_use = 0;      SCpnt->request.dev = -1;  /* Mark as not busy */      return (-EIO);    }    SCpnt->sense_buffer[0]=0;    memset ((void *) &cmd[0], 0, 10);    cmd[0] = READ_BLOCK_LIMITS;    SCpnt->request.dev = dev;    scsi_do_cmd(SCpnt,                (void *) cmd, (void *) scsi_tapes[dev].buffer->b_data,                ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_RETRIES);    if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting );    if (!SCpnt->result && !SCpnt->sense_buffer[0]) {      scsi_tapes[dev].max_block = (scsi_tapes[dev].buffer->b_data[1] << 16) |	(scsi_tapes[dev].buffer->b_data[2] << 8) | scsi_tapes[dev].buffer->b_data[3];      scsi_tapes[dev].min_block = (scsi_tapes[dev].buffer->b_data[4] << 8) |	scsi_tapes[dev].buffer->b_data[5];#ifdef DEBUG      printk("st%d: Block limits %d - %d bytes.\n", dev, scsi_tapes[dev].min_block,	     scsi_tapes[dev].max_block);#endif    }    else {      scsi_tapes[dev].min_block = scsi_tapes[dev].max_block = (-1);#ifdef DEBUG      printk("st%d: Can't read block limits.\n", dev);#endif    }    SCpnt->sense_buffer[0]=0;    memset ((void *) &cmd[0], 0, 10);    cmd[0] = MODE_SENSE;    cmd[4] = 12;    SCpnt->request.dev = dev;    scsi_do_cmd(SCpnt,                (void *) cmd, (void *) scsi_tapes[dev].buffer->b_data,                ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_RETRIES);    if (SCpnt->request.dev == dev) sleep_on( &scsi_tapes[dev].waiting );    i = st_chk_result(dev, SCpnt->result, SCpnt->sense_buffer);    if (i) {#ifdef DEBUG      printk("st%d: No Mode Sense.\n", dev);#endif      scsi_tapes[dev].buffer->b_data[2] =      scsi_tapes[dev].buffer->b_data[3] = 0;    }    SCpnt->request.dev = -1;  /* Mark as not busy */#ifdef DEBUG    printk("st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", dev,	   scsi_tapes[dev].buffer->b_data[0], scsi_tapes[dev].buffer->b_data[1],	   scsi_tapes[dev].buffer->b_data[2], scsi_tapes[dev].buffer->b_data[3]);#endif    if (scsi_tapes[dev].buffer->b_data[3] >= 8) {      scsi_tapes[dev].block_size = scsi_tapes[dev].buffer->b_data[9] * 65536 +

⌨️ 快捷键说明

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