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_detect
  10. sg_init
  11. sg_attach
  12. sg_detach
  13. init_module
  14. cleanup_module

   1 /*
   2  *  History:
   3  *  Started: Aug 9 by Lawrence Foard (entropy@world.std.com), 
   4  *           to allow user process control of SCSI devices.
   5  *  Development Sponsored by Killy Corp. NY NY
   6  *   
   7  *  Borrows code from st driver.
   8  */
   9 #ifdef MODULE
  10 #include <linux/autoconf.h>
  11 #include <linux/module.h>
  12 #include <linux/version.h>
  13 #endif /* MODULE */
  14 
  15 #include <linux/fs.h>
  16 #include <linux/kernel.h>
  17 #include <linux/sched.h>
  18 #include <linux/string.h>
  19 #include <linux/mm.h>
  20 #include <linux/errno.h>
  21 #include <linux/mtio.h>
  22 #include <linux/ioctl.h>
  23 #include <linux/fcntl.h>
  24 #include <asm/io.h>
  25 #include <asm/segment.h>
  26 #include <asm/system.h>
  27 
  28 #include "../block/blk.h"
  29 #include "scsi.h"
  30 #include "hosts.h"
  31 #include "scsi_ioctl.h"
  32 #include "sg.h"
  33 
  34 static void sg_init(void);
  35 static int sg_attach(Scsi_Device *);
  36 static int sg_detect(Scsi_Device *);
  37 static void sg_detach(Scsi_Device *);
  38 
  39 
  40 struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff, 
  41                                                SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
  42                                                sg_detect, sg_init,
  43                                                NULL, sg_attach, sg_detach};
  44 
  45 #ifdef SG_BIG_BUFF
  46 static char *big_buff = NULL;
  47 static struct wait_queue *big_wait;   /* wait for buffer available */
  48 static int big_inuse=0;
  49 #endif
  50 
  51 struct scsi_generic
  52 {
  53     Scsi_Device *device;
  54     int users;   /* how many people have it open? */
  55     struct wait_queue *generic_wait; /* wait for device to be available */
  56     struct wait_queue *read_wait;    /* wait for response */
  57     struct wait_queue *write_wait;   /* wait for free buffer */
  58     int timeout; /* current default value for device */
  59     int buff_len; /* length of current buffer */
  60     char *buff;   /* the buffer */
  61     struct sg_header header; /* header of pending command */
  62     char exclude; /* opened for exclusive access */
  63     char pending;  /* don't accept writes now */
  64     char complete; /* command complete allow a read */
  65 };
  66 
  67 static struct scsi_generic *scsi_generics=NULL;
  68 static void sg_free(char *buff,int size);
  69 
  70 static int sg_ioctl(struct inode * inode,struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
  71                     unsigned int cmd_in, unsigned long arg)
  72 {
  73     int dev = MINOR(inode->i_rdev);
  74     if ((dev<0) || (dev>=sg_template.dev_max))
  75         return -ENXIO;
  76     switch(cmd_in)
  77     {
  78     case SG_SET_TIMEOUT:
  79         scsi_generics[dev].timeout=get_user((int *) arg);
  80         return 0;
  81     case SG_GET_TIMEOUT:
  82         return scsi_generics[dev].timeout;
  83     default:
  84         return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
  85     }
  86 }
  87 
  88 static int sg_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90     int dev=MINOR(inode->i_rdev);
  91     int flags=filp->f_flags;
  92     if (dev>=sg_template.dev_max || !scsi_generics[dev].device)
  93         return -ENXIO;
  94     if (O_RDWR!=(flags & O_ACCMODE))
  95         return -EACCES;
  96     if (flags & O_EXCL)
  97     {
  98         while(scsi_generics[dev].users)
  99         {
 100             if (flags & O_NONBLOCK)
 101                 return -EBUSY;
 102             interruptible_sleep_on(&scsi_generics[dev].generic_wait);
 103             if (current->signal & ~current->blocked)
 104                 return -ERESTARTSYS;
 105         }
 106         scsi_generics[dev].exclude=1;
 107     }
 108     else
 109         while(scsi_generics[dev].exclude)
 110         {
 111             if (flags & O_NONBLOCK)
 112                 return -EBUSY;
 113             interruptible_sleep_on(&scsi_generics[dev].generic_wait);
 114             if (current->signal & ~current->blocked)
 115                 return -ERESTARTSYS;
 116         }
 117     if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
 118     {
 119         if (scsi_generics[dev].buff != NULL)
 120             sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
 121         scsi_generics[dev].buff=NULL;
 122         scsi_generics[dev].pending=0;
 123     }
 124     if (!scsi_generics[dev].users)
 125         scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT;
 126     if (scsi_generics[dev].device->host->hostt->usage_count)
 127         (*scsi_generics[dev].device->host->hostt->usage_count)++;
 128     if(sg_template.usage_count) (*sg_template.usage_count)++;
 129     scsi_generics[dev].users++;
 130     return 0;
 131 }
 132 
 133 static void sg_close(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135     int dev=MINOR(inode->i_rdev);
 136     scsi_generics[dev].users--;
 137     if (scsi_generics[dev].device->host->hostt->usage_count)
 138         (*scsi_generics[dev].device->host->hostt->usage_count)--;
 139     if(sg_template.usage_count) (*sg_template.usage_count)--;
 140     scsi_generics[dev].exclude=0;
 141     wake_up(&scsi_generics[dev].generic_wait);
 142 }
 143 
 144 static char *sg_malloc(int size)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146     if (size<=4096)
 147         return (char *) scsi_malloc(size);
 148 #ifdef SG_BIG_BUFF
 149     if (size<SG_BIG_BUFF)
 150     {
 151         while(big_inuse)
 152         {
 153             interruptible_sleep_on(&big_wait);
 154             if (current->signal & ~current->blocked)
 155                 return NULL;
 156         }
 157         big_inuse=1;
 158         return big_buff;
 159     }
 160 #endif   
 161     return NULL;
 162 }
 163 
 164 static void sg_free(char *buff,int size) 
     /* [previous][next][first][last][top][bottom][index][help] */
 165 {
 166 #ifdef SG_BIG_BUFF
 167     if (buff==big_buff)
 168     {
 169         big_inuse=0;
 170         wake_up(&big_wait);
 171         return;
 172     }
 173 #endif
 174     scsi_free(buff,size);
 175 }
 176 
 177 static int sg_read(struct inode *inode,struct file *filp,char *buf,int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 178 {
 179     int dev=MINOR(inode->i_rdev);
 180     int i;
 181     struct scsi_generic *device=&scsi_generics[dev];
 182     if ((i=verify_area(VERIFY_WRITE,buf,count)))
 183         return i;
 184     while(!device->pending || !device->complete)
 185     {
 186         if (filp->f_flags & O_NONBLOCK)
 187             return -EWOULDBLOCK;
 188         interruptible_sleep_on(&device->read_wait);
 189         if (current->signal & ~current->blocked)
 190             return -ERESTARTSYS;
 191     }
 192     device->header.pack_len=device->header.reply_len;
 193     device->header.result=0;
 194     if (count>=sizeof(struct sg_header))
 195     {
 196         memcpy_tofs(buf,&device->header,sizeof(struct sg_header));
 197         buf+=sizeof(struct sg_header);
 198         if (count>device->header.pack_len)
 199             count=device->header.pack_len;
 200         if (count > sizeof(struct sg_header)) {
 201             memcpy_tofs(buf,device->buff,count-sizeof(struct sg_header));
 202         }
 203     }
 204     else
 205         count=0;
 206     sg_free(device->buff,device->buff_len);
 207     device->buff = NULL;
 208     device->pending=0;
 209     wake_up(&device->write_wait);
 210     return count;
 211 }
 212 
 213 static void sg_command_done(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215     int dev=SCpnt->request.dev;
 216     struct scsi_generic *device=&scsi_generics[dev];
 217     if (!device->pending)
 218     {
 219         printk("unexpected done for sg %d\n",dev);
 220         SCpnt->request.dev=-1;
 221         return;
 222     }
 223     memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
 224     if (SCpnt->sense_buffer[0])
 225     {
 226         device->header.result=EIO;
 227     }
 228     else
 229         device->header.result=SCpnt->result;
 230     device->complete=1;
 231     SCpnt->request.dev=-1;
 232     wake_up(&scsi_generics[dev].read_wait);
 233 }
 234 
 235 static int sg_write(struct inode *inode,struct file *filp,char *buf,int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 236 {
 237     int dev=MINOR(inode->i_rdev);
 238     Scsi_Cmnd *SCpnt;
 239     int bsize,size,amt,i;
 240     unsigned char opcode;
 241     unsigned char cmnd[MAX_COMMAND_SIZE];
 242     struct scsi_generic *device=&scsi_generics[dev];
 243     
 244     if ((i=verify_area(VERIFY_READ,buf,count)))
 245         return i;
 246     /*
 247      * The minimum scsi command length is 6 bytes.  If we get anything less than this,
 248      * it is clearly bogus.
 249      */
 250     if (count<(sizeof(struct sg_header) + 6))
 251         return -EIO;
 252     /* make sure we can fit */
 253     while(device->pending)
 254     {
 255         if (filp->f_flags & O_NONBLOCK)
 256             return -EWOULDBLOCK;
 257 #ifdef DEBUG
 258         printk("sg_write: sleeping on pending request\n");
 259 #endif     
 260         interruptible_sleep_on(&device->write_wait);
 261         if (current->signal & ~current->blocked)
 262             return -ERESTARTSYS;
 263     }
 264     device->pending=1;
 265     device->complete=0;
 266     memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
 267     /* fix input size */
 268     device->header.pack_len=count;
 269     buf+=sizeof(struct sg_header);
 270     bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len;
 271     bsize-=sizeof(struct sg_header);
 272     amt=bsize;
 273     if (!bsize)
 274         bsize++;
 275     bsize=(bsize+511) & ~511;
 276     if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
 277     {
 278         device->pending=0;
 279         wake_up(&device->write_wait);
 280         return -ENOMEM;
 281     }
 282 #ifdef DEBUG
 283     printk("allocating device\n");
 284 #endif
 285     if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
 286     {
 287         device->pending=0;
 288         wake_up(&device->write_wait);
 289         sg_free(device->buff,device->buff_len);
 290         device->buff = NULL;
 291         return -EWOULDBLOCK;
 292     } 
 293 #ifdef DEBUG
 294     printk("device allocated\n");
 295 #endif    
 296     /* now issue command */
 297     SCpnt->request.dev=dev;
 298     SCpnt->sense_buffer[0]=0;
 299     opcode = get_user(buf);
 300     size=COMMAND_SIZE(opcode);
 301     if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
 302     SCpnt->cmd_len = size;
 303     amt-=device->header.pack_len>device->header.reply_len ? size : 0;
 304     /*
 305      * Verify that the user has actually passed enough bytes for this command.
 306      */
 307     if (count<(sizeof(struct sg_header) + size))
 308     {
 309         device->pending=0;
 310         wake_up(&device->write_wait);
 311         sg_free(device->buff,device->buff_len);
 312         device->buff = NULL;
 313         return -EIO;
 314     }
 315     
 316     memcpy_fromfs(cmnd,buf,size);
 317     buf+=size;
 318     memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
 319     cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5);
 320 #ifdef DEBUG
 321     printk("do cmd\n");
 322 #endif
 323     scsi_do_cmd (SCpnt,(void *) cmnd,
 324                  (void *) device->buff,amt,
 325                  sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
 326 #ifdef DEBUG
 327     printk("done cmd\n");
 328 #endif               
 329     return count;
 330 }
 331 
 332 static struct file_operations sg_fops = {
 333     NULL,            /* lseek */
 334     sg_read,         /* read */
 335     sg_write,        /* write */
 336     NULL,            /* readdir */
 337     NULL,            /* select */
 338     sg_ioctl,        /* ioctl */
 339     NULL,            /* mmap */
 340     sg_open,         /* open */
 341     sg_close,        /* release */
 342     NULL             /* fsync */
 343 };
 344 
 345 
 346 static int sg_detect(Scsi_Device * SDp){
     /* [previous][next][first][last][top][bottom][index][help] */
 347     ++sg_template.dev_noticed;
 348     return 1;
 349 }
 350 
 351 /* Driver initialization */
 352 static void sg_init()
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354     static int sg_registered = 0;
 355     
 356     if (sg_template.dev_noticed == 0) return;
 357     
 358     if(!sg_registered) {
 359         if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) 
 360         {
 361             printk("Unable to get major %d for generic SCSI device\n",
 362                    SCSI_GENERIC_MAJOR);
 363             return;
 364         }
 365         sg_registered++;
 366     }
 367     
 368     /* If we have already been through here, return */
 369     if(scsi_generics) return;
 370     
 371 #ifdef DEBUG
 372     printk("sg: Init generic device.\n");
 373 #endif
 374     
 375 #ifdef SG_BIG_BUFF
 376     big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA);
 377 #endif
 378     
 379     scsi_generics = (struct scsi_generic *) 
 380         scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) 
 381                          * sizeof(struct scsi_generic), GFP_ATOMIC);
 382     memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS)
 383            * sizeof(struct scsi_generic));
 384     
 385     sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS;
 386 }
 387 
 388 static int sg_attach(Scsi_Device * SDp)
     /* [previous][next][first][last][top][bottom][index][help] */
 389 {
 390     struct scsi_generic * gpnt;
 391     int i;
 392     
 393     if(sg_template.nr_dev >= sg_template.dev_max) 
 394     {
 395         SDp->attached--;
 396         return 1;
 397     }
 398     
 399     for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
 400         if(!gpnt->device) break;
 401     
 402     if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)");
 403     
 404     scsi_generics[i].device=SDp;
 405     scsi_generics[i].users=0;
 406     scsi_generics[i].generic_wait=NULL;
 407     scsi_generics[i].read_wait=NULL;
 408     scsi_generics[i].write_wait=NULL;
 409     scsi_generics[i].buff=NULL;
 410     scsi_generics[i].exclude=0;
 411     scsi_generics[i].pending=0;
 412     scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT;
 413     sg_template.nr_dev++;
 414     return 0;
 415 };
 416 
 417 
 418 
 419 static void sg_detach(Scsi_Device * SDp)
     /* [previous][next][first][last][top][bottom][index][help] */
 420 {
 421     struct scsi_generic * gpnt;
 422     int i;
 423     
 424     for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++) 
 425         if(gpnt->device == SDp) {
 426             gpnt->device = NULL;
 427             SDp->attached--;
 428             sg_template.nr_dev--;
 429             return;
 430         }
 431     return;
 432 }
 433 
 434 #ifdef MODULE
 435 char kernel_version[] = UTS_RELEASE;
 436 
 437 int init_module(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 438     sg_template.usage_count = &mod_use_count_;
 439     return scsi_register_module(MODULE_SCSI_DEV, &sg_template);
 440 }
 441 
 442 void cleanup_module( void) 
     /* [previous][next][first][last][top][bottom][index][help] */
 443 {
 444     if (MOD_IN_USE) {
 445         printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
 446         return;
 447     }
 448     scsi_unregister_module(MODULE_SCSI_DEV, &sg_template);
 449     unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
 450     
 451     if(scsi_generics != NULL) {
 452         scsi_init_free((char *) scsi_generics,
 453                        (sg_template.dev_noticed + SG_EXTRA_DEVS) 
 454                        * sizeof(struct scsi_generic));
 455     }
 456     sg_template.dev_max = 0;
 457 #ifdef SG_BIG_BUFF
 458     if(big_buff != NULL)
 459         scsi_init_free(big_buff, SG_BIG_BUFF);
 460 #endif
 461 }
 462 #endif /* MODULE */
 463 
 464 /*
 465  * Overrides for Emacs so that we almost follow Linus's tabbing style.
 466  * Emacs will notice this stuff at the end of the file and automatically
 467  * adjust the settings for this buffer only.  This must remain at the end
 468  * of the file.
 469  * ---------------------------------------------------------------------------
 470  * Local variables:
 471  * c-indent-level: 4
 472  * c-brace-imaginary-offset: 0
 473  * c-brace-offset: -4
 474  * c-argdecl-indent: 4
 475  * c-label-offset: -4
 476  * c-continued-statement-offset: 4
 477  * c-continued-brace-offset: 0
 478  * indent-tabs-mode: nil
 479  * tab-width: 8
 480  * End:
 481  */

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