* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / drivers / scsi / scsi_proc.c
blobcddb6c90a50516a8a28619f33c17a58ebbeb75aa
1 /*
2 * linux/drivers/scsi/scsi_proc.c
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.
9 * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
10 * Version: 0.99.8 last change: 95/09/13
12 * generic command parser provided by:
13 * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
15 * generic_proc_info() support of xxxx_info() by:
16 * Michael A. Griffith <grif@acm.org>
19 #include <linux/config.h> /* for CONFIG_PROC_FS */
20 #define __NO_VERSION__
21 #include <linux/module.h>
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 #include "scsi.h"
31 #include "hosts.h"
33 #ifndef TRUE
34 #define TRUE 1
35 #define FALSE 0
36 #endif
38 #ifdef CONFIG_PROC_FS
39 extern int scsi_proc_info(char *, char **, off_t, int, int, int);
41 struct scsi_dir {
42 struct proc_dir_entry entry;
43 char name[4];
47 /* generic_proc_info
48 * Used if the driver currently has no own support for /proc/scsi
50 int generic_proc_info(char *buffer, char **start, off_t offset,
51 int length, int inode, int inout,
52 const char *(*info) (struct Scsi_Host *),
53 struct Scsi_Host *sh)
55 int len, pos, begin;
57 if (inout == TRUE)
58 return (-ENOSYS); /* This is a no-op */
60 begin = 0;
61 if (info && sh) {
62 pos = len = sprintf(buffer, "%s\n", info(sh));
63 } else {
64 pos = len = sprintf(buffer,
65 "The driver does not yet support the proc-fs\n");
67 if (pos < offset) {
68 len = 0;
69 begin = pos;
71 *start = buffer + (offset - begin); /* Start of wanted data */
72 len -= (offset - begin);
73 if (len > length)
74 len = length;
76 return (len);
79 /* dispatch_scsi_info is the central dispatcher
80 * It is the interface between the proc-fs and the SCSI subsystem code
82 extern int dispatch_scsi_info(int ino, char *buffer, char **start,
83 off_t offset, int length, int func)
85 struct Scsi_Host *hpnt = scsi_hostlist;
87 if (ino == PROC_SCSI_SCSI) {
89 * This is for the scsi core, rather than any specific
90 * lowlevel driver.
92 return (scsi_proc_info(buffer, start, offset, length, 0, func));
94 while (hpnt) {
95 if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
96 if (hpnt->hostt->proc_info == NULL)
97 return generic_proc_info(buffer, start, offset, length,
98 hpnt->host_no, func,
99 hpnt->hostt->info,
100 hpnt);
101 else
102 return (hpnt->hostt->proc_info(buffer, start, offset,
103 length, hpnt->host_no, func));
105 hpnt = hpnt->next;
107 return (-EBADF);
110 static void scsi_proc_fill_inode(struct inode *inode, int fill)
112 Scsi_Host_Template *shpnt;
114 shpnt = scsi_hosts;
115 while (shpnt && shpnt->proc_dir->low_ino != inode->i_ino)
116 shpnt = shpnt->next;
117 if (!shpnt || !shpnt->module)
118 return;
119 if (fill)
120 __MOD_INC_USE_COUNT(shpnt->module);
121 else
122 __MOD_DEC_USE_COUNT(shpnt->module);
125 void build_proc_dir_entries(Scsi_Host_Template * tpnt)
127 struct Scsi_Host *hpnt;
128 struct scsi_dir *scsi_hba_dir;
130 proc_scsi_register(0, tpnt->proc_dir);
131 tpnt->proc_dir->fill_inode = &scsi_proc_fill_inode;
133 hpnt = scsi_hostlist;
134 while (hpnt) {
135 if (tpnt == hpnt->hostt) {
136 scsi_hba_dir = scsi_init_malloc(sizeof(struct scsi_dir), GFP_KERNEL);
137 if (scsi_hba_dir == NULL)
138 panic("Not enough memory to register SCSI HBA in /proc/scsi !\n");
139 memset(scsi_hba_dir, 0, sizeof(struct scsi_dir));
140 scsi_hba_dir->entry.low_ino = PROC_SCSI_FILE + hpnt->host_no;
141 scsi_hba_dir->entry.namelen = sprintf(scsi_hba_dir->name, "%d",
142 hpnt->host_no);
143 scsi_hba_dir->entry.name = scsi_hba_dir->name;
144 scsi_hba_dir->entry.mode = S_IFREG | S_IRUGO | S_IWUSR;
145 proc_scsi_register(tpnt->proc_dir, &scsi_hba_dir->entry);
147 hpnt = hpnt->next;
152 * parseHandle *parseInit(char *buf, char *cmdList, int cmdNum);
153 * gets a pointer to a null terminated data buffer
154 * and a list of commands with blanks as delimiter
155 * in between.
156 * The commands have to be alphanumerically sorted.
157 * cmdNum has to contain the number of commands.
158 * On success, a pointer to a handle structure
159 * is returned, NULL on failure
161 * int parseOpt(parseHandle *handle, char **param);
162 * processes the next parameter. On success, the
163 * index of the appropriate command in the cmdList
164 * is returned, starting with zero.
165 * param points to the null terminated parameter string.
166 * On failure, -1 is returned.
168 * The databuffer buf may only contain pairs of commands
169 * options, separated by blanks:
170 * <Command> <Parameter> [<Command> <Parameter>]*
173 typedef struct {
174 char *buf, /* command buffer */
175 *cmdList, /* command list */
176 *bufPos, /* actual position */
177 **cmdPos, /* cmdList index */
178 cmdNum; /* cmd number */
179 } parseHandle;
182 inline int parseFree(parseHandle * handle)
183 { /* free memory */
184 kfree(handle->cmdPos);
185 kfree(handle);
187 return (-1);
191 parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
193 char *ptr; /* temp pointer */
194 parseHandle *handle; /* new handle */
196 if (!buf || !cmdList) /* bad input ? */
197 return (NULL);
198 if ((handle = (parseHandle *) kmalloc(sizeof(parseHandle), GFP_KERNEL)) == 0)
199 return (NULL); /* out of memory */
200 if ((handle->cmdPos = (char **) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL)) == 0) {
201 kfree(handle);
202 return (NULL); /* out of memory */
204 handle->buf = handle->bufPos = buf; /* init handle */
205 handle->cmdList = cmdList;
206 handle->cmdNum = cmdNum;
208 handle->cmdPos[cmdNum = 0] = cmdList;
209 for (ptr = cmdList; *ptr; ptr++) { /* scan command string */
210 if (*ptr == ' ') { /* and insert zeroes */
211 *ptr++ = 0;
212 handle->cmdPos[++cmdNum] = ptr++;
215 return (handle);
219 int parseOpt(parseHandle * handle, char **param)
221 int cmdIndex = 0, cmdLen = 0;
222 char *startPos;
224 if (!handle) /* invalid handle */
225 return (parseFree(handle));
226 /* skip spaces */
227 for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
228 if (!*(handle->bufPos))
229 return (parseFree(handle)); /* end of data */
231 startPos = handle->bufPos; /* store cmd start */
232 for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) { /* no string end? */
233 for (;;) {
234 if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
235 break; /* char matches ? */
236 else if (memcmp(startPos, (char *) (handle->cmdPos[++cmdIndex]), cmdLen))
237 return (parseFree(handle)); /* unknown command */
239 if (cmdIndex >= handle->cmdNum)
240 return (parseFree(handle)); /* unknown command */
243 cmdLen++; /* next char */
246 /* Get param. First skip all blanks, then insert zero after param */
248 for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
249 *param = handle->bufPos;
251 for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
252 *(handle->bufPos++) = 0;
254 return (cmdIndex);
257 void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
260 int x, y = *size;
261 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
263 y = sprintf(buffer + len,
264 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
265 scd->host->host_no, scd->channel, scd->id, scd->lun);
266 for (x = 0; x < 8; x++) {
267 if (scd->vendor[x] >= 0x20)
268 y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
269 else
270 y += sprintf(buffer + len + y, " ");
272 y += sprintf(buffer + len + y, " Model: ");
273 for (x = 0; x < 16; x++) {
274 if (scd->model[x] >= 0x20)
275 y += sprintf(buffer + len + y, "%c", scd->model[x]);
276 else
277 y += sprintf(buffer + len + y, " ");
279 y += sprintf(buffer + len + y, " Rev: ");
280 for (x = 0; x < 4; x++) {
281 if (scd->rev[x] >= 0x20)
282 y += sprintf(buffer + len + y, "%c", scd->rev[x]);
283 else
284 y += sprintf(buffer + len + y, " ");
286 y += sprintf(buffer + len + y, "\n");
288 y += sprintf(buffer + len + y, " Type: %s ",
289 scd->type < MAX_SCSI_DEVICE_CODE ?
290 scsi_device_types[(int) scd->type] : "Unknown ");
291 y += sprintf(buffer + len + y, " ANSI"
292 " SCSI revision: %02x", (scd->scsi_level - 1) ? scd->scsi_level - 1 : 1);
293 if (scd->scsi_level == 2)
294 y += sprintf(buffer + len + y, " CCS\n");
295 else
296 y += sprintf(buffer + len + y, "\n");
298 *size = y;
299 return;
302 #else
304 void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
308 #endif /* CONFIG_PROC_FS */
311 * Overrides for Emacs so that we get a uniform tabbing style.
312 * Emacs will notice this stuff at the end of the file and automatically
313 * adjust the settings for this buffer only. This must remain at the end
314 * of the file.
315 * ---------------------------------------------------------------------------
316 * Local variables:
317 * c-indent-level: 4
318 * c-brace-imaginary-offset: 0
319 * c-brace-offset: -4
320 * c-argdecl-indent: 4
321 * c-label-offset: -4
322 * c-continued-statement-offset: 4
323 * c-continued-brace-offset: 0
324 * indent-tabs-mode: nil
325 * tab-width: 8
326 * End: