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>
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>
39 extern int scsi_proc_info(char *, char **, off_t
, int, int, int);
42 struct proc_dir_entry entry
;
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
*),
58 return (-ENOSYS
); /* This is a no-op */
62 pos
= len
= sprintf(buffer
, "%s\n", info(sh
));
64 pos
= len
= sprintf(buffer
,
65 "The driver does not yet support the proc-fs\n");
71 *start
= buffer
+ (offset
- begin
); /* Start of wanted data */
72 len
-= (offset
- begin
);
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
92 return (scsi_proc_info(buffer
, start
, offset
, length
, 0, func
));
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
,
102 return (hpnt
->hostt
->proc_info(buffer
, start
, offset
,
103 length
, hpnt
->host_no
, func
));
110 static void scsi_proc_fill_inode(struct inode
*inode
, int fill
)
112 Scsi_Host_Template
*shpnt
;
115 while (shpnt
&& shpnt
->proc_dir
->low_ino
!= inode
->i_ino
)
117 if (!shpnt
|| !shpnt
->module
)
120 __MOD_INC_USE_COUNT(shpnt
->module
);
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
;
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",
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
);
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
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>]*
174 char *buf
, /* command buffer */
175 *cmdList
, /* command list */
176 *bufPos
, /* actual position */
177 **cmdPos
, /* cmdList index */
178 cmdNum
; /* cmd number */
182 inline int parseFree(parseHandle
* handle
)
184 kfree(handle
->cmdPos
);
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 ? */
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) {
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 */
212 handle
->cmdPos
[++cmdNum
] = ptr
++;
219 int parseOpt(parseHandle
* handle
, char **param
)
221 int cmdIndex
= 0, cmdLen
= 0;
224 if (!handle
) /* invalid handle */
225 return (parseFree(handle
));
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? */
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;
257 void proc_print_scsidevice(Scsi_Device
* scd
, char *buffer
, int *size
, int len
)
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
]);
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
]);
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
]);
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");
296 y
+= sprintf(buffer
+ len
+ y
, "\n");
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
315 * ---------------------------------------------------------------------------
318 * c-brace-imaginary-offset: 0
320 * c-argdecl-indent: 4
322 * c-continued-statement-offset: 4
323 * c-continued-brace-offset: 0
324 * indent-tabs-mode: nil