root/drivers/scsi/sg.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sg_ioctl
  2. sg_open
  3. sg_close
  4. sg_malloc
  5. sg_free
  6. sg_read
  7. sg_command_done
  8. sg_write
  9. sg_init
  10. sg_init1
  11. sg_attach

   1 /*
   2    History:
   3     Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user 
   4      process control of SCSI devices.
   5     Development Sponsored by Killy Corp. NY NY
   6     
   7     Borrows code from st driver.
   8 */
   9 
  10 #include <linux/fs.h>
  11 #include <linux/kernel.h>
  12 #include <linux/sched.h>
  13 #include <linux/string.h>
  14 #include <linux/errno.h>
  15 #include <linux/mtio.h>
  16 #include <linux/ioctl.h>
  17 #include <linux/fcntl.h>
  18 #include <asm/io.h>
  19 #include <asm/segment.h>
  20 #include <asm/system.h>
  21 
  22 #include "../block/blk.h"
  23 #include "scsi.h"
  24 #include "scsi_ioctl.h"
  25 #include "sg.h"
  26 
  27 int NR_SG=0;
  28 int MAX_SG=0;
  29 
  30 #ifdef SG_BIG_BUFF
  31 static char *big_buff;
  32 static struct wait_queue *big_wait;   /* wait for buffer available */
  33 static int big_inuse=0;
  34 #endif
  35 
  36 struct scsi_generic
  37  {
  38   Scsi_Device *device;
  39   int users;   /* how many people have it open? */
  40   struct wait_queue *generic_wait; /* wait for device to be available */
  41   struct wait_queue *read_wait;    /* wait for response */
  42   struct wait_queue *write_wait;   /* wait for free buffer */
  43   int timeout; /* current default value for device */
  44   int buff_len; /* length of current buffer */
  45   char *buff;   /* the buffer */
  46   struct sg_header header; /* header of pending command */
  47   char exclude; /* opened for exclusive access */
  48   char pending;  /* don't accept writes now */
  49   char complete; /* command complete allow a read */
  50  };
  51 
  52 static struct scsi_generic *scsi_generics=NULL;
  53 
  54 static int sg_ioctl(struct inode * inode,struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
  55              unsigned int cmd_in, unsigned long arg)
  56  {
  57   int dev = MINOR(inode->i_rdev);
  58   if ((dev<0) || (dev>=NR_SG))
  59    return -ENXIO;
  60   switch(cmd_in)
  61    {
  62     case SG_SET_TIMEOUT:
  63      scsi_generics[dev].timeout=get_fs_long((int *) arg);
  64      return 0;
  65     case SG_GET_TIMEOUT:
  66      return scsi_generics[dev].timeout;
  67     default:
  68      return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
  69    }
  70  }
  71 
  72 static int sg_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
  73  {
  74   int dev=MINOR(inode->i_rdev);
  75   int flags=filp->f_flags;
  76   if (dev>=NR_SG)
  77    return -ENXIO;
  78   if (O_RDWR!=(flags & O_ACCMODE))
  79    return -EACCES;
  80   if (flags & O_EXCL)
  81    {
  82     while(scsi_generics[dev].users)
  83      {
  84       if (flags & O_NONBLOCK)
  85        return -EBUSY;
  86       interruptible_sleep_on(&scsi_generics[dev].generic_wait);
  87       if (current->signal & ~current->blocked)
  88        return -ERESTARTSYS;
  89      }
  90     scsi_generics[dev].exclude=1;
  91    }
  92   else
  93    while(scsi_generics[dev].exclude)
  94     {
  95      if (flags & O_NONBLOCK)
  96       return -EBUSY;
  97      interruptible_sleep_on(&scsi_generics[dev].generic_wait);
  98      if (current->signal & ~current->blocked)
  99       return -ERESTARTSYS;
 100     }
 101   if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
 102    {
 103     scsi_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
 104     scsi_generics[dev].pending=0;
 105    }
 106   if (!scsi_generics[dev].users)
 107    scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT;
 108   scsi_generics[dev].users++;
 109   return 0;
 110  }
 111 
 112 static void sg_close(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 113  {
 114   int dev=MINOR(inode->i_rdev);
 115   scsi_generics[dev].users--;
 116   scsi_generics[dev].exclude=0;
 117   wake_up(&scsi_generics[dev].generic_wait);
 118  }
 119 
 120 static char *sg_malloc(int size)
     /* [previous][next][first][last][top][bottom][index][help] */
 121  {
 122   if (size<=4096)
 123    return (char *) scsi_malloc(size);
 124 #ifdef SG_BIG_BUFF
 125   if (size<SG_BIG_BUFF)
 126    {
 127     while(big_inuse)
 128      {
 129       interruptible_sleep_on(&big_wait);
 130       if (current->signal & ~current->blocked)
 131        return NULL;
 132      }
 133     big_inuse=1;
 134     return big_buff;
 135    }
 136 #endif   
 137   return NULL;
 138  }
 139 
 140 static void sg_free(char *buff,int size) 
     /* [previous][next][first][last][top][bottom][index][help] */
 141  {
 142 #ifdef SG_BIG_BUFF
 143   if (buff==big_buff)
 144    {
 145     big_inuse=0;
 146     wake_up(&big_wait);
 147     return;
 148    }
 149 #endif
 150   scsi_free(buff,size);
 151  }
 152 
 153 static int sg_read(struct inode *inode,struct file *filp,char *buf,int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 154  {
 155   int dev=MINOR(inode->i_rdev);
 156   int i;
 157   struct scsi_generic *device=&scsi_generics[dev];
 158   if ((i=verify_area(VERIFY_WRITE,buf,count)))
 159    return i;
 160   while(!device->pending || !device->complete)
 161    {
 162     if (filp->f_flags & O_NONBLOCK)
 163      return -EWOULDBLOCK;
 164     interruptible_sleep_on(&device->read_wait);
 165     if (current->signal & ~current->blocked)
 166      return -ERESTARTSYS;
 167    }
 168   device->header.pack_len=device->header.reply_len;
 169   device->header.result=0;
 170   if (count>=sizeof(struct sg_header))
 171    {
 172     memcpy_tofs(buf,&device->header,sizeof(struct sg_header));
 173     buf+=sizeof(struct sg_header);
 174     if (count>device->header.pack_len)
 175      count=device->header.pack_len;
 176     if (count > sizeof(struct sg_header)) {
 177        memcpy_tofs(buf,device->buff,count-sizeof(struct sg_header));
 178     }
 179    }
 180   else
 181    count=0;
 182   sg_free(device->buff,device->buff_len);
 183   device->pending=0;
 184   wake_up(&device->write_wait);
 185   return count;
 186  }
 187 
 188 static void sg_command_done(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 189  {
 190   int dev=SCpnt->request.dev;
 191   struct scsi_generic *device=&scsi_generics[dev];
 192   if (!device->pending)
 193    {
 194     printk("unexpected done for sg %d\n",dev);
 195     SCpnt->request.dev=-1;
 196     return;
 197    }
 198   memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
 199   if (SCpnt->sense_buffer[0])
 200    {
 201     device->header.result=EIO;
 202    }
 203   else
 204    device->header.result=SCpnt->result;
 205   device->complete=1;
 206   SCpnt->request.dev=-1;
 207   wake_up(&scsi_generics[dev].read_wait);
 208  }
 209 
 210 static int sg_write(struct inode *inode,struct file *filp,char *buf,int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 211  {
 212   int dev=MINOR(inode->i_rdev);
 213   Scsi_Cmnd *SCpnt;
 214   int bsize,size,amt,i;
 215   unsigned char cmnd[MAX_COMMAND_SIZE];
 216   struct scsi_generic *device=&scsi_generics[dev];
 217 
 218   if ((i=verify_area(VERIFY_READ,buf,count)))
 219    return i;
 220   if (count<sizeof(struct sg_header))
 221    return -EIO;
 222   /* make sure we can fit */
 223   while(device->pending)
 224    {
 225     if (filp->f_flags & O_NONBLOCK)
 226      return -EWOULDBLOCK;
 227 #ifdef DEBUG
 228     printk("sg_write: sleeping on pending request\n");
 229 #endif     
 230     interruptible_sleep_on(&device->write_wait);
 231     if (current->signal & ~current->blocked)
 232      return -ERESTARTSYS;
 233    }
 234   device->pending=1;
 235   device->complete=0;
 236   memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
 237   /* fix input size */
 238   device->header.pack_len=count;
 239   buf+=sizeof(struct sg_header);
 240   bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len;
 241   bsize-=sizeof(struct sg_header);
 242   amt=bsize;
 243   if (!bsize)
 244    bsize++;
 245   bsize=(bsize+511) & ~511;
 246   if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
 247    {
 248     device->pending=0;
 249     wake_up(&device->write_wait);
 250     return -ENOMEM;
 251    }
 252 #ifdef DEBUG
 253   printk("allocating device\n");
 254 #endif
 255   if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
 256    {
 257     device->pending=0;
 258     wake_up(&device->write_wait);
 259     sg_free(device->buff,device->buff_len);
 260     return -EWOULDBLOCK;
 261    } 
 262 #ifdef DEBUG
 263   printk("device allocated\n");
 264 #endif    
 265   /* now issue command */
 266   SCpnt->request.dev=dev;
 267   SCpnt->sense_buffer[0]=0;
 268   size=COMMAND_SIZE(get_fs_byte(buf));
 269   memcpy_fromfs(cmnd,buf,size);
 270   buf+=size;
 271   memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
 272   cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5);
 273 #ifdef DEBUG
 274   printk("do cmd\n");
 275 #endif
 276   scsi_do_cmd (SCpnt,(void *) cmnd,
 277                (void *) device->buff,amt,sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
 278 #ifdef DEBUG
 279   printk("done cmd\n");
 280 #endif               
 281   return count;
 282  }
 283 
 284 static struct file_operations sg_fops = {
 285    NULL,            /* lseek */
 286    sg_read,         /* read */
 287    sg_write,        /* write */
 288    NULL,            /* readdir */
 289    NULL,            /* select */
 290    sg_ioctl,        /* ioctl */
 291    NULL,            /* mmap */
 292    sg_open,         /* open */
 293    sg_close,        /* release */
 294    NULL             /* fsync */
 295 };
 296 
 297 
 298 /* Driver initialization */
 299 unsigned long sg_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 300  {
 301   if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) 
 302    {
 303     printk("Unable to get major %d for generic SCSI device\n",
 304            SCSI_GENERIC_MAJOR);
 305     return mem_start;
 306    }
 307   if (NR_SG == 0) return mem_start;
 308 
 309 #ifdef DEBUG
 310   printk("sg: Init generic device.\n");
 311 #endif
 312 
 313 #ifdef SG_BIG_BUFF
 314   big_buff= (char *) mem_start;
 315   mem_start+=SG_BIG_BUFF;
 316 #endif
 317   return mem_start;
 318  }
 319 
 320 void sg_init1()
     /* [previous][next][first][last][top][bottom][index][help] */
 321  {
 322   scsi_generics = (struct scsi_generic *) 
 323     scsi_init_malloc(MAX_SG * sizeof(struct scsi_generic));
 324  };
 325 
 326 void sg_attach(Scsi_Device * SDp)
     /* [previous][next][first][last][top][bottom][index][help] */
 327  {
 328   if(NR_SG >= MAX_SG) 
 329    panic ("scsi_devices corrupt (sg)");
 330   scsi_generics[NR_SG].device=SDp;
 331   scsi_generics[NR_SG].users=0;
 332   scsi_generics[NR_SG].generic_wait=NULL;
 333   scsi_generics[NR_SG].read_wait=NULL;
 334   scsi_generics[NR_SG].write_wait=NULL;
 335   scsi_generics[NR_SG].exclude=0;
 336   scsi_generics[NR_SG].pending=0;
 337   scsi_generics[NR_SG].timeout=SG_DEFAULT_TIMEOUT;
 338   NR_SG++;
 339  };

/* [previous][next][first][last][top][bottom][index][help] */