root/fs/proc/scsi.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_not_present_info
  2. proc_readscsi
  3. proc_writescsi
  4. proc_scsilseek

   1 /*
   2  *  linux/fs/proc/scsi.c  
   3  *  (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
   4  *
   5  *  The original version was derived from linux/fs/proc/net.c,
   6  *  which is Copyright (C) 1991, 1992 Linus Torvalds. 
   7  *  Much has been rewritten, but some of the code still remains.
   8  *
   9  *  /proc/scsi directory handling functions
  10  *
  11  *  last change: 95/07/04    
  12  *
  13  *  Initial version: March '95
  14  *  95/05/15 Added subdirectories for each driver and show every
  15  *           registered HBA as a single file. 
  16  *  95/05/30 Added rudimentary write support for parameter passing
  17  *  95/07/04 Fixed bugs in directory handling
  18  *  95/09/13 Update to support the new proc-dir tree
  19  *
  20  *  TODO: Improve support to write to the driver files
  21  *        Add some more comments
  22  */
  23 #include <linux/errno.h>
  24 #include <linux/sched.h>
  25 #include <linux/proc_fs.h>
  26 #include <linux/stat.h>
  27 #include <linux/mm.h>
  28 
  29 #include <asm/segment.h>
  30 
  31 /* forward references */
  32 static int proc_readscsi(struct inode * inode, struct file * file,
  33                          char * buf, int count);
  34 static int proc_writescsi(struct inode * inode, struct file * file,
  35                          const char * buf, int count);
  36 static int proc_scsilseek(struct inode *, struct file *, off_t, int);
  37 
  38 extern void build_proc_dir_hba_entries(uint);
  39 
  40 /* the *_get_info() functions are in the respective scsi driver code */
  41 int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
  42                                 off_t offset, int length, int inout) = 0;
  43 
  44 static struct file_operations proc_scsi_operations = {
  45     proc_scsilseek,     /* lseek   */
  46     proc_readscsi,      /* read    */
  47     proc_writescsi,     /* write   */
  48     proc_readdir,       /* readdir */
  49     NULL,               /* select  */
  50     NULL,               /* ioctl   */
  51     NULL,               /* mmap    */
  52     NULL,               /* no special open code    */
  53     NULL,               /* no special release code */
  54     NULL                /* can't fsync */
  55 };
  56 
  57 /*
  58  * proc directories can do almost nothing..
  59  */
  60 struct inode_operations proc_scsi_inode_operations = {
  61     &proc_scsi_operations,  /* default scsi directory file-ops */
  62     NULL,           /* create      */
  63     proc_lookup,    /* lookup      */
  64     NULL,           /* link        */
  65     NULL,           /* unlink      */
  66     NULL,           /* symlink     */
  67     NULL,           /* mkdir       */
  68     NULL,           /* rmdir       */
  69     NULL,           /* mknod       */
  70     NULL,           /* rename      */
  71     NULL,           /* readlink    */
  72     NULL,           /* follow_link */
  73     NULL,           /* readpage    */
  74     NULL,           /* writepage   */
  75     NULL,           /* bmap        */
  76     NULL,           /* truncate    */
  77     NULL            /* permission  */
  78 };
  79 
  80 int get_not_present_info(char *buffer, char **start, off_t offset, int length)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82     int len, pos, begin;
  83     
  84     begin = 0;
  85     pos = len = sprintf(buffer, 
  86                         "No low-level scsi modules are currently present\n");
  87     if(pos < offset) {
  88         len = 0;
  89         begin = pos;
  90     }
  91     
  92     *start = buffer + (offset - begin);   /* Start of wanted data */
  93     len -= (offset - begin);
  94     if(len > length)
  95         len = length;
  96     
  97     return(len);
  98 }
  99 
 100 #define PROC_BLOCK_SIZE (3*1024)     /* 4K page size, but our output routines 
 101                                       * use some slack for overruns 
 102                                       */
 103 
 104 static int proc_readscsi(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 105                          char * buf, int count)
 106 {
 107     int length;
 108     int bytes = count;
 109     int copied = 0;
 110     int thistime;
 111     char * page;
 112     char * start;
 113     
 114     if (count < -1)               /* Normally I wouldn't do this, */ 
 115         return(-EINVAL);          /* but it saves some redundant code.
 116                                    * Now it is possible to seek to the 
 117                                    * end of the file */
 118     if (!(page = (char *) __get_free_page(GFP_KERNEL)))
 119         return(-ENOMEM);
 120     
 121     while(bytes > 0 || count == -1) {   
 122         thistime = bytes;
 123         if(bytes > PROC_BLOCK_SIZE || count == -1)
 124             thistime = PROC_BLOCK_SIZE;
 125         
 126         if(dispatch_scsi_info_ptr)
 127             length = dispatch_scsi_info_ptr(inode->i_ino, page, &start, 
 128                                             file->f_pos, thistime, 0);
 129         else
 130             length = get_not_present_info(page, &start, file->f_pos, thistime);
 131         if(length < 0) {
 132             free_page((ulong) page);
 133             return(length);
 134         }
 135         
 136         /*
 137          *  We have been given a non page aligned block of
 138          *  the data we asked for + a bit. We have been given
 139          *  the start pointer and we know the length.. 
 140          */
 141         if (length <= 0)
 142             break;
 143         /*
 144          *  Copy the bytes, if we're not doing a seek to 
 145          *      the end of the file 
 146          */
 147         if (count != -1)
 148             memcpy_tofs(buf + copied, start, length);
 149         file->f_pos += length;  /* Move down the file */
 150         bytes -= length;
 151         copied += length;
 152         
 153         if(length < thistime)
 154             break;  /* End of file */
 155         
 156     }
 157     
 158     free_page((ulong) page);
 159     return(copied);
 160 }
 161 
 162 
 163 static int proc_writescsi(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 164                          const char * buf, int count)
 165 {
 166     int ret = 0;
 167     char * page;
 168     
 169     if(count > PROC_BLOCK_SIZE) {
 170         return(-EOVERFLOW);
 171     }
 172 
 173     if(dispatch_scsi_info_ptr != NULL) {
 174         if (!(page = (char *) __get_free_page(GFP_KERNEL)))
 175             return(-ENOMEM);
 176         memcpy_fromfs(page, buf, count);
 177         ret = dispatch_scsi_info_ptr(inode->i_ino, page, 0, 0, count, 1);
 178     } else 
 179         return(-ENOPKG);          /* Nothing here */
 180     
 181     free_page((ulong) page);
 182     return(ret);
 183 }
 184 
 185 
 186 static int proc_scsilseek(struct inode * inode, struct file * file, 
     /* [previous][next][first][last][top][bottom][index][help] */
 187                           off_t offset, int orig)
 188 {
 189     switch (orig) {
 190     case 0:
 191         file->f_pos = offset;
 192         return(file->f_pos);
 193     case 1:
 194         file->f_pos += offset;
 195         return(file->f_pos);
 196     case 2:                  /* This ugly hack allows us to    */
 197         if (offset)          /* to determine the length of the */
 198             return(-EINVAL); /* file and then later safely to  */ 
 199         proc_readscsi(inode, file, 0, -1); /* seek in it       */ 
 200         return(file->f_pos);
 201     default:
 202         return(-EINVAL);
 203     }
 204 }
 205 
 206 /*
 207  * Overrides for Emacs so that we almost follow Linus's tabbing style.
 208  * Emacs will notice this stuff at the end of the file and automatically
 209  * adjust the settings for this buffer only.  This must remain at the end
 210  * of the file.
 211  * ---------------------------------------------------------------------------
 212  * Local variables:
 213  * c-indent-level: 4
 214  * c-brace-imaginary-offset: 0
 215  * c-brace-offset: -4
 216  * c-argdecl-indent: 4
 217  * c-label-offset: -4
 218  * c-continued-statement-offset: 4
 219  * c-continued-brace-offset: 0
 220  * indent-tabs-mode: nil
 221  * tab-width: 8
 222  * End:
 223  */

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