root/kernel/blk_drv/scsi/scsi_ioctl.c

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

DEFINITIONS

This source file includes following definitions.
  1. ioctl_probe
  2. scsi_ioctl_done
  3. ioctl_command
  4. scsi_ioctl

   1 #include <linux/config.h>
   2 #ifdef CONFIG_SCSI 
   3 
   4 #include <asm/io.h>
   5 #include <asm/segment.h>
   6 #include <asm/system.h>
   7 
   8 #include <linux/errno.h>
   9 #include <linux/kernel.h>
  10 #include <linux/sched.h>
  11 #include <linux/string.h>
  12 
  13 #include "scsi.h"
  14 #include "hosts.h"
  15 #include "scsi_ioctl.h"
  16 
  17 #define MAX_RETRIES 5   
  18 #define MAX_TIMEOUT 200
  19 #define MAX_BUF 8192    
  20 
  21 #define max(a,b) (((a) > (b)) ? (a) : (b))
  22 
  23 /*
  24  * If we are told to probe a host, we will return 0 if  the host is not
  25  * present, 1 if the host is present, and will return an identifying
  26  * string at *arg, if arg is non null, filling to the length stored at
  27  * (int *) arg
  28  */
  29 
  30 static int ioctl_probe(int dev, void *buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
  31 {
  32         int temp;
  33         int len;
  34         
  35         if ((temp = scsi_hosts[dev].present) && buffer) {
  36                 len = get_fs_long ((int *) buffer);
  37                 memcpy_tofs (buffer, scsi_hosts[dev].info(), len);
  38         }
  39         return temp;
  40 }
  41 
  42 /*
  43  * 
  44  * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
  45  * The MAX_TIMEOUT and MAX_RETRIES  variables are used.  
  46  * 
  47  * dev is the SCSI device struct ptr, *(int *) arg is the length of the
  48  * input data, if any, not including the command string & counts, 
  49  * *((int *)arg + 1) is the output buffer size in bytes.
  50  * 
  51  * *(char *) ((int *) arg)[2] the actual command byte.   
  52  * 
  53  * Note that no more than MAX_BUF data bytes will be transfered.  Since
  54  * SCSI block device size is 512 bytes, I figured 1K was good.
  55  * but (WDE) changed it to 8192 to handle large bad track buffers.
  56  * 
  57  * This size *does not* include the initial lengths that were passed.
  58  * 
  59  * The SCSI command is read from the memory location immediately after the
  60  * length words, and the input data is right after the command.  The SCSI
  61  * routines know the command size based on the opcode decode.  
  62  * 
  63  * The output area is then filled in starting from the command byte. 
  64  */
  65 
  66 static int the_result[MAX_SCSI_HOSTS];
  67 
  68 static void scsi_ioctl_done (int host, int result)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70         the_result[host] = result;      
  71 }       
  72         
  73 static int ioctl_command(Scsi_Device *dev, void *buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75         char buf[MAX_BUF];
  76         char cmd[10];
  77         char * cmd_in;
  78         unsigned char opcode;
  79         int inlen, outlen, cmdlen, temp, host;
  80 
  81         if (!buffer)
  82                 return -EINVAL;
  83         
  84         inlen = get_fs_long((int *) buffer);
  85         outlen = get_fs_long( ((int *) buffer) + 1);
  86 
  87         cmd_in = (char *) ( ((int *)buffer) + 2);
  88         opcode = get_fs_byte(cmd_in); 
  89 
  90         memcpy_fromfs ((void *) cmd,  cmd_in,  cmdlen = COMMAND_SIZE (opcode));
  91         memcpy_fromfs ((void *) buf,  (void *) (cmd_in + cmdlen),  inlen);
  92         host = dev->host_no;
  93 
  94 #ifndef DEBUG_NO_CMD
  95         do {
  96                 cli();
  97                 if (the_result[host]) {
  98                         sti();
  99                         while(the_result[host])
 100                                 /* nothing */;
 101                 } else {
 102                         the_result[host]=-1;
 103                         sti();
 104                         break;
 105                 }
 106         } while (1);
 107         
 108         scsi_do_cmd(host,  dev->id,  cmd,  buf,  ((outlen > MAX_BUF) ? 
 109                         MAX_BUF : outlen),  scsi_ioctl_done,  MAX_TIMEOUT, 
 110                         buf,  MAX_RETRIES);
 111 
 112         while (the_result[host] == -1)
 113                 /* nothing */;
 114         temp = the_result[host];
 115         the_result[host] = 0;
 116         memcpy_tofs ((void *) cmd_in,  buf,  (outlen > MAX_BUF) ? MAX_BUF  : outlen);
 117         return temp;
 118 #else
 119         {
 120         int i;
 121         printk("scsi_ioctl : device %d.  command = ", dev->id);
 122         for (i = 0; i < 10; ++i)
 123                 printk("%02x ", cmd[i]);
 124         printk("\r\nbuffer =");
 125         for (i = 0; i < 20; ++i)
 126                 printk("%02x ", buf[i]);
 127         printk("\r\n");
 128         printk("inlen = %d, outlen = %d, cmdlen = %d\n",
 129                 inlen, outlen, cmdlen);
 130         printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
 131         }
 132         return 0;
 133 #endif
 134 }
 135 
 136         
 137 /*
 138         the scsi_ioctl() function differs from most ioctls in that it does
 139         not take a major/minor number as the dev filed.  Rather, it takes
 140         a pointer to a scsi_devices[] element, a structure. 
 141 */
 142 int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         if ((cmd != 0 && dev->id > NR_SCSI_DEVICES))
 145                 return -ENODEV;
 146         if ((cmd == 0 && dev->host_no > MAX_SCSI_HOSTS))
 147                 return -ENODEV;
 148         
 149         switch (cmd) {
 150                 case SCSI_IOCTL_PROBE_HOST:
 151                         return ioctl_probe(dev->host_no, arg);
 152                 case SCSI_IOCTL_SEND_COMMAND:
 153                         return ioctl_command((Scsi_Device *) dev, arg);
 154                 default :                       
 155                         return -EINVAL;
 156         }
 157 }
 158 #endif

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