home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / drivers / scsi / scsi_ioctl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-01  |  8.5 KB  |  306 lines

  1. #include <asm/io.h>
  2. #include <asm/segment.h>
  3. #include <asm/system.h>
  4.  
  5. #include <linux/errno.h>
  6. #include <linux/kernel.h>
  7. #include <linux/sched.h>
  8. #include <linux/string.h>
  9.  
  10. #include "../block/blk.h"
  11. #include "scsi.h"
  12. #include "hosts.h"
  13. #include "scsi_ioctl.h"
  14.  
  15. #define MAX_RETRIES 5    
  16. #define MAX_TIMEOUT 200
  17. #define MAX_BUF 4096
  18.  
  19. #define max(a,b) (((a) > (b)) ? (a) : (b))
  20.  
  21. /*
  22.  * If we are told to probe a host, we will return 0 if  the host is not
  23.  * present, 1 if the host is present, and will return an identifying
  24.  * string at *arg, if arg is non null, filling to the length stored at
  25.  * (int *) arg
  26.  */
  27.  
  28. static int ioctl_probe(struct Scsi_Host * host, void *buffer)
  29. {
  30.     int temp;
  31.     unsigned int len,slen;
  32.     const char * string;
  33.     
  34.     if ((temp = host->hostt->present) && buffer) {
  35.         len = get_fs_long ((unsigned long *) buffer);
  36.         string = host->hostt->info();
  37.         slen = strlen(string);
  38.         if (len > slen)
  39.             len = slen + 1;
  40.         verify_area(VERIFY_WRITE, buffer, len);
  41.         memcpy_tofs (buffer, string, len);
  42.     }
  43.     return temp;
  44. }
  45.  
  46. /*
  47.  * 
  48.  * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
  49.  * The MAX_TIMEOUT and MAX_RETRIES  variables are used.  
  50.  * 
  51.  * dev is the SCSI device struct ptr, *(int *) arg is the length of the
  52.  * input data, if any, not including the command string & counts, 
  53.  * *((int *)arg + 1) is the output buffer size in bytes.
  54.  * 
  55.  * *(char *) ((int *) arg)[2] the actual command byte.   
  56.  * 
  57.  * Note that no more than MAX_BUF data bytes will be transfered.  Since
  58.  * SCSI block device size is 512 bytes, I figured 1K was good.
  59.  * but (WDE) changed it to 8192 to handle large bad track buffers.
  60.  * ERY: I changed this to a dynamic allocation using scsi_malloc - we were
  61.  * getting a kernel stack overflow which was crashing the system when we
  62.  * were using 8192 bytes.
  63.  * 
  64.  * This size *does not* include the initial lengths that were passed.
  65.  * 
  66.  * The SCSI command is read from the memory location immediately after the
  67.  * length words, and the input data is right after the command.  The SCSI
  68.  * routines know the command size based on the opcode decode.  
  69.  * 
  70.  * The output area is then filled in starting from the command byte. 
  71.  */
  72.  
  73. static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
  74. {
  75.   struct request * req;
  76.   struct task_struct * p;
  77.   
  78.   req = &SCpnt->request;
  79.   req->dev = 0xfffe; /* Busy, but indicate request done */
  80.   
  81.   if ((p = req->waiting) != NULL) {
  82.     req->waiting = NULL;
  83.     p->state = TASK_RUNNING;
  84.     if (p->counter > current->counter)
  85.       need_resched = 1;
  86.   }
  87. }    
  88.  
  89. static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
  90. {
  91.     int result;
  92.     Scsi_Cmnd * SCpnt;
  93.  
  94.     SCpnt = allocate_device(NULL, dev->index, 1);
  95.     scsi_do_cmd(SCpnt,  cmd, NULL,  0,
  96.             scsi_ioctl_done,  MAX_TIMEOUT,
  97.             MAX_RETRIES);
  98.  
  99.     if (SCpnt->request.dev != 0xfffe){
  100.       SCpnt->request.waiting = current;
  101.       current->state = TASK_UNINTERRUPTIBLE;
  102.       while (SCpnt->request.dev != 0xfffe) schedule();
  103.     };
  104.  
  105.     if(driver_byte(SCpnt->result) != 0)
  106.       switch(SCpnt->sense_buffer[2] & 0xf) {
  107.       case ILLEGAL_REQUEST:
  108.         if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
  109.         else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
  110.         break;
  111.       case NOT_READY: /* This happens if there is no disc in drive */
  112.         if(dev->removable){
  113.           printk("Device not ready.  Make sure there is a disc in the drive.\n");
  114.           break;
  115.         };
  116.       case UNIT_ATTENTION:
  117.         if (dev->removable){
  118.           dev->changed = 1;
  119.           SCpnt->result = 0; /* This is no longer considered an error */
  120.           printk("Disc change detected.\n");
  121.           break;
  122.         };
  123.       default: /* Fall through for non-removable media */
  124.         printk("SCSI CD error: host %d id %d lun %d return code = %x\n",
  125.            dev->host->host_no,
  126.            dev->id,
  127.            dev->lun,
  128.            SCpnt->result);
  129.         printk("\tSense class %x, sense error %x, extended sense %x\n",
  130.            sense_class(SCpnt->sense_buffer[0]),
  131.            sense_error(SCpnt->sense_buffer[0]),
  132.            SCpnt->sense_buffer[2] & 0xf);
  133.  
  134.       };
  135.  
  136.     result = SCpnt->result;
  137.     SCpnt->request.dev = -1;  /* Mark as not busy */
  138.     wake_up(&scsi_devices[SCpnt->index].device_wait);
  139.     return result;
  140. }
  141.  
  142. static int ioctl_command(Scsi_Device *dev, void *buffer)
  143. {
  144.     char * buf;
  145.     char cmd[12];
  146.     char * cmd_in;
  147.     Scsi_Cmnd * SCpnt;
  148.     unsigned char opcode;
  149.     int inlen, outlen, cmdlen;
  150.     int needed;
  151.     int result;
  152.  
  153.     if (!buffer)
  154.         return -EINVAL;
  155.     
  156.     inlen = get_fs_long((unsigned long *) buffer);
  157.     outlen = get_fs_long( ((unsigned long *) buffer) + 1);
  158.  
  159.     cmd_in = (char *) ( ((int *)buffer) + 2);
  160.     opcode = get_fs_byte(cmd_in); 
  161.  
  162.     needed = (inlen > outlen ? inlen : outlen);
  163.     if(needed){
  164.       needed = (needed + 511) & ~511;
  165.       if (needed > MAX_BUF) needed = MAX_BUF;
  166.       buf = (char *) scsi_malloc(needed);
  167.       if (!buf) return -ENOMEM;
  168.     } else
  169.       buf = NULL;
  170.  
  171.     memcpy_fromfs ((void *) cmd,  cmd_in,  cmdlen = COMMAND_SIZE (opcode));
  172.     memcpy_fromfs ((void *) buf,  (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);
  173.  
  174.     cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
  175.  
  176. #ifndef DEBUG_NO_CMD
  177.     
  178.     SCpnt = allocate_device(NULL, dev->index, 1);
  179.  
  180.     scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,  MAX_TIMEOUT, 
  181.             MAX_RETRIES);
  182.  
  183.     if (SCpnt->request.dev != 0xfffe){
  184.       SCpnt->request.waiting = current;
  185.       current->state = TASK_UNINTERRUPTIBLE;
  186.       while (SCpnt->request.dev != 0xfffe) schedule();
  187.     };
  188.  
  189.  
  190.     /* If there was an error condition, pass the info back to the user. */
  191.     if(SCpnt->result) {
  192.       result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer));
  193.       if (result)
  194.         return result;
  195.       memcpy_tofs((void *) cmd_in,  SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
  196.     } else {
  197.  
  198.       result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF  : outlen);
  199.       if (result)
  200.         return result;
  201.       memcpy_tofs ((void *) cmd_in,  buf,  (outlen > MAX_BUF) ? MAX_BUF  : outlen);
  202.     };
  203.     result = SCpnt->result;
  204.     SCpnt->request.dev = -1;  /* Mark as not busy */
  205.     if (buf) scsi_free(buf, needed);
  206.     wake_up(&scsi_devices[SCpnt->index].device_wait);
  207.     return result;
  208. #else
  209.     {
  210.     int i;
  211.     printk("scsi_ioctl : device %d.  command = ", dev->id);
  212.     for (i = 0; i < 12; ++i)
  213.         printk("%02x ", cmd[i]);
  214.     printk("\nbuffer =");
  215.     for (i = 0; i < 20; ++i)
  216.         printk("%02x ", buf[i]);
  217.     printk("\n");
  218.     printk("inlen = %d, outlen = %d, cmdlen = %d\n",
  219.         inlen, outlen, cmdlen);
  220.     printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
  221.     }
  222.     return 0;
  223. #endif
  224. }
  225.  
  226.     
  227.  
  228. /*
  229.     the scsi_ioctl() function differs from most ioctls in that it does
  230.     not take a major/minor number as the dev filed.  Rather, it takes
  231.     a pointer to a scsi_devices[] element, a structure. 
  232. */
  233. int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
  234. {
  235.         char scsi_cmd[12];
  236.  
  237.     if ((cmd != 0 && dev->index > NR_SCSI_DEVICES))
  238.         return -ENODEV;
  239.     
  240.     switch (cmd) {
  241.             case SCSI_IOCTL_GET_IDLUN:
  242.                     verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
  243.             put_fs_long(dev->id + (dev->lun << 8) + 
  244.                     (dev->host->host_no << 16), (unsigned long *) arg);
  245.             return 0;
  246.         case SCSI_IOCTL_TAGGED_ENABLE:
  247.             if(!suser())  return -EACCES;
  248.             if(!dev->tagged_supported) return -EINVAL;
  249.             dev->tagged_queue = 1;
  250.             dev->current_tag = 1;
  251.             break;
  252.         case SCSI_IOCTL_TAGGED_DISABLE:
  253.             if(!suser())  return -EACCES;
  254.             if(!dev->tagged_supported) return -EINVAL;
  255.             dev->tagged_queue = 0;
  256.             dev->current_tag = 0;
  257.             break;
  258.         case SCSI_IOCTL_PROBE_HOST:
  259.             return ioctl_probe(dev->host, arg);
  260.         case SCSI_IOCTL_SEND_COMMAND:
  261.             if(!suser())  return -EACCES;
  262.             return ioctl_command((Scsi_Device *) dev, arg);
  263.         case SCSI_IOCTL_DOORLOCK:
  264.             if (!dev->removable || !dev->lockable) return 0;
  265.                 scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
  266.             scsi_cmd[1] = dev->lun << 5;
  267.             scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
  268.             scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
  269.             return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
  270.             break;
  271.         case SCSI_IOCTL_DOORUNLOCK:
  272.             if (!dev->removable || !dev->lockable) return 0;
  273.                 scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
  274.             scsi_cmd[1] = dev->lun << 5;
  275.             scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
  276.             scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
  277.             return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
  278.         case SCSI_IOCTL_TEST_UNIT_READY:
  279.                 scsi_cmd[0] = TEST_UNIT_READY;
  280.             scsi_cmd[1] = dev->lun << 5;
  281.             scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
  282.             scsi_cmd[4] = 0;
  283.             return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
  284.             break;
  285.         default :            
  286.             return -EINVAL;
  287.     }
  288.     return -EINVAL;
  289. }
  290.  
  291. /*
  292.  * Just like scsi_ioctl, only callable from kernel space with no 
  293.  * fs segment fiddling.
  294.  */
  295.  
  296. int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) {
  297.   unsigned long oldfs;
  298.   int tmp;
  299.   oldfs = get_fs();
  300.   set_fs(get_ds());
  301.   tmp = scsi_ioctl (dev, cmd, arg);
  302.   set_fs(oldfs);
  303.   return tmp;
  304. }
  305.  
  306.