linux-old/drivers/scsi/scsi_proc.c
<<
>>
Prefs
   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 * generic_proc_info() support of xxxx_info() by:
  16 * Michael A. Griffith <grif@acm.org>
  17 */
  18
  19#include <linux/config.h>       /* for CONFIG_PROC_FS */
  20#define __NO_VERSION__
  21#include <linux/module.h>
  22
  23#include <linux/string.h>
  24#include <linux/mm.h>
  25#include <linux/slab.h>
  26#include <linux/proc_fs.h>
  27#include <linux/errno.h>
  28#include <linux/stat.h>
  29#include <linux/blk.h>
  30
  31#include <asm/uaccess.h>
  32
  33#include "scsi.h"
  34#include "hosts.h"
  35
  36#ifndef TRUE
  37#define TRUE  1
  38#define FALSE 0
  39#endif
  40
  41#ifdef CONFIG_PROC_FS
  42
  43/* generic_proc_info
  44 * Used if the driver currently has no own support for /proc/scsi
  45 */
  46int generic_proc_info(char *buffer, char **start, off_t offset, int length, 
  47                      const char *(*info) (struct Scsi_Host *),
  48                      struct Scsi_Host *sh)
  49{
  50        int len, pos, begin;
  51
  52        begin = 0;
  53        if (info && sh) {
  54                pos = len = sprintf(buffer, "%s\n", info(sh));
  55        } else {
  56                pos = len = sprintf(buffer,
  57                        "The driver does not yet support the proc-fs\n");
  58        }
  59        if (pos < offset) {
  60                len = 0;
  61                begin = pos;
  62        }
  63        *start = buffer + (offset - begin);     /* Start of wanted data */
  64        len -= (offset - begin);
  65        if (len > length)
  66                len = length;
  67
  68        return (len);
  69}
  70
  71/* dispatch_scsi_info is the central dispatcher 
  72 * It is the interface between the proc-fs and the SCSI subsystem code
  73 */
  74static int proc_scsi_read(char *buffer, char **start, off_t offset,
  75        int length, int *eof, void *data)
  76{
  77        struct Scsi_Host *hpnt = data;
  78        int n;
  79
  80        if (hpnt->hostt->proc_info == NULL)
  81                n = generic_proc_info(buffer, start, offset, length,
  82                                      hpnt->hostt->info, hpnt);
  83        else
  84                n = (hpnt->hostt->proc_info(buffer, start, offset,
  85                                           length, hpnt->host_no, 0));
  86        *eof = (n<length);
  87        return n;
  88}
  89
  90#define PROC_BLOCK_SIZE (3*1024)     /* 4K page size, but our output routines 
  91                                      * use some slack for overruns 
  92                                      */
  93
  94static int proc_scsi_write(struct file * file, const char * buf,
  95                           unsigned long count, void *data)
  96{
  97        struct Scsi_Host *hpnt = data;
  98        ssize_t ret = 0;
  99        char * page;
 100        char *start;
 101    
 102        if (hpnt->hostt->proc_info == NULL)
 103                ret = -ENOSYS;
 104
 105        if (count > PROC_BLOCK_SIZE)
 106                return -EOVERFLOW;
 107
 108        if (!(page = (char *) __get_free_page(GFP_KERNEL)))
 109                return -ENOMEM;
 110        if(copy_from_user(page, buf, count))
 111        {
 112                free_page((ulong) page);
 113                return -EFAULT;
 114        }
 115
 116        ret = hpnt->hostt->proc_info(page, &start, 0, count,
 117                                     hpnt->host_no, 1);
 118
 119        free_page((ulong) page);
 120        return(ret);
 121}
 122
 123void build_proc_dir_entries(Scsi_Host_Template * tpnt)
 124{
 125        struct Scsi_Host *hpnt;
 126        char name[10];  /* see scsi_unregister_host() */
 127
 128        tpnt->proc_dir = proc_mkdir(tpnt->proc_name, proc_scsi);
 129        if (!tpnt->proc_dir) {
 130                printk(KERN_ERR "Unable to proc_mkdir in scsi.c/build_proc_dir_entries");
 131                return;
 132        }
 133        tpnt->proc_dir->owner = tpnt->module;
 134
 135        hpnt = scsi_hostlist;
 136        while (hpnt) {
 137                if (tpnt == hpnt->hostt) {
 138                        struct proc_dir_entry *p;
 139                        sprintf(name,"%d",hpnt->host_no);
 140                        p = create_proc_read_entry(name,
 141                                        S_IFREG | S_IRUGO | S_IWUSR,
 142                                        tpnt->proc_dir,
 143                                        proc_scsi_read,
 144                                        (void *)hpnt);
 145                        if (!p)
 146                                panic("Not enough memory to register SCSI HBA in /proc/scsi !\n");
 147                        p->write_proc=proc_scsi_write;
 148                        p->owner = tpnt->module;
 149                }
 150                hpnt = hpnt->next;
 151        }
 152}
 153
 154/*
 155 *  parseHandle *parseInit(char *buf, char *cmdList, int cmdNum); 
 156 *              gets a pointer to a null terminated data buffer
 157 *              and a list of commands with blanks as delimiter 
 158 *      in between. 
 159 *      The commands have to be alphanumerically sorted. 
 160 *      cmdNum has to contain the number of commands.
 161 *              On success, a pointer to a handle structure
 162 *              is returned, NULL on failure
 163 *
 164 *      int parseOpt(parseHandle *handle, char **param);
 165 *              processes the next parameter. On success, the
 166 *              index of the appropriate command in the cmdList
 167 *              is returned, starting with zero.
 168 *              param points to the null terminated parameter string.
 169 *              On failure, -1 is returned.
 170 *
 171 *      The databuffer buf may only contain pairs of commands
 172 *          options, separated by blanks:
 173 *              <Command> <Parameter> [<Command> <Parameter>]*
 174 */
 175
 176typedef struct {
 177        char *buf,              /* command buffer  */
 178        *cmdList,               /* command list    */
 179        *bufPos,                /* actual position */
 180        **cmdPos,               /* cmdList index   */
 181         cmdNum;                /* cmd number      */
 182} parseHandle;
 183
 184inline int parseFree(parseHandle * handle)
 185{                               /* free memory     */
 186        kfree(handle->cmdPos);
 187        kfree(handle);
 188
 189        return -1;
 190}
 191
 192parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
 193{
 194        char *ptr;              /* temp pointer    */
 195        parseHandle *handle;    /* new handle      */
 196
 197        if (!buf || !cmdList)   /* bad input ?     */
 198                return NULL;
 199        handle = (parseHandle *) kmalloc(sizeof(parseHandle), GFP_KERNEL);
 200        if (!handle)
 201                return NULL;    /* out of memory   */
 202        handle->cmdPos = (char **) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL);
 203        if (!handle->cmdPos) {
 204                kfree(handle);
 205                return NULL;    /* out of memory   */
 206        }
 207        handle->buf = handle->bufPos = buf;     /* init handle     */
 208        handle->cmdList = cmdList;
 209        handle->cmdNum = cmdNum;
 210
 211        handle->cmdPos[cmdNum = 0] = cmdList;
 212        for (ptr = cmdList; *ptr; ptr++) {      /* scan command string */
 213                if (*ptr == ' ') {      /* and insert zeroes   */
 214                        *ptr++ = 0;
 215                        handle->cmdPos[++cmdNum] = ptr++;
 216                }
 217        }
 218        return handle;
 219}
 220
 221int parseOpt(parseHandle * handle, char **param)
 222{
 223        int cmdIndex = 0, cmdLen = 0;
 224        char *startPos;
 225
 226        if (!handle)            /* invalid handle  */
 227                return (parseFree(handle));
 228        /* skip spaces     */
 229        for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
 230        if (!*(handle->bufPos))
 231                return (parseFree(handle));     /* end of data     */
 232
 233        startPos = handle->bufPos;      /* store cmd start */
 234        for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) {       /* no string end?  */
 235                for (;;) {
 236                        if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
 237                                break;  /* char matches ?  */
 238                        else if (memcmp(startPos, (char *) (handle->cmdPos[++cmdIndex]), cmdLen))
 239                                return (parseFree(handle));     /* unknown command */
 240
 241                        if (cmdIndex >= handle->cmdNum)
 242                                return (parseFree(handle));     /* unknown command */
 243                }
 244
 245                cmdLen++;       /* next char       */
 246        }
 247
 248        /* Get param. First skip all blanks, then insert zero after param  */
 249
 250        for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
 251        *param = handle->bufPos;
 252
 253        for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
 254        *(handle->bufPos++) = 0;
 255
 256        return (cmdIndex);
 257}
 258
 259void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
 260{
 261
 262        int x, y = *size;
 263        extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 264
 265        y = sprintf(buffer + len,
 266             "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
 267                    scd->host->host_no, scd->channel, scd->id, scd->lun);
 268        for (x = 0; x < 8; x++) {
 269                if (scd->vendor[x] >= 0x20)
 270                        y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
 271                else
 272                        y += sprintf(buffer + len + y, " ");
 273        }
 274        y += sprintf(buffer + len + y, " Model: ");
 275        for (x = 0; x < 16; x++) {
 276                if (scd->model[x] >= 0x20)
 277                        y += sprintf(buffer + len + y, "%c", scd->model[x]);
 278                else
 279                        y += sprintf(buffer + len + y, " ");
 280        }
 281        y += sprintf(buffer + len + y, " Rev: ");
 282        for (x = 0; x < 4; x++) {
 283                if (scd->rev[x] >= 0x20)
 284                        y += sprintf(buffer + len + y, "%c", scd->rev[x]);
 285                else
 286                        y += sprintf(buffer + len + y, " ");
 287        }
 288        y += sprintf(buffer + len + y, "\n");
 289
 290        y += sprintf(buffer + len + y, "  Type:   %s ",
 291                     scd->type < MAX_SCSI_DEVICE_CODE ?
 292               scsi_device_types[(int) scd->type] : "Unknown          ");
 293        y += sprintf(buffer + len + y, "               ANSI"
 294                     " SCSI revision: %02x", (scd->scsi_level - 1) ? scd->scsi_level - 1 : 1);
 295        if (scd->scsi_level == 2)
 296                y += sprintf(buffer + len + y, " CCS\n");
 297        else
 298                y += sprintf(buffer + len + y, "\n");
 299
 300        *size = y;
 301        return;
 302}
 303
 304#else                           /* if !CONFIG_PROC_FS */
 305
 306void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
 307{
 308}
 309
 310#endif                          /* CONFIG_PROC_FS */
 311
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.