home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / drivers / scsi / sg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  8.6 KB  |  337 lines

  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,
  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 -ENODEV;
  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)
  73.  {
  74.   int dev=MINOR(inode->i_rdev);
  75.   int flags=filp->f_flags;
  76.   if (dev>=NR_SG)
  77.    return -ENODEV;
  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)
  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)
  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) 
  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)
  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.     memcpy_tofs(buf,device->buff,count-sizeof(struct sg_header));
  177.    }
  178.   else
  179.    count=0;
  180.   sg_free(device->buff,device->buff_len);
  181.   device->pending=0;
  182.   wake_up(&device->write_wait);
  183.   return count;
  184.  }
  185.  
  186. static void sg_command_done(Scsi_Cmnd * SCpnt)
  187.  {
  188.   int dev=SCpnt->request.dev;
  189.   struct scsi_generic *device=&scsi_generics[dev];
  190.   if (!device->pending)
  191.    {
  192.     printk("unexpected done for sg %d\n",dev);
  193.     SCpnt->request.dev=-1;
  194.     return;
  195.    }
  196.   if (SCpnt->sense_buffer[0])
  197.    {
  198.     device->header.result=EIO;
  199.    }
  200.   else
  201.    device->header.result=SCpnt->result;
  202.   device->complete=1;
  203.   SCpnt->request.dev=-1;
  204.   wake_up(&scsi_generics[dev].read_wait);
  205.  }
  206.  
  207. static int sg_write(struct inode *inode,struct file *filp,char *buf,int count)
  208.  {
  209.   int dev=MINOR(inode->i_rdev);
  210.   Scsi_Cmnd *SCpnt;
  211.   int bsize,size,amt,i;
  212.   unsigned char cmnd[MAX_COMMAND_SIZE];
  213.   struct scsi_generic *device=&scsi_generics[dev];
  214.   if ((i=verify_area(VERIFY_READ,buf,count)))
  215.    return i;
  216.   if (count<sizeof(struct sg_header))
  217.    return -EIO;
  218.   /* make sure we can fit */
  219.   while(device->pending)
  220.    {
  221.     if (filp->f_flags & O_NONBLOCK)
  222.      return -EWOULDBLOCK;
  223. #ifdef DEBUG
  224.     printk("sg_write: sleeping on pending request\n");
  225. #endif     
  226.     interruptible_sleep_on(&device->write_wait);
  227.     if (current->signal & ~current->blocked)
  228.      return -ERESTARTSYS;
  229.    }
  230.   device->pending=1;
  231.   device->complete=0;
  232.   memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
  233.   /* fix input size */
  234.   device->header.pack_len=count;
  235.   buf+=sizeof(struct sg_header);
  236.   bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len;
  237.   bsize-=sizeof(struct sg_header);
  238.   amt=bsize;
  239.   if (!bsize)
  240.    bsize++;
  241.   bsize=(bsize+511) & ~511;
  242.   if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
  243.    {
  244.     device->pending=0;
  245.     wake_up(&device->write_wait);
  246.     return -ENOMEM;
  247.    }
  248. #ifdef DEBUG
  249.   printk("allocating device\n");
  250. #endif
  251.   if (!(SCpnt=allocate_device(NULL,device->device->index, !(filp->f_flags & O_NONBLOCK))))
  252.    {
  253.     device->pending=0;
  254.     wake_up(&device->write_wait);
  255.     sg_free(device->buff,device->buff_len);
  256.     return -EWOULDBLOCK;
  257.    } 
  258. #ifdef DEBUG
  259.   printk("device allocated\n");
  260. #endif    
  261.   /* now issue command */
  262.   SCpnt->request.dev=dev;
  263.   SCpnt->sense_buffer[0]=0;
  264.   size=COMMAND_SIZE(get_fs_byte(buf));
  265.   memcpy_fromfs(cmnd,buf,size);
  266.   buf+=size;
  267.   memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
  268.   cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5);
  269. #ifdef DEBUG
  270.   printk("do cmd\n");
  271. #endif
  272.   scsi_do_cmd (SCpnt,(void *) cmnd,
  273.                (void *) device->buff,amt,sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
  274. #ifdef DEBUG
  275.   printk("done cmd\n");
  276. #endif               
  277.   return count;
  278.  }
  279.  
  280. static struct file_operations sg_fops = {
  281.    NULL,            /* lseek */
  282.    sg_read,         /* read */
  283.    sg_write,        /* write */
  284.    NULL,            /* readdir */
  285.    NULL,            /* select */
  286.    sg_ioctl,        /* ioctl */
  287.    NULL,            /* mmap */
  288.    sg_open,         /* open */
  289.    sg_close,        /* release */
  290.    NULL            /* fsync */
  291. };
  292.  
  293.  
  294. /* Driver initialization */
  295. unsigned long sg_init(unsigned long mem_start, unsigned long mem_end)
  296.  {
  297.   if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) 
  298.    {
  299.     printk("Unable to get major %d for generic SCSI device\n",
  300.        SCSI_GENERIC_MAJOR);
  301.     return mem_start;
  302.    }
  303.   if (NR_SG == 0) return mem_start;
  304.  
  305. #ifdef DEBUG
  306.   printk("sg: Init generic device.\n");
  307. #endif
  308.  
  309. #ifdef SG_BIG_BUFF
  310.   big_buff= (char *) mem_start;
  311.   mem_start+=SG_BIG_BUFF;
  312. #endif
  313.   return mem_start;
  314.  }
  315.  
  316. unsigned long sg_init1(unsigned long mem_start, unsigned long mem_end)
  317.  {
  318.   scsi_generics = (struct scsi_generic *) mem_start;
  319.   mem_start += MAX_SG * sizeof(struct scsi_generic);
  320.   return mem_start;
  321.  };
  322.  
  323. void sg_attach(Scsi_Device * SDp)
  324.  {
  325.   if(NR_SG >= MAX_SG) 
  326.    panic ("scsi_devices corrupt (sg)");
  327.   scsi_generics[NR_SG].device=SDp;
  328.   scsi_generics[NR_SG].users=0;
  329.   scsi_generics[NR_SG].generic_wait=NULL;
  330.   scsi_generics[NR_SG].read_wait=NULL;
  331.   scsi_generics[NR_SG].write_wait=NULL;
  332.   scsi_generics[NR_SG].exclude=0;
  333.   scsi_generics[NR_SG].pending=0;
  334.   scsi_generics[NR_SG].timeout=SG_DEFAULT_TIMEOUT;
  335.   NR_SG++;
  336.  };
  337.