Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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/module.h>
 20 #include <linux/init.h>
 21 #include <linux/string.h>
 22 #include <linux/mm.h>
 23 #include <linux/slab.h>
 24 #include <linux/proc_fs.h>
 25 #include <linux/errno.h>
 26 #include <linux/blkdev.h>
 27 #include <linux/seq_file.h>
 28 #include <asm/uaccess.h>
 29 
 30 #include <scsi/scsi.h>
 31 #include <scsi/scsi_device.h>
 32 #include <scsi/scsi_host.h>
 33 
 34 #include "scsi_priv.h"
 35 #include "scsi_logging.h"
 36 
 37 
 38 /* 4K page size, but our output routines, use some slack for overruns */
 39 #define PROC_BLOCK_SIZE (3*1024)
 40 
 41 static struct proc_dir_entry *proc_scsi;
 42 
 43 /* Protect sht->present and sht->proc_dir */
 44 static DECLARE_MUTEX(global_host_template_sem);
 45 
 46 static int proc_scsi_read(char *buffer, char **start, off_t offset,
 47                           int length, int *eof, void *data)
 48 {
 49         struct Scsi_Host *shost = data;
 50         int n;
 51 
 52         n = shost->hostt->proc_info(shost, buffer, start, offset, length, 0);
 53         *eof = (n < length);
 54 
 55         return n;
 56 }
 57 
 58 static int proc_scsi_write_proc(struct file *file, const char __user *buf,
 59                            unsigned long count, void *data)
 60 {
 61         struct Scsi_Host *shost = data;
 62         ssize_t ret = -ENOMEM;
 63         char *page;
 64         char *start;
 65     
 66         if (count > PROC_BLOCK_SIZE)
 67                 return -EOVERFLOW;
 68 
 69         page = (char *)__get_free_page(GFP_KERNEL);
 70         if (page) {
 71                 ret = -EFAULT;
 72                 if (copy_from_user(page, buf, count))
 73                         goto out;
 74                 ret = shost->hostt->proc_info(shost, page, &start, 0, count, 1);
 75         }
 76 out:
 77         free_page((unsigned long)page);
 78         return ret;
 79 }
 80 
 81 void scsi_proc_hostdir_add(struct scsi_host_template *sht)
 82 {
 83         if (!sht->proc_info)
 84                 return;
 85 
 86         down(&global_host_template_sem);
 87         if (!sht->present++) {
 88                 sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
 89                 if (!sht->proc_dir)
 90                         printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
 91                                __FUNCTION__, sht->proc_name);
 92                 else
 93                         sht->proc_dir->owner = sht->module;
 94         }
 95         up(&global_host_template_sem);
 96 }
 97 
 98 void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
 99 {
100         if (!sht->proc_info)
101                 return;
102 
103         down(&global_host_template_sem);
104         if (!--sht->present && sht->proc_dir) {
105                 remove_proc_entry(sht->proc_name, proc_scsi);
106                 sht->proc_dir = NULL;
107         }
108         up(&global_host_template_sem);
109 }
110 
111 void scsi_proc_host_add(struct Scsi_Host *shost)
112 {
113         struct scsi_host_template *sht = shost->hostt;
114         struct proc_dir_entry *p;
115         char name[10];
116 
117         if (!sht->proc_dir)
118                 return;
119 
120         sprintf(name,"%d", shost->host_no);
121         p = create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
122                         sht->proc_dir, proc_scsi_read, shost);
123         if (!p) {
124                 printk(KERN_ERR "%s: Failed to register host %d in"
125                        "%s\n", __FUNCTION__, shost->host_no,
126                        sht->proc_name);
127                 return;
128         } 
129 
130         p->write_proc = proc_scsi_write_proc;
131         p->owner = sht->module;
132 }
133 
134 void scsi_proc_host_rm(struct Scsi_Host *shost)
135 {
136         char name[10];
137 
138         if (!shost->hostt->proc_dir)
139                 return;
140 
141         sprintf(name,"%d", shost->host_no);
142         remove_proc_entry(name, shost->hostt->proc_dir);
143 }
144 
145 static int proc_print_scsidevice(struct device *dev, void *data)
146 {
147         struct scsi_device *sdev = to_scsi_device(dev);
148         struct seq_file *s = data;
149         int i;
150 
151         seq_printf(s,
152                 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
153                 sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
154         for (i = 0; i < 8; i++) {
155                 if (sdev->vendor[i] >= 0x20)
156                         seq_printf(s, "%c", sdev->vendor[i]);
157                 else
158                         seq_printf(s, " ");
159         }
160 
161         seq_printf(s, " Model: ");
162         for (i = 0; i < 16; i++) {
163                 if (sdev->model[i] >= 0x20)
164                         seq_printf(s, "%c", sdev->model[i]);
165                 else
166                         seq_printf(s, " ");
167         }
168 
169         seq_printf(s, " Rev: ");
170         for (i = 0; i < 4; i++) {
171                 if (sdev->rev[i] >= 0x20)
172                         seq_printf(s, "%c", sdev->rev[i]);
173                 else
174                         seq_printf(s, " ");
175         }
176 
177         seq_printf(s, "\n");
178 
179         seq_printf(s, "  Type:   %s ",
180                      sdev->type < MAX_SCSI_DEVICE_CODE ?
181                scsi_device_types[(int) sdev->type] : "Unknown          ");
182         seq_printf(s, "               ANSI"
183                      " SCSI revision: %02x", (sdev->scsi_level - 1) ?
184                      sdev->scsi_level - 1 : 1);
185         if (sdev->scsi_level == 2)
186                 seq_printf(s, " CCS\n");
187         else
188                 seq_printf(s, "\n");
189 
190         return 0;
191 }
192 
193 static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
194 {
195         struct Scsi_Host *shost;
196         int error = -ENXIO;
197 
198         shost = scsi_host_lookup(host);
199         if (IS_ERR(shost))
200                 return PTR_ERR(shost);
201 
202         error = scsi_scan_host_selected(shost, channel, id, lun, 1);
203         scsi_host_put(shost);
204         return error;
205 }
206 
207 static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
208 {
209         struct scsi_device *sdev;
210         struct Scsi_Host *shost;
211         int error = -ENXIO;
212 
213         shost = scsi_host_lookup(host);
214         if (IS_ERR(shost))
215                 return PTR_ERR(shost);
216         sdev = scsi_device_lookup(shost, channel, id, lun);
217         if (sdev) {
218                 scsi_remove_device(sdev);
219                 scsi_device_put(sdev);
220                 error = 0;
221         }
222 
223         scsi_host_put(shost);
224         return error;
225 }
226 
227 static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
228                                size_t length, loff_t *ppos)
229 {
230         int host, channel, id, lun;
231         char *buffer, *p;
232         int err;
233 
234         if (!buf || length > PAGE_SIZE)
235                 return -EINVAL;
236 
237         buffer = (char *)__get_free_page(GFP_KERNEL);
238         if (!buffer)
239                 return -ENOMEM;
240 
241         err = -EFAULT;
242         if (copy_from_user(buffer, buf, length))
243                 goto out;
244 
245         err = -EINVAL;
246         if (length < PAGE_SIZE)
247                 buffer[length] = '\0';
248         else if (buffer[PAGE_SIZE-1])
249                 goto out;
250 
251         /*
252          * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
253          * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
254          */
255         if (!strncmp("scsi add-single-device", buffer, 22)) {
256                 p = buffer + 23;
257 
258                 host = simple_strtoul(p, &p, 0);
259                 channel = simple_strtoul(p + 1, &p, 0);
260                 id = simple_strtoul(p + 1, &p, 0);
261                 lun = simple_strtoul(p + 1, &p, 0);
262 
263                 err = scsi_add_single_device(host, channel, id, lun);
264                 if (err >= 0)
265                         err = length;
266 
267         /*
268          * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
269          * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
270          */
271         } else if (!strncmp("scsi remove-single-device", buffer, 25)) {
272                 p = buffer + 26;
273 
274                 host = simple_strtoul(p, &p, 0);
275                 channel = simple_strtoul(p + 1, &p, 0);
276                 id = simple_strtoul(p + 1, &p, 0);
277                 lun = simple_strtoul(p + 1, &p, 0);
278 
279                 err = scsi_remove_single_device(host, channel, id, lun);
280         }
281 
282  out:
283         free_page((unsigned long)buffer);
284         return err;
285 }
286 
287 static int proc_scsi_show(struct seq_file *s, void *p)
288 {
289         seq_printf(s, "Attached devices:\n");
290         bus_for_each_dev(&scsi_bus_type, NULL, s, proc_print_scsidevice);
291         return 0;
292 }
293 
294 static int proc_scsi_open(struct inode *inode, struct file *file)
295 {
296         /*
297          * We don't really needs this for the write case but it doesn't
298          * harm either.
299          */
300         return single_open(file, proc_scsi_show, NULL);
301 }
302 
303 static struct file_operations proc_scsi_operations = {
304         .open           = proc_scsi_open,
305         .read           = seq_read,
306         .write          = proc_scsi_write,
307         .llseek         = seq_lseek,
308         .release        = single_release,
309 };
310 
311 int __init scsi_init_procfs(void)
312 {
313         struct proc_dir_entry *pde;
314 
315         proc_scsi = proc_mkdir("scsi", NULL);
316         if (!proc_scsi)
317                 goto err1;
318 
319         pde = create_proc_entry("scsi/scsi", 0, NULL);
320         if (!pde)
321                 goto err2;
322         pde->proc_fops = &proc_scsi_operations;
323 
324         return 0;
325 
326 err2:
327         remove_proc_entry("scsi", NULL);
328 err1:
329         return -ENOMEM;
330 }
331 
332 void scsi_exit_procfs(void)
333 {
334         remove_proc_entry("scsi/scsi", NULL);
335         remove_proc_entry("scsi", NULL);
336 }
337 
  This page was automatically generated by the LXR engine.