root/drivers/scsi/scsi_proc.c

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

DEFINITIONS

This source file includes following definitions.
  1. generic_proc_info
  2. dispatch_scsi_info
  3. build_proc_dir_entries
  4. parseFree
  5. parseInit
  6. parseOpt
  7. proc_print_scsidevice

   1 /*
   2  * linux/drivers/scsi/scsi_proc.c
   3  *
   4  * The functions in this file provide an interface between
   5  * the PROC file system and the SCSI device drivers
   6  * It is mainly used for debugging, statistics and to pass 
   7  * information directly to the lowlevel driver.
   8  *
   9  * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de 
  10  * Version: 0.99.8   last change: 95/09/13
  11  * 
  12  * generic command parser provided by: 
  13  * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
  14  */
  15 
  16 #ifdef MODULE
  17 /*
  18  * Don't import our own symbols, as this would severely mess up our
  19  * symbol tables.
  20  */
  21 #define _SCSI_SYMS_VER_
  22 #include <linux/autoconf.h>
  23 #include <linux/module.h>
  24 #include <linux/version.h>
  25 #else
  26 #define MOD_INC_USE_COUNT
  27 #define MOD_DEC_USE_COUNT
  28 #endif
  29 
  30 #include <linux/string.h>
  31 #include <linux/mm.h>
  32 #include <linux/malloc.h>
  33 #include <linux/proc_fs.h>
  34 #include <linux/errno.h>
  35 #include <linux/stat.h>
  36 #include "../block/blk.h"
  37 #include "scsi.h"
  38 #include "hosts.h"
  39 
  40 #ifndef TRUE
  41 #define TRUE  1
  42 #define FALSE 0
  43 #endif
  44 
  45 extern int scsi_proc_info(char *, char **, off_t, int, int, int);
  46  
  47 struct scsi_dir {
  48     struct proc_dir_entry entry;
  49     char name[4];
  50 };
  51 
  52 
  53 /* generic_proc_info
  54  * Used if the driver currently has no own support for /proc/scsi
  55  */
  56 int generic_proc_info(char *buffer, char **start, off_t offset, 
     /* [previous][next][first][last][top][bottom][index][help] */
  57                      int length, int inode, int inout)
  58 {
  59     int len, pos, begin;
  60 
  61     if(inout == TRUE)
  62         return(-ENOSYS);  /* This is a no-op */
  63     
  64     begin = 0;
  65     pos = len = sprintf(buffer, 
  66                         "The driver does not yet support the proc-fs\n");
  67     if(pos < offset) {
  68         len = 0;
  69         begin = pos;
  70     }
  71     
  72     *start = buffer + (offset - begin);   /* Start of wanted data */
  73     len -= (offset - begin);
  74     if(len > length)
  75         len = length;
  76     
  77     return(len);
  78 }
  79 
  80 /* dispatch_scsi_info is the central dispatcher 
  81  * It is the interface between the proc-fs and the SCSI subsystem code
  82  */
  83 extern int dispatch_scsi_info(int ino, char *buffer, char **start, 
     /* [previous][next][first][last][top][bottom][index][help] */
  84                               off_t offset, int length, int func)
  85 {
  86     struct Scsi_Host *hpnt = scsi_hostlist;
  87     
  88     if(ino == PROC_SCSI_SCSI) {            
  89         /*
  90          * This is for the scsi core, rather than any specific
  91          * lowlevel driver.
  92          */
  93         return(scsi_proc_info(buffer, start, offset, length, 0, func));
  94     }
  95     
  96     while(hpnt) {
  97         if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
  98             if(hpnt->hostt->proc_info == NULL)
  99                 return generic_proc_info(buffer, start, offset, length, 
 100                                          hpnt->host_no, func);
 101             else
 102                 return(hpnt->hostt->proc_info(buffer, start, offset, 
 103                                               length, hpnt->host_no, func));
 104         }
 105         hpnt = hpnt->next;
 106     }
 107     return(-EBADF);
 108 }
 109 
 110 void build_proc_dir_entries(Scsi_Host_Template *tpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112     struct Scsi_Host *hpnt;
 113 
 114     struct scsi_dir *scsi_hba_dir;
 115 
 116     proc_scsi_register(0, tpnt->proc_dir);
 117     
 118     hpnt = scsi_hostlist;
 119     while (hpnt) {
 120         if (tpnt == hpnt->hostt) {
 121             scsi_hba_dir = scsi_init_malloc(sizeof(struct scsi_dir), GFP_KERNEL);
 122             if(scsi_hba_dir == NULL)
 123                 panic("Not enough memory to register SCSI HBA in /proc/scsi !\n");
 124             memset(scsi_hba_dir, 0, sizeof(struct scsi_dir));
 125             scsi_hba_dir->entry.low_ino = PROC_SCSI_FILE + hpnt->host_no;
 126             scsi_hba_dir->entry.namelen = sprintf(scsi_hba_dir->name,"%d",
 127                                                     hpnt->host_no);
 128             scsi_hba_dir->entry.name = scsi_hba_dir->name;
 129             scsi_hba_dir->entry.mode = S_IFREG | S_IRUGO | S_IWUSR;
 130             proc_scsi_register(tpnt->proc_dir, &scsi_hba_dir->entry);
 131         }
 132         hpnt = hpnt->next;
 133     }
 134 }
 135 
 136 /*
 137  *  parseHandle *parseInit(char *buf, char *cmdList, int cmdNum); 
 138  *              gets a pointer to a null terminated data buffer
 139  *              and a list of commands with blanks as delimiter 
 140  *      in between. 
 141  *      The commands have to be alphanumerically sorted. 
 142  *      cmdNum has to contain the number of commands.
 143  *              On success, a pointer to a handle structure
 144  *              is returned, NULL on failure
 145  *
 146  *      int parseOpt(parseHandle *handle, char **param);
 147  *              processes the next parameter. On success, the
 148  *              index of the appropriate command in the cmdList
 149  *              is returned, starting with zero.
 150  *              param points to the null terminated parameter string.
 151  *              On failure, -1 is returned.
 152  *
 153  *      The databuffer buf may only contain pairs of commands
 154  *          options, separated by blanks:
 155  *              <Command> <Parameter> [<Command> <Parameter>]*
 156  */
 157 
 158 typedef struct
 159 {
 160     char *buf,                             /* command buffer  */
 161          *cmdList,                         /* command list    */
 162          *bufPos,                          /* actual position */
 163          **cmdPos,                         /* cmdList index   */
 164          cmdNum;                           /* cmd number      */
 165 } parseHandle;
 166         
 167 
 168 inline int parseFree (parseHandle *handle)               /* free memory     */
     /* [previous][next][first][last][top][bottom][index][help] */
 169 {
 170     kfree (handle->cmdPos);
 171     kfree (handle);
 172     
 173     return(-1);
 174 }
 175 
 176         
 177 parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 178 {
 179     char        *ptr;                               /* temp pointer    */
 180     parseHandle *handle;                            /* new handle      */
 181     
 182     if (!buf || !cmdList)                           /* bad input ?     */
 183         return(NULL);
 184     if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), 1)) == 0)
 185         return(NULL);                               /* out of memory   */
 186     if ((handle->cmdPos = (char**) kmalloc(sizeof(int), cmdNum)) == 0) {
 187         kfree(handle);
 188         return(NULL);                               /* out of memory   */
 189     }
 190     
 191     handle->buf     = handle->bufPos = buf;         /* init handle     */
 192     handle->cmdList = cmdList;
 193     handle->cmdNum  = cmdNum;
 194     
 195     handle->cmdPos[cmdNum = 0] = cmdList;
 196     for (ptr = cmdList; *ptr; ptr++) {          /* scan command string */
 197         if(*ptr == ' ') {                       /* and insert zeroes   */
 198             *ptr++ = 0;
 199             handle->cmdPos[++cmdNum] = ptr++;
 200         } 
 201     }
 202     return(handle);
 203 }
 204 
 205 
 206 int parseOpt(parseHandle *handle, char **param)
     /* [previous][next][first][last][top][bottom][index][help] */
 207 {
 208     int  cmdIndex = 0, 
 209          cmdLen = 0;
 210     char *startPos;
 211     
 212     if (!handle)                                    /* invalid handle  */
 213         return(parseFree(handle));
 214     /* skip spaces     */  
 215     for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
 216     if (!*(handle->bufPos))
 217         return(parseFree(handle));                  /* end of data     */
 218     
 219     startPos = handle->bufPos;                      /* store cmd start */
 220     for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++)
 221     {                                               /* no string end?  */
 222         for (;;)
 223         {
 224             if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
 225                 break;                              /* char matches ?  */
 226             else
 227                 if (memcmp(startPos, (char*)(handle->cmdPos[++cmdIndex]), cmdLen))
 228                     return(parseFree(handle));      /* unknown command */
 229             
 230             if (cmdIndex >= handle->cmdNum)
 231                 return(parseFree(handle));          /* unknown command */     
 232         }
 233         
 234         cmdLen++;                                   /* next char       */
 235     }
 236     
 237     /* Get param. First skip all blanks, then insert zero after param  */
 238     
 239     for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
 240     *param = handle->bufPos; 
 241     
 242     for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
 243     *(handle->bufPos++) = 0;
 244     
 245     return(cmdIndex);
 246 }
 247 
 248 #define MAX_SCSI_DEVICE_CODE 10
 249 const char *const scsi_dev_types[MAX_SCSI_DEVICE_CODE] =
 250 {
 251     "Direct-Access    ",
 252     "Sequential-Access",
 253     "Printer          ",
 254     "Processor        ",
 255     "WORM             ",
 256     "CD-ROM           ",
 257     "Scanner          ",
 258     "Optical Device   ",
 259     "Medium Changer   ",
 260     "Communications   "
 261 };
 262 
 263 void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 264 {           
 265     int x, y = *size;
 266     
 267     y = sprintf(buffer + len, 
 268                     "Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
 269                     scd->channel, scd->id, scd->lun);
 270     for (x = 0; x < 8; x++) {
 271         if (scd->vendor[x] >= 0x20)
 272             y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
 273         else
 274             y += sprintf(buffer + len + y," ");
 275     }
 276     y += sprintf(buffer + len + y, " Model: ");
 277     for (x = 0; x < 16; x++) {
 278         if (scd->model[x] >= 0x20)
 279             y +=  sprintf(buffer + len + y, "%c", scd->model[x]);
 280         else
 281             y += sprintf(buffer + len + y, " ");
 282     }
 283     y += sprintf(buffer + len + y, " Rev: ");
 284     for (x = 0; x < 4; x++) {
 285         if (scd->rev[x] >= 0x20)
 286             y += sprintf(buffer + len + y, "%c", scd->rev[x]);
 287         else
 288             y += sprintf(buffer + len + y, " ");
 289     }
 290     y += sprintf(buffer + len + y, "\n");
 291     
 292     y += sprintf(buffer + len + y, "  Type:   %s ",
 293                      scd->type < MAX_SCSI_DEVICE_CODE ? 
 294                      scsi_dev_types[(int)scd->type] : "Unknown          " );
 295     y += sprintf(buffer + len + y, "               ANSI"
 296                      " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
 297     if (scd->scsi_level == 2)
 298         y += sprintf(buffer + len + y, " CCS\n");
 299     else
 300         y += sprintf(buffer + len + y, "\n");
 301 
 302     *size = y; 
 303     return;
 304 }
 305 
 306 /*
 307  * Overrides for Emacs so that we get a uniform tabbing style.
 308  * Emacs will notice this stuff at the end of the file and automatically
 309  * adjust the settings for this buffer only.  This must remain at the end
 310  * of the file.
 311  * ---------------------------------------------------------------------------
 312  * Local variables:
 313  * c-indent-level: 4
 314  * c-brace-imaginary-offset: 0
 315  * c-brace-offset: -4
 316  * c-argdecl-indent: 4
 317  * c-label-offset: -4
 318  * c-continued-statement-offset: 4
 319  * c-continued-brace-offset: 0
 320  * indent-tabs-mode: nil
 321  * tab-width: 8
 322  * End:
 323  */

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