~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/scsi/scsi_proc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/malloc.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  */
 46 int 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  */
 74 static 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 
 94 static 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 (count > PROC_BLOCK_SIZE)
103                 return -EOVERFLOW;
104 
105         if (!(page = (char *) __get_free_page(GFP_KERNEL)))
106                 return -ENOMEM;
107         copy_from_user(page, buf, count);
108 
109         if (hpnt->hostt->proc_info == NULL)
110                 ret = -ENOSYS;
111         else
112                 ret = hpnt->hostt->proc_info(page, &start, 0, count,
113                                                 hpnt->host_no, 1);
114         free_page((ulong) page);
115         return(ret);
116 }
117 
118 void build_proc_dir_entries(Scsi_Host_Template * tpnt)
119 {
120         struct Scsi_Host *hpnt;
121         char name[10];  /* see scsi_unregister_host() */
122 
123         tpnt->proc_dir = proc_mkdir(tpnt->proc_name, proc_scsi);
124         tpnt->proc_dir->owner = tpnt->module;
125 
126         hpnt = scsi_hostlist;
127         while (hpnt) {
128                 if (tpnt == hpnt->hostt) {
129                         struct proc_dir_entry *p;
130                         sprintf(name,"%d",hpnt->host_no);
131                         p = create_proc_read_entry(name,
132                                         S_IFREG | S_IRUGO | S_IWUSR,
133                                         tpnt->proc_dir,
134                                         proc_scsi_read,
135                                         (void *)hpnt);
136                         if (!p)
137                                 panic("Not enough memory to register SCSI HBA in /proc/scsi !\n");
138                         p->write_proc=proc_scsi_write;
139                         p->owner = tpnt->module;
140                 }
141                 hpnt = hpnt->next;
142         }
143 }
144 
145 /*
146  *  parseHandle *parseInit(char *buf, char *cmdList, int cmdNum); 
147  *              gets a pointer to a null terminated data buffer
148  *              and a list of commands with blanks as delimiter 
149  *      in between. 
150  *      The commands have to be alphanumerically sorted. 
151  *      cmdNum has to contain the number of commands.
152  *              On success, a pointer to a handle structure
153  *              is returned, NULL on failure
154  *
155  *      int parseOpt(parseHandle *handle, char **param);
156  *              processes the next parameter. On success, the
157  *              index of the appropriate command in the cmdList
158  *              is returned, starting with zero.
159  *              param points to the null terminated parameter string.
160  *              On failure, -1 is returned.
161  *
162  *      The databuffer buf may only contain pairs of commands
163  *          options, separated by blanks:
164  *              <Command> <Parameter> [<Command> <Parameter>]*
165  */
166 
167 typedef struct {
168         char *buf,              /* command buffer  */
169         *cmdList,               /* command list    */
170         *bufPos,                /* actual position */
171         **cmdPos,               /* cmdList index   */
172          cmdNum;                /* cmd number      */
173 } parseHandle;
174 
175 inline int parseFree(parseHandle * handle)
176 {                               /* free memory     */
177         kfree(handle->cmdPos);
178         kfree(handle);
179 
180         return -1;
181 }
182 
183 parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
184 {
185         char *ptr;              /* temp pointer    */
186         parseHandle *handle;    /* new handle      */
187 
188         if (!buf || !cmdList)   /* bad input ?     */
189                 return NULL;
190         handle = (parseHandle *) kmalloc(sizeof(parseHandle), GFP_KERNEL);
191         if (!handle)
192                 return NULL;    /* out of memory   */
193         handle->cmdPos = (char **) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL);
194         if (!handle->cmdPos) {
195                 kfree(handle);
196                 return NULL;    /* out of memory   */
197         }
198         handle->buf = handle->bufPos = buf;     /* init handle     */
199         handle->cmdList = cmdList;
200         handle->cmdNum = cmdNum;
201 
202         handle->cmdPos[cmdNum = 0] = cmdList;
203         for (ptr = cmdList; *ptr; ptr++) {      /* scan command string */
204                 if (*ptr == ' ') {      /* and insert zeroes   */
205                         *ptr++ = 0;
206                         handle->cmdPos[++cmdNum] = ptr++;
207                 }
208         }
209         return handle;
210 }
211 
212 int parseOpt(parseHandle * handle, char **param)
213 {
214         int cmdIndex = 0, cmdLen = 0;
215         char *startPos;
216 
217         if (!handle)            /* invalid handle  */
218                 return (parseFree(handle));
219         /* skip spaces     */
220         for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
221         if (!*(handle->bufPos))
222                 return (parseFree(handle));     /* end of data     */
223 
224         startPos = handle->bufPos;      /* store cmd start */
225         for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) {       /* no string end?  */
226                 for (;;) {
227                         if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
228                                 break;  /* char matches ?  */
229                         else if (memcmp(startPos, (char *) (handle->cmdPos[++cmdIndex]), cmdLen))
230                                 return (parseFree(handle));     /* unknown command */
231 
232                         if (cmdIndex >= handle->cmdNum)
233                                 return (parseFree(handle));     /* unknown command */
234                 }
235 
236                 cmdLen++;       /* next char       */
237         }
238 
239         /* Get param. First skip all blanks, then insert zero after param  */
240 
241         for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
242         *param = handle->bufPos;
243 
244         for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
245         *(handle->bufPos++) = 0;
246 
247         return (cmdIndex);
248 }
249 
250 void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
251 {
252 
253         int x, y = *size;
254         extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
255 
256         y = sprintf(buffer + len,
257              "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
258                     scd->host->host_no, scd->channel, scd->id, scd->lun);
259         for (x = 0; x < 8; x++) {
260                 if (scd->vendor[x] >= 0x20)
261                         y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
262                 else
263                         y += sprintf(buffer + len + y, " ");
264         }
265         y += sprintf(buffer + len + y, " Model: ");
266         for (x = 0; x < 16; x++) {
267                 if (scd->model[x] >= 0x20)
268                         y += sprintf(buffer + len + y, "%c", scd->model[x]);
269                 else
270                         y += sprintf(buffer + len + y, " ");
271         }
272         y += sprintf(buffer + len + y, " Rev: ");
273         for (x = 0; x < 4; x++) {
274                 if (scd->rev[x] >= 0x20)
275                         y += sprintf(buffer + len + y, "%c", scd->rev[x]);
276                 else
277                         y += sprintf(buffer + len + y, " ");
278         }
279         y += sprintf(buffer + len + y, "\n");
280 
281         y += sprintf(buffer + len + y, "  Type:   %s ",
282                      scd->type < MAX_SCSI_DEVICE_CODE ?
283                scsi_device_types[(int) scd->type] : "Unknown          ");
284         y += sprintf(buffer + len + y, "               ANSI"
285                      " SCSI revision: %02x", (scd->scsi_level - 1) ? scd->scsi_level - 1 : 1);
286         if (scd->scsi_level == 2)
287                 y += sprintf(buffer + len + y, " CCS\n");
288         else
289                 y += sprintf(buffer + len + y, "\n");
290 
291         *size = y;
292         return;
293 }
294 
295 #else                           /* if !CONFIG_PROC_FS */
296 
297 void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
298 {
299 }
300 
301 #endif                          /* CONFIG_PROC_FS */
302 
303 /*
304  * Overrides for Emacs so that we get a uniform tabbing style.
305  * Emacs will notice this stuff at the end of the file and automatically
306  * adjust the settings for this buffer only.  This must remain at the end
307  * of the file.
308  * ---------------------------------------------------------------------------
309  * Local variables:
310  * c-indent-level: 4
311  * c-brace-imaginary-offset: 0
312  * c-brace-offset: -4
313  * c-argdecl-indent: 4
314  * c-label-offset: -4
315  * c-continued-statement-offset: 4
316  * c-continued-brace-offset: 0
317  * indent-tabs-mode: nil
318  * tab-width: 8
319  * End:
320  */
321 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.