|
|
1.1 root 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 [email protected]
10: * Version: 0.99.8 last change: 95/09/13
11: *
12: * generic command parser provided by:
13: * Andreas Heilwagen <[email protected]>
14: */
15:
16: /*
17: * Don't import our own symbols, as this would severely mess up our
18: * symbol tables.
19: */
20: #define _SCSI_SYMS_VER_
21: #define __NO_VERSION__
22: #include <linux/module.h>
23:
24: #include <linux/string.h>
25: #include <linux/mm.h>
26: #include <linux/malloc.h>
27: #include <linux/proc_fs.h>
28: #include <linux/errno.h>
29: #include <linux/stat.h>
30: #include <linux/blk.h>
31: #include "scsi.h"
32: #include "hosts.h"
33:
34: #ifndef TRUE
35: #define TRUE 1
36: #define FALSE 0
37: #endif
38:
39: extern int scsi_proc_info(char *, char **, off_t, int, int, int);
40:
41: struct scsi_dir {
42: struct proc_dir_entry entry;
43: char name[4];
44: };
45:
46:
47: /* generic_proc_info
48: * Used if the driver currently has no own support for /proc/scsi
49: */
50: int generic_proc_info(char *buffer, char **start, off_t offset,
51: int length, int inode, int inout)
52: {
53: int len, pos, begin;
54:
55: if(inout == TRUE)
56: return(-ENOSYS); /* This is a no-op */
57:
58: begin = 0;
59: pos = len = sprintf(buffer,
60: "The driver does not yet support the proc-fs\n");
61: if(pos < offset) {
62: len = 0;
63: begin = pos;
64: }
65:
66: *start = buffer + (offset - begin); /* Start of wanted data */
67: len -= (offset - begin);
68: if(len > length)
69: len = length;
70:
71: return(len);
72: }
73:
74: /* dispatch_scsi_info is the central dispatcher
75: * It is the interface between the proc-fs and the SCSI subsystem code
76: */
77: extern int dispatch_scsi_info(int ino, char *buffer, char **start,
78: off_t offset, int length, int func)
79: {
80: struct Scsi_Host *hpnt = scsi_hostlist;
81:
82: if(ino == PROC_SCSI_SCSI) {
83: /*
84: * This is for the scsi core, rather than any specific
85: * lowlevel driver.
86: */
87: return(scsi_proc_info(buffer, start, offset, length, 0, func));
88: }
89:
90: while(hpnt) {
91: if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
92: if(hpnt->hostt->proc_info == NULL)
93: return generic_proc_info(buffer, start, offset, length,
94: hpnt->host_no, func);
95: else
96: return(hpnt->hostt->proc_info(buffer, start, offset,
97: length, hpnt->host_no, func));
98: }
99: hpnt = hpnt->next;
100: }
101: return(-EBADF);
102: }
103:
104: void build_proc_dir_entries(Scsi_Host_Template *tpnt)
105: {
106: struct Scsi_Host *hpnt;
107:
108: struct scsi_dir *scsi_hba_dir;
109:
110: proc_scsi_register(0, tpnt->proc_dir);
111:
112: hpnt = scsi_hostlist;
113: while (hpnt) {
114: if (tpnt == hpnt->hostt) {
115: scsi_hba_dir = scsi_init_malloc(sizeof(struct scsi_dir), GFP_KERNEL);
116: if(scsi_hba_dir == NULL)
117: panic("Not enough memory to register SCSI HBA in /proc/scsi !\n");
118: memset(scsi_hba_dir, 0, sizeof(struct scsi_dir));
119: scsi_hba_dir->entry.low_ino = PROC_SCSI_FILE + hpnt->host_no;
120: scsi_hba_dir->entry.namelen = sprintf(scsi_hba_dir->name,"%d",
121: hpnt->host_no);
122: scsi_hba_dir->entry.name = scsi_hba_dir->name;
123: scsi_hba_dir->entry.mode = S_IFREG | S_IRUGO | S_IWUSR;
124: proc_scsi_register(tpnt->proc_dir, &scsi_hba_dir->entry);
125: }
126: hpnt = hpnt->next;
127: }
128: }
129:
130: /*
131: * parseHandle *parseInit(char *buf, char *cmdList, int cmdNum);
132: * gets a pointer to a null terminated data buffer
133: * and a list of commands with blanks as delimiter
134: * in between.
135: * The commands have to be alphanumerically sorted.
136: * cmdNum has to contain the number of commands.
137: * On success, a pointer to a handle structure
138: * is returned, NULL on failure
139: *
140: * int parseOpt(parseHandle *handle, char **param);
141: * processes the next parameter. On success, the
142: * index of the appropriate command in the cmdList
143: * is returned, starting with zero.
144: * param points to the null terminated parameter string.
145: * On failure, -1 is returned.
146: *
147: * The databuffer buf may only contain pairs of commands
148: * options, separated by blanks:
149: * <Command> <Parameter> [<Command> <Parameter>]*
150: */
151:
152: typedef struct
153: {
154: char *buf, /* command buffer */
155: *cmdList, /* command list */
156: *bufPos, /* actual position */
157: **cmdPos, /* cmdList index */
158: cmdNum; /* cmd number */
159: } parseHandle;
160:
161:
162: inline int parseFree (parseHandle *handle) /* free memory */
163: {
164: kfree (handle->cmdPos);
165: kfree (handle);
166:
167: return(-1);
168: }
169:
170:
171: parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
172: {
173: char *ptr; /* temp pointer */
174: parseHandle *handle; /* new handle */
175:
176: if (!buf || !cmdList) /* bad input ? */
177: return(NULL);
178: if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), 1)) == 0)
179: return(NULL); /* out of memory */
180: if ((handle->cmdPos = (char**) kmalloc(sizeof(int), cmdNum)) == 0) {
181: kfree(handle);
182: return(NULL); /* out of memory */
183: }
184:
185: handle->buf = handle->bufPos = buf; /* init handle */
186: handle->cmdList = cmdList;
187: handle->cmdNum = cmdNum;
188:
189: handle->cmdPos[cmdNum = 0] = cmdList;
190: for (ptr = cmdList; *ptr; ptr++) { /* scan command string */
191: if(*ptr == ' ') { /* and insert zeroes */
192: *ptr++ = 0;
193: handle->cmdPos[++cmdNum] = ptr++;
194: }
195: }
196: return(handle);
197: }
198:
199:
200: int parseOpt(parseHandle *handle, char **param)
201: {
202: int cmdIndex = 0,
203: cmdLen = 0;
204: char *startPos;
205:
206: if (!handle) /* invalid handle */
207: return(parseFree(handle));
208: /* skip spaces */
209: for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
210: if (!*(handle->bufPos))
211: return(parseFree(handle)); /* end of data */
212:
213: startPos = handle->bufPos; /* store cmd start */
214: for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++)
215: { /* no string end? */
216: for (;;)
217: {
218: if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
219: break; /* char matches ? */
220: else
221: if (memcmp(startPos, (char*)(handle->cmdPos[++cmdIndex]), cmdLen))
222: return(parseFree(handle)); /* unknown command */
223:
224: if (cmdIndex >= handle->cmdNum)
225: return(parseFree(handle)); /* unknown command */
226: }
227:
228: cmdLen++; /* next char */
229: }
230:
231: /* Get param. First skip all blanks, then insert zero after param */
232:
233: for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
234: *param = handle->bufPos;
235:
236: for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
237: *(handle->bufPos++) = 0;
238:
239: return(cmdIndex);
240: }
241:
242: #define MAX_SCSI_DEVICE_CODE 10
243: const char *const scsi_dev_types[MAX_SCSI_DEVICE_CODE] =
244: {
245: "Direct-Access ",
246: "Sequential-Access",
247: "Printer ",
248: "Processor ",
249: "WORM ",
250: "CD-ROM ",
251: "Scanner ",
252: "Optical Device ",
253: "Medium Changer ",
254: "Communications "
255: };
256:
257: void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
258: {
259: int x, y = *size;
260:
261: y = sprintf(buffer + len,
262: "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
263: scd->host->host_no, scd->channel, scd->id, scd->lun);
264: for (x = 0; x < 8; x++) {
265: if (scd->vendor[x] >= 0x20)
266: y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
267: else
268: y += sprintf(buffer + len + y," ");
269: }
270: y += sprintf(buffer + len + y, " Model: ");
271: for (x = 0; x < 16; x++) {
272: if (scd->model[x] >= 0x20)
273: y += sprintf(buffer + len + y, "%c", scd->model[x]);
274: else
275: y += sprintf(buffer + len + y, " ");
276: }
277: y += sprintf(buffer + len + y, " Rev: ");
278: for (x = 0; x < 4; x++) {
279: if (scd->rev[x] >= 0x20)
280: y += sprintf(buffer + len + y, "%c", scd->rev[x]);
281: else
282: y += sprintf(buffer + len + y, " ");
283: }
284: y += sprintf(buffer + len + y, "\n");
285:
286: y += sprintf(buffer + len + y, " Type: %s ",
287: scd->type < MAX_SCSI_DEVICE_CODE ?
288: scsi_dev_types[(int)scd->type] : "Unknown " );
289: y += sprintf(buffer + len + y, " ANSI"
290: " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
291: if (scd->scsi_level == 2)
292: y += sprintf(buffer + len + y, " CCS\n");
293: else
294: y += sprintf(buffer + len + y, "\n");
295:
296: *size = y;
297: return;
298: }
299:
300: /*
301: * Overrides for Emacs so that we get a uniform tabbing style.
302: * Emacs will notice this stuff at the end of the file and automatically
303: * adjust the settings for this buffer only. This must remain at the end
304: * of the file.
305: * ---------------------------------------------------------------------------
306: * Local variables:
307: * c-indent-level: 4
308: * c-brace-imaginary-offset: 0
309: * c-brace-offset: -4
310: * c-argdecl-indent: 4
311: * c-label-offset: -4
312: * c-continued-statement-offset: 4
313: * c-continued-brace-offset: 0
314: * indent-tabs-mode: nil
315: * tab-width: 8
316: * End:
317: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.