root/fs/proc/scsi.c

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

DEFINITIONS

This source file includes following definitions.
  1. count_dir_entries
  2. proc_lookupscsi
  3. proc_readscsidir
  4. get_not_present_info
  5. proc_readscsi
  6. proc_writescsi
  7. 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/06/13    
  12  *
  13  *  Initial version: March '95
  14  *  95/15/05 Added subdirectories for each driver and show every
  15  *           registered HBA as a single file. 
  16  *  95/30/05 Added rudimentary write support for parameter passing
  17  *
  18  *  TODO: Improve support to write to the driver files
  19  *        Optimize directory handling 
  20  *        Add some more comments
  21  */
  22 #include <linux/autoconf.h>
  23 #include <asm/segment.h>
  24 #include <linux/errno.h>
  25 #include <linux/sched.h>
  26 #include <linux/proc_fs.h>
  27 #include <linux/stat.h>
  28 #include <linux/config.h>
  29 #include <linux/mm.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                          char * buf, int count);
  36 static int proc_readscsidir(struct inode *, struct file *, 
  37                             void *, filldir_t filldir);
  38 static int proc_lookupscsi(struct inode *,const char *,int,struct inode **);
  39 static int proc_scsilseek(struct inode *, struct file *, off_t, int);
  40 
  41 extern uint count_templates(void);
  42 extern void build_proc_dir_hba_entries(uint);
  43 
  44 /* the *_get_info() functions are in the respective scsi driver code */
  45 extern int (* dispatch_scsi_info_ptr)(int, char *, char **, off_t, int, int);
  46     
  47     
  48 static struct file_operations proc_scsi_operations = {
  49     proc_scsilseek,     /* lseek   */
  50     proc_readscsi,      /* read    */
  51     proc_writescsi,     /* write   */
  52     proc_readscsidir,   /* readdir */
  53     NULL,               /* select  */
  54     NULL,               /* ioctl   */
  55     NULL,               /* mmap    */
  56     NULL,               /* no special open code    */
  57     NULL,               /* no special release code */
  58     NULL                /* can't fsync */
  59 };
  60 
  61 /*
  62  * proc directories can do almost nothing..
  63  */
  64 struct inode_operations proc_scsi_inode_operations = {
  65     &proc_scsi_operations,  /* default scsi directory file-ops */
  66     NULL,           /* create      */
  67     proc_lookupscsi,/* lookup      */
  68     NULL,           /* link        */
  69     NULL,           /* unlink      */
  70     NULL,           /* symlink     */
  71     NULL,           /* mkdir       */
  72     NULL,           /* rmdir       */
  73     NULL,           /* mknod       */
  74     NULL,           /* rename      */
  75     NULL,           /* readlink    */
  76     NULL,           /* follow_link */
  77     NULL,           /* bmap        */
  78     NULL,           /* truncate    */
  79     NULL            /* permission  */
  80 };
  81 
  82 struct proc_dir_entry scsi_dir[PROC_SCSI_FILE - PROC_SCSI_SCSI + 3]; 
  83 struct proc_dir_entry scsi_hba_dir[(PROC_SCSI_LAST - PROC_SCSI_FILE) * 4]; 
  84 
  85 static struct proc_dir_entry scsi_dir2[] = {
  86     { PROC_SCSI,                 1, "." },
  87     { PROC_ROOT_INO,             2, ".." },
  88     { PROC_SCSI_NOT_PRESENT,    11, "not.present" },
  89     { 0, 0, NULL }
  90 };
  91 
  92 inline static uint count_dir_entries(uint inode, uint *num)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94     struct proc_dir_entry *dir;
  95     uint index, flag;
  96 
  97     (uint) *num = flag = index = 0;    
  98     
  99     if(dispatch_scsi_info_ptr)
 100     {
 101         if (inode == PROC_SCSI) { 
 102             dir = scsi_dir;
 103             while(dir[(uint)*num].low_ino)
 104                 (*num)++;
 105         } else {
 106             dir = scsi_hba_dir;
 107             while(dir[index].low_ino || dir[index].low_ino <= PROC_SCSI_LAST) {
 108                 if(dir[index].low_ino == inode)
 109                     flag = 1;
 110                 if(dir[index].low_ino == 0) {
 111                     if(flag == 1)
 112                         break;
 113                     else
 114                         *num = 0;
 115                 } else {
 116                     (*num)++;
 117                 }
 118                 index++;
 119             }
 120             return(index - (*num));
 121         }
 122     }
 123     else {
 124         dir = scsi_dir2;
 125         while(dir[(uint)*num].low_ino)
 126             (*num)++;
 127     }   
 128     return(0);
 129 }
 130 
 131 static int proc_lookupscsi(struct inode * dir, const char * name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 132                            struct inode ** result)
 133 {
 134     struct proc_dir_entry *de = NULL;
 135 
 136     *result = NULL;
 137     if (!dir)
 138         return(-ENOENT);
 139     if (!S_ISDIR(dir->i_mode)) {
 140         iput(dir);
 141         return(-ENOENT);
 142     }
 143     if (dispatch_scsi_info_ptr != NULL)
 144     {
 145         if (dir->i_ino <= PROC_SCSI_SCSI)
 146             de = scsi_dir;
 147         else {
 148             de = &scsi_hba_dir[dispatch_scsi_info_ptr(dir->i_ino, 0, 0, 0, 0, 2)];
 149         }
 150     }
 151     else
 152         de = scsi_dir2;
 153     
 154     for (; de->name ; de++) {
 155         if (!proc_match(len, name, de))
 156             continue;
 157         *result = iget(dir->i_sb, de->low_ino);
 158         iput(dir);
 159         if (!*result)
 160             return(-ENOENT);
 161         return(0);
 162     }
 163     iput(dir);
 164     return(-ENOENT);
 165 }
 166 
 167 static int proc_readscsidir(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 168                             void * dirent, filldir_t filldir)
 169 {
 170     struct proc_dir_entry * de;
 171     uint index, num;
 172  
 173     index = num = 0;
 174 
 175     if (!inode || !S_ISDIR(inode->i_mode))
 176         return(-EBADF);
 177 
 178     index = count_dir_entries(inode->i_ino, &num);
 179 
 180     while (((unsigned) filp->f_pos + index) < index + num) {
 181         if (dispatch_scsi_info_ptr) {
 182             if (inode->i_ino <= PROC_SCSI_SCSI)
 183                 de = scsi_dir + filp->f_pos;
 184             else
 185                 de = scsi_hba_dir + filp->f_pos + index;
 186         }
 187         else {
 188             de = scsi_dir2 + filp->f_pos;
 189         }
 190         if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino)<0)
 191             break;
 192         filp->f_pos++;
 193     }
 194     return(0);
 195 }
 196 
 197 int get_not_present_info(char *buffer, char **start, off_t offset, int length)
     /* [previous][next][first][last][top][bottom][index][help] */
 198 {
 199     int len, pos, begin;
 200     
 201     begin = 0;
 202     pos = len = sprintf(buffer, 
 203                         "No low-level scsi modules are currently present\n");
 204     if(pos < offset) {
 205         len = 0;
 206         begin = pos;
 207     }
 208     
 209     *start = buffer + (offset - begin);   /* Start of wanted data */
 210     len -= (offset - begin);
 211     if(len > length)
 212         len = length;
 213     
 214     return(len);
 215 }
 216 
 217 #define PROC_BLOCK_SIZE (3*1024)     /* 4K page size, but our output routines 
 218                                       * use some slack for overruns 
 219                                       */
 220 
 221 static int proc_readscsi(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 222                          char * buf, int count)
 223 {
 224     uint ino;
 225     int length;
 226     int bytes = count;
 227     int copied = 0;
 228     int thistime;
 229     char * page;
 230     char * start;
 231     
 232     if (count < -1)               /* Normally I wouldn't do this, */ 
 233         return(-EINVAL);          /* but it saves some redundant code.
 234                                    * Now it is possible to seek to the 
 235                                    * end of the file */
 236     if (!(page = (char *) __get_free_page(GFP_KERNEL)))
 237         return(-ENOMEM);
 238     ino = inode->i_ino;
 239     
 240     
 241     while(bytes > 0 || count == -1)
 242     {
 243         
 244         thistime = bytes;
 245         if(bytes > PROC_BLOCK_SIZE || count == -1)
 246             thistime = PROC_BLOCK_SIZE;
 247         
 248         if(dispatch_scsi_info_ptr)
 249             length = dispatch_scsi_info_ptr(ino, page, &start, 
 250                                             file->f_pos, thistime, 0);
 251         else
 252             length = get_not_present_info(page, &start, file->f_pos, thistime);
 253         if(length < 0) {
 254             free_page((ulong) page);
 255             return(length);
 256         }
 257         
 258         /*
 259          *  We have been given a non page aligned block of
 260          *  the data we asked for + a bit. We have been given
 261          *  the start pointer and we know the length.. 
 262          */
 263         if (length <= 0)
 264             break;
 265         /*
 266          *  Copy the bytes, if we're not doing a seek to 
 267          *      the end of the file 
 268          */
 269         if (count != -1)
 270             memcpy_tofs(buf + copied, start, length);
 271         file->f_pos += length;  /* Move down the file */
 272         bytes -= length;
 273         copied += length;
 274         
 275         if(length < thistime)
 276             break;  /* End of file */
 277         
 278     }
 279     
 280     free_page((ulong) page);
 281     return(copied);
 282 }
 283 
 284 
 285 static int proc_writescsi(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 286                          char * buf, int count)
 287 {
 288     int ret = 0;
 289     char * page;
 290     
 291     if (!(page = (char *) __get_free_page(GFP_KERNEL)))
 292         return(-ENOMEM);
 293 
 294     if(count > PROC_BLOCK_SIZE) {
 295         return(-EOVERFLOW);
 296     }
 297 
 298     if(dispatch_scsi_info_ptr != NULL) {
 299         memcpy_fromfs(page, buf, count);
 300         ret = dispatch_scsi_info_ptr(inode->i_ino, page, 0, 0, count, 1);
 301     } else {
 302         free_page((ulong) page);   
 303         return(-ENOPKG);          /* Nothing here */
 304     }
 305     
 306     free_page((ulong) page);
 307     return(ret);
 308 }
 309 
 310 
 311 static int proc_scsilseek(struct inode * inode, struct file * file, 
     /* [previous][next][first][last][top][bottom][index][help] */
 312                           off_t offset, int orig)
 313 {
 314     switch (orig) {
 315     case 0:
 316         file->f_pos = offset;
 317         return(file->f_pos);
 318     case 1:
 319         file->f_pos += offset;
 320         return(file->f_pos);
 321     case 2:                  /* This ugly hack allows us to    */
 322         if (offset)          /* to determine the length of the */
 323             return(-EINVAL); /* file and then later savely to  */ 
 324         proc_readscsi(inode, file, 0, -1); /* seek in it       */ 
 325         return(file->f_pos);
 326     default:
 327         return(-EINVAL);
 328     }
 329 }
 330 
 331 /*
 332  * Overrides for Emacs so that we almost follow Linus's tabbing style.
 333  * Emacs will notice this stuff at the end of the file and automatically
 334  * adjust the settings for this buffer only.  This must remain at the end
 335  * of the file.
 336  * ---------------------------------------------------------------------------
 337  * Local variables:
 338  * c-indent-level: 4
 339  * c-brace-imaginary-offset: 0
 340  * c-brace-offset: -4
 341  * c-argdecl-indent: 4
 342  * c-label-offset: -4
 343  * c-continued-statement-offset: 4
 344  * c-continued-brace-offset: 0
 345  * indent-tabs-mode: nil
 346  * tab-width: 8
 347  * End:
 348  */

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