root/drivers/scsi/scsi_proc.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_hba_index
  2. generic_proc_info
  3. dispatch_scsi_info
  4. count_templates
  5. build_proc_dir_hba_entries
  6. build_proc_dir_entries
  7. parseFree
  8. parseInit
  9. parseOpt
  10. 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.7   last change: 95/07/18
  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 "../block/blk.h"
  36 #include "scsi.h"
  37 #include "hosts.h"
  38 
  39 #ifndef TRUE
  40 #define TRUE  1
  41 #define FALSE 0
  42 #endif
  43 
  44 extern struct proc_dir_entry scsi_dir[];
  45 extern struct proc_dir_entry scsi_hba_dir[];
  46 extern int scsi_proc_info(char *, char **, off_t, int, int, int);
  47  
  48 
  49 int get_hba_index(int ino)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51     Scsi_Host_Template *tpnt = scsi_hosts;
  52     struct Scsi_Host *hpnt = scsi_hostlist;
  53     uint x = 0;
  54 
  55     /*
  56      * Danger - this has massive race conditions in it.
  57      * If the someone adds/removes entries from the scsi chain
  58      * while someone else is looking at /proc/scsi, unpredictable
  59      * results will be obtained.
  60      */
  61     while (tpnt) {
  62         if (ino == tpnt->low_ino) 
  63                 return(x);
  64         x += 3;
  65         while (hpnt) {
  66             if(hpnt->hostt == tpnt) /* This gives us the correct index */
  67                 x++;
  68             hpnt = hpnt->next;
  69         }
  70         tpnt = tpnt->next;
  71     }
  72     return(0);
  73 }
  74 
  75 /* generic_proc_info
  76  * Used if the driver currently has no own support for /proc/scsi
  77  */
  78 int generic_proc_info(char *buffer, char **start, off_t offset, 
     /* [previous][next][first][last][top][bottom][index][help] */
  79                      int length, int inode, int inout)
  80 {
  81     int len, pos, begin;
  82 
  83     if(inout == TRUE)
  84         return(-ENOSYS);  /* This is a no-op */
  85     
  86     begin = 0;
  87     pos = len = sprintf(buffer, 
  88                         "The driver does not yet support the proc-fs\n");
  89     if(pos < offset) {
  90         len = 0;
  91         begin = pos;
  92     }
  93     
  94     *start = buffer + (offset - begin);   /* Start of wanted data */
  95     len -= (offset - begin);
  96     if(len > length)
  97         len = length;
  98     
  99     return(len);
 100 }
 101 
 102 /* dispatch_scsi_info is the central dispatcher 
 103  * It is the interface between the proc-fs and the SCSI subsystem code
 104  */
 105 extern int dispatch_scsi_info(int ino, char *buffer, char **start, 
     /* [previous][next][first][last][top][bottom][index][help] */
 106                               off_t offset, int length, int func)
 107 {
 108     struct Scsi_Host *hpnt = scsi_hostlist;
 109 
 110     if(func != 2) {    
 111         if(ino == PROC_SCSI_SCSI) {            
 112             /*
 113              * This is for the scsi core, rather than any specific
 114              * lowlevel driver.
 115              */
 116             return(scsi_proc_info(buffer, start, offset, length, 0, func));
 117         }
 118 
 119         while(hpnt) {
 120             if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
 121                 if(hpnt->hostt->proc_info == NULL)
 122                     return generic_proc_info(buffer, start, offset, length, 
 123                                              hpnt->host_no, func);
 124                 else
 125                     return(hpnt->hostt->proc_info(buffer, start, offset, 
 126                                                   length, hpnt->host_no, func));
 127             }
 128             hpnt = hpnt->next;
 129         }
 130         return(-EBADF);
 131     } else
 132         return(get_hba_index(ino));
 133 }
 134 
 135 inline uint count_templates(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137     Scsi_Host_Template *tpnt = scsi_hosts;
 138     uint x = 0;
 139     
 140     while (tpnt) {
 141         tpnt = tpnt->next;
 142         x++;
 143     }
 144     return (x);
 145 }
 146 
 147 void build_proc_dir_hba_entries(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149     Scsi_Host_Template *tpnt = scsi_hosts;
 150     struct Scsi_Host *hpnt;
 151     uint x, y;
 152 
 153     /* namespace for 16 HBAs with host_no 0-999 
 154      * I don't think we'll need more. Having more than 2 
 155      * HBAs in one system is already highly unusual 
 156      */
 157     static char names[PROC_SCSI_LAST - PROC_SCSI_FILE][4];
 158     
 159     x = y = 0;
 160 
 161     while (tpnt) {
 162         scsi_hba_dir[x].low_ino = tpnt->low_ino;
 163         scsi_hba_dir[x].namelen = 1;
 164         scsi_hba_dir[x++].name = ".";
 165         scsi_hba_dir[x].low_ino = PROC_SCSI;
 166         scsi_hba_dir[x].namelen = 2;
 167         scsi_hba_dir[x++].name = "..";
 168 
 169         hpnt = scsi_hostlist;
 170         while (hpnt) {
 171             if (tpnt == hpnt->hostt) {
 172                 scsi_hba_dir[x].low_ino = PROC_SCSI_FILE + hpnt->host_no;
 173                 scsi_hba_dir[x].namelen = sprintf(names[y],"%d",hpnt->host_no);
 174                 scsi_hba_dir[x].name = names[y];
 175                 y++;
 176                 x++;
 177             }
 178             hpnt = hpnt->next;
 179         }
 180 
 181         scsi_hba_dir[x].low_ino = 0;
 182         scsi_hba_dir[x].namelen = 0;
 183         scsi_hba_dir[x++].name = NULL;
 184         tpnt = tpnt->next;
 185     }    
 186 }
 187 
 188 void build_proc_dir_entries(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190     Scsi_Host_Template *tpnt = scsi_hosts;
 191     
 192     uint newnum; 
 193     uint x;
 194     
 195     newnum = count_templates();
 196     
 197     scsi_dir[0].low_ino = PROC_SCSI;
 198     scsi_dir[0].namelen = 1;
 199     scsi_dir[0].name = ".";
 200     scsi_dir[1].low_ino = PROC_ROOT_INO;
 201     scsi_dir[1].namelen = 2;
 202     scsi_dir[1].name = "..";
 203     scsi_dir[2].low_ino = PROC_SCSI_SCSI;
 204     scsi_dir[2].namelen = 4;
 205     scsi_dir[2].name = "scsi";
 206 
 207     for(x = 3; x < newnum + 3; x++, tpnt = tpnt->next) { 
 208         scsi_dir[x].low_ino = tpnt->low_ino;
 209         scsi_dir[x].namelen = strlen(tpnt->procname);
 210         scsi_dir[x].name = tpnt->procname;
 211     }
 212 
 213     scsi_dir[x].low_ino = 0;
 214     scsi_dir[x].namelen = 0;
 215     scsi_dir[x].name = NULL;
 216     
 217     build_proc_dir_hba_entries();
 218 }
 219 
 220 
 221 /*
 222  *  parseHandle *parseInit(char *buf, char *cmdList, int cmdNum); 
 223  *              gets a pointer to a null terminated data buffer
 224  *              and a list of commands with blanks as delimiter 
 225  *      in between. 
 226  *      The commands have to be alphanumerically sorted. 
 227  *      cmdNum has to contain the number of commands.
 228  *              On success, a pointer to a handle structure
 229  *              is returned, NULL on failure
 230  *
 231  *      int parseOpt(parseHandle *handle, char **param);
 232  *              processes the next parameter. On success, the
 233  *              index of the appropriate command in the cmdList
 234  *              is returned, starting with zero.
 235  *              param points to the null terminated parameter string.
 236  *              On failure, -1 is returned.
 237  *
 238  *      The databuffer buf may only contain pairs of commands
 239  *          options, separated by blanks:
 240  *              <Command> <Parameter> [<Command> <Parameter>]*
 241  */
 242 
 243 typedef struct
 244 {
 245     char *buf,                             /* command buffer  */
 246          *cmdList,                         /* command list    */
 247          *bufPos,                          /* actual position */
 248          **cmdPos,                         /* cmdList index   */
 249          cmdNum;                           /* cmd number      */
 250 } parseHandle;
 251         
 252 
 253 inline int parseFree (parseHandle *handle)               /* free memory     */
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255     kfree (handle->cmdPos);
 256     kfree (handle);
 257     
 258     return(-1);
 259 }
 260 
 261         
 262 parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
     /* [previous][next][first][last][top][bottom][index][help] */
 263 {
 264     char        *ptr;                               /* temp pointer    */
 265     parseHandle *handle;                            /* new handle      */
 266     
 267     if (!buf || !cmdList)                           /* bad input ?     */
 268         return(NULL);
 269     if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), 1)) == 0)
 270         return(NULL);                               /* out of memory   */
 271     if ((handle->cmdPos = (char**) kmalloc(sizeof(int), cmdNum)) == 0) {
 272         kfree(handle);
 273         return(NULL);                               /* out of memory   */
 274     }
 275     
 276     handle->buf     = handle->bufPos = buf;         /* init handle     */
 277     handle->cmdList = cmdList;
 278     handle->cmdNum  = cmdNum;
 279     
 280     handle->cmdPos[cmdNum = 0] = cmdList;
 281     for (ptr = cmdList; *ptr; ptr++) {          /* scan command string */
 282         if(*ptr == ' ') {                       /* and insert zeroes   */
 283             *ptr++ = 0;
 284             handle->cmdPos[++cmdNum] = ptr++;
 285         } 
 286     }
 287     return(handle);
 288 }
 289 
 290 
 291 int parseOpt(parseHandle *handle, char **param)
     /* [previous][next][first][last][top][bottom][index][help] */
 292 {
 293     int  cmdIndex = 0, 
 294          cmdLen = 0;
 295     char *startPos;
 296     
 297     if (!handle)                                    /* invalid handle  */
 298         return(parseFree(handle));
 299     /* skip spaces     */  
 300     for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
 301     if (!*(handle->bufPos))
 302         return(parseFree(handle));                  /* end of data     */
 303     
 304     startPos = handle->bufPos;                      /* store cmd start */
 305     for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++)
 306     {                                               /* no string end?  */
 307         for (;;)
 308         {
 309             if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
 310                 break;                              /* char matches ?  */
 311             else
 312                 if (memcmp(startPos, (char*)(handle->cmdPos[++cmdIndex]), cmdLen))
 313                     return(parseFree(handle));      /* unknown command */
 314             
 315             if (cmdIndex >= handle->cmdNum)
 316                 return(parseFree(handle));          /* unknown command */     
 317         }
 318         
 319         cmdLen++;                                   /* next char       */
 320     }
 321     
 322     /* Get param. First skip all blanks, then insert zero after param  */
 323     
 324     for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
 325     *param = handle->bufPos; 
 326     
 327     for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
 328     *(handle->bufPos++) = 0;
 329     
 330     return(cmdIndex);
 331 }
 332 
 333 #define MAX_SCSI_DEVICE_CODE 10
 334 const char *const scsi_dev_types[MAX_SCSI_DEVICE_CODE] =
 335 {
 336     "Direct-Access    ",
 337     "Sequential-Access",
 338     "Printer          ",
 339     "Processor        ",
 340     "WORM             ",
 341     "CD-ROM           ",
 342     "Scanner          ",
 343     "Optical Device   ",
 344     "Medium Changer   ",
 345     "Communications   "
 346 };
 347 
 348 void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 349 {           
 350     int x, y = *size;
 351     
 352     y = sprintf(buffer + len, 
 353                     "Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
 354                     scd->channel, scd->id, scd->lun);
 355     for (x = 0; x < 8; x++) {
 356         if (scd->vendor[x] >= 0x20)
 357             y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
 358         else
 359             y += sprintf(buffer + len + y," ");
 360     }
 361     y += sprintf(buffer + len + y, " Model: ");
 362     for (x = 0; x < 16; x++) {
 363         if (scd->model[x] >= 0x20)
 364             y +=  sprintf(buffer + len + y, "%c", scd->model[x]);
 365         else
 366             y += sprintf(buffer + len + y, " ");
 367     }
 368     y += sprintf(buffer + len + y, " Rev: ");
 369     for (x = 0; x < 4; x++) {
 370         if (scd->rev[x] >= 0x20)
 371             y += sprintf(buffer + len + y, "%c", scd->rev[x]);
 372         else
 373             y += sprintf(buffer + len + y, " ");
 374     }
 375     y += sprintf(buffer + len + y, "\n");
 376     
 377     y += sprintf(buffer + len + y, "  Type:   %s ",
 378                      scd->type < MAX_SCSI_DEVICE_CODE ? 
 379                      scsi_dev_types[(int)scd->type] : "Unknown          " );
 380     y += sprintf(buffer + len + y, "               ANSI"
 381                      " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
 382     if (scd->scsi_level == 2)
 383         y += sprintf(buffer + len + y, " CCS\n");
 384     else
 385         y += sprintf(buffer + len + y, "\n");
 386 
 387     *size = y; 
 388     return;
 389 }
 390 
 391 /*
 392  * Overrides for Emacs so that we get a uniform tabbing style.
 393  * Emacs will notice this stuff at the end of the file and automatically
 394  * adjust the settings for this buffer only.  This must remain at the end
 395  * of the file.
 396  * ---------------------------------------------------------------------------
 397  * Local variables:
 398  * c-indent-level: 4
 399  * c-brace-imaginary-offset: 0
 400  * c-brace-offset: -4
 401  * c-argdecl-indent: 4
 402  * c-label-offset: -4
 403  * c-continued-statement-offset: 4
 404  * c-continued-brace-offset: 0
 405  * indent-tabs-mode: nil
 406  * tab-width: 8
 407  * End:
 408  */

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