Linux-2.3.7.. Let's be careful out there..
[davej-history.git] / fs / proc / scsi.c
blobae2679b6d1d7002412810659a5ab7773c16b0a89
1 /*
2 * linux/fs/proc/scsi.c
3 * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
5 * The original version was derived from linux/fs/proc/net.c,
6 * which is Copyright (C) 1991, 1992 Linus Torvalds.
7 * Much has been rewritten, but some of the code still remains.
9 * /proc/scsi directory handling functions
11 * last change: 95/07/04
13 * Initial version: March '95
14 * 95/05/15 Added subdirectories for each driver and show every
15 * registered HBA as a single file.
16 * 95/05/30 Added rudimentary write support for parameter passing
17 * 95/07/04 Fixed bugs in directory handling
18 * 95/09/13 Update to support the new proc-dir tree
20 * TODO: Improve support to write to the driver files
21 * Add some more comments
23 #include <linux/errno.h>
24 #include <linux/sched.h>
25 #include <linux/proc_fs.h>
26 #include <linux/stat.h>
27 #include <linux/mm.h>
29 #include <asm/uaccess.h>
31 /* forward references */
32 static ssize_t proc_readscsi(struct file * file, char * buf,
33 size_t count, loff_t *ppos);
34 static ssize_t proc_writescsi(struct file * file, const char * buf,
35 size_t count, loff_t *ppos);
36 static long long proc_scsilseek(struct file *, long long, int);
38 extern void build_proc_dir_hba_entries(uint);
40 /* the *_get_info() functions are in the respective scsi driver code */
41 int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
42 off_t offset, int length, int inout) = 0;
44 static struct file_operations proc_scsi_operations = {
45 proc_scsilseek, /* lseek */
46 proc_readscsi, /* read */
47 proc_writescsi, /* write */
48 proc_readdir, /* readdir */
49 NULL, /* poll */
50 NULL, /* ioctl */
51 NULL, /* mmap */
52 NULL, /* no special open code */
53 NULL, /* flush */
54 NULL, /* no special release code */
55 NULL /* can't fsync */
59 * proc directories can do almost nothing..
61 struct inode_operations proc_scsi_inode_operations = {
62 &proc_scsi_operations, /* default scsi directory file-ops */
63 NULL, /* create */
64 proc_lookup, /* lookup */
65 NULL, /* link */
66 NULL, /* unlink */
67 NULL, /* symlink */
68 NULL, /* mkdir */
69 NULL, /* rmdir */
70 NULL, /* mknod */
71 NULL, /* rename */
72 NULL, /* readlink */
73 NULL, /* follow_link */
74 NULL, /* bmap */
75 NULL, /* readpage */
76 NULL, /* writepage */
77 NULL, /* flushpage */
78 NULL, /* truncate */
79 NULL, /* permission */
80 NULL, /* smap */
81 NULL /* revalidate */
84 int get_not_present_info(char *buffer, char **start, off_t offset, int length)
86 int len, pos, begin;
88 begin = 0;
89 pos = len = sprintf(buffer,
90 "No low-level scsi modules are currently present\n");
91 if(pos < offset) {
92 len = 0;
93 begin = pos;
96 *start = buffer + (offset - begin); /* Start of wanted data */
97 len -= (offset - begin);
98 if(len > length)
99 len = length;
101 return(len);
104 #define PROC_BLOCK_SIZE (3*1024) /* 4K page size, but our output routines
105 * use some slack for overruns
108 static ssize_t proc_readscsi(struct file * file, char * buf,
109 size_t count, loff_t *ppos)
111 struct inode * inode = file->f_dentry->d_inode;
112 ssize_t length;
113 ssize_t bytes = count;
114 ssize_t copied = 0;
115 ssize_t thistime;
116 char * page;
117 char * start;
119 if (!(page = (char *) __get_free_page(GFP_KERNEL)))
120 return(-ENOMEM);
122 while (bytes > 0) {
123 thistime = bytes;
124 if(bytes > PROC_BLOCK_SIZE)
125 thistime = PROC_BLOCK_SIZE;
127 if(dispatch_scsi_info_ptr)
128 length = dispatch_scsi_info_ptr(inode->i_ino, page, &start,
129 *ppos, thistime, 0);
130 else
131 length = get_not_present_info(page, &start, *ppos, thistime);
132 if(length < 0) {
133 free_page((ulong) page);
134 return(length);
138 * We have been given a non page aligned block of
139 * the data we asked for + a bit. We have been given
140 * the start pointer and we know the length..
142 if (length <= 0)
143 break;
145 * Copy the bytes
147 copy_to_user(buf + copied, start, length);
148 *ppos += length; /* Move down the file */
149 bytes -= length;
150 copied += length;
152 if(length < thistime)
153 break; /* End of file */
157 free_page((ulong) page);
158 return(copied);
162 static ssize_t proc_writescsi(struct file * file, const char * buf,
163 size_t count, loff_t *ppos)
165 struct inode * inode = file->f_dentry->d_inode;
166 ssize_t ret = 0;
167 char * page;
169 if(count > PROC_BLOCK_SIZE) {
170 return(-EOVERFLOW);
173 if(dispatch_scsi_info_ptr != NULL) {
174 if (!(page = (char *) __get_free_page(GFP_KERNEL)))
175 return(-ENOMEM);
176 copy_from_user(page, buf, count);
177 ret = dispatch_scsi_info_ptr(inode->i_ino, page, 0, 0, count, 1);
178 } else
179 return(-ENOPKG); /* Nothing here */
181 free_page((ulong) page);
182 return(ret);
186 static long long proc_scsilseek(struct file * file, long long offset, int orig)
188 switch (orig) {
189 case 0:
190 file->f_pos = offset;
191 return(file->f_pos);
192 case 1:
193 file->f_pos += offset;
194 return(file->f_pos);
195 case 2:
196 return(-EINVAL);
197 default:
198 return(-EINVAL);
203 * Overrides for Emacs so that we almost follow Linus's tabbing style.
204 * Emacs will notice this stuff at the end of the file and automatically
205 * adjust the settings for this buffer only. This must remain at the end
206 * of the file.
207 * ---------------------------------------------------------------------------
208 * Local variables:
209 * c-indent-level: 4
210 * c-brace-imaginary-offset: 0
211 * c-brace-offset: -4
212 * c-argdecl-indent: 4
213 * c-label-offset: -4
214 * c-continued-statement-offset: 4
215 * c-continued-brace-offset: 0
216 * indent-tabs-mode: nil
217 * tab-width: 8
218 * End: