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

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