* [PATCH] move all procfs code to scsi_proc.c
@ 2002-11-16 19:02 Christoph Hellwig
2002-11-16 20:01 ` Patrick Mansfield
0 siblings, 1 reply; 3+ messages in thread
From: Christoph Hellwig @ 2002-11-16 19:02 UTC (permalink / raw)
To: James.Bottomley; +Cc: linux-scsi
scsi.c gets really far too big, and having all code that depends on
CONFIG_PROC_FS in scsi_proc.c is a nice cleanup. Note that much of
the procfs code is really really ugly and wants a rewrite to at
least use the seq_file interface and probably moving to sysfs.
(the patch was much nicer before Pat's dynamic blacklist changes,
now I need to de-privatize two symbols)
===== drivers/scsi/Makefile 1.31 vs edited =====
--- 1.31/drivers/scsi/Makefile Fri Jun 21 06:09:54 2002
+++ edited/drivers/scsi/Makefile Sat Nov 16 17:28:08 2002
@@ -18,7 +18,7 @@
CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
-export-objs := scsi_syms.o 53c700.o
+export-objs := scsi_syms.o scsi_proc.o 53c700.o
subdir-$(CONFIG_PCMCIA) += pcmcia
@@ -123,8 +123,11 @@
obj-$(CONFIG_CHR_DEV_SG) += sg.o
scsi_mod-objs := scsi.o hosts.o scsi_ioctl.o constants.o scsicam.o \
- scsi_proc.o scsi_error.o scsi_lib.o scsi_scan.o \
- scsi_syms.o
+ scsi_error.o scsi_lib.o scsi_scan.o scsi_syms.o
+
+ifdef CONFIG_PROC_FS
+scsi_mod-objs += scsi_proc.o
+endif
sd_mod-objs := sd.o
sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o
===== drivers/scsi/hosts.c 1.27 vs edited =====
--- 1.27/drivers/scsi/hosts.c Thu Nov 14 13:19:04 2002
+++ edited/drivers/scsi/hosts.c Sat Nov 16 17:28:08 2002
@@ -352,11 +352,7 @@
shost->hostt->present--;
/* Cleanup proc and driverfs */
-#ifdef CONFIG_PROC_FS
scsi_proc_host_rm(shost);
- if (!shost->hostt->present)
- remove_proc_entry(shost->hostt->proc_name, proc_scsi);
-#endif
device_unregister(&shost->host_driverfs_dev);
kfree(shost);
@@ -470,12 +466,7 @@
found:
spin_unlock(&scsi_host_list_lock);
-#ifdef CONFIG_PROC_FS
- /* Add the new driver to /proc/scsi if not already there */
- if (!shost_tp->proc_dir)
- scsi_proc_host_mkdir(shost_tp);
scsi_proc_host_add(shost);
-#endif
strncpy(shost->host_driverfs_dev.name, shost_tp->proc_name,
DEVICE_NAME_SIZE-1);
===== drivers/scsi/hosts.h 1.36 vs edited =====
--- 1.36/drivers/scsi/hosts.h Thu Nov 14 13:07:27 2002
+++ edited/drivers/scsi/hosts.h Sat Nov 16 17:28:08 2002
@@ -509,10 +509,6 @@
unsigned short host_registered;
} Scsi_Host_Name;
-extern void scsi_proc_host_mkdir(Scsi_Host_Template *);
-extern void scsi_proc_host_add(struct Scsi_Host *);
-extern void scsi_proc_host_rm(struct Scsi_Host *);
-
extern void scsi_register_blocked_host(struct Scsi_Host *);
extern void scsi_deregister_blocked_host(struct Scsi_Host *);
===== drivers/scsi/scsi.c 1.61 vs edited =====
--- 1.61/drivers/scsi/scsi.c Thu Nov 14 13:19:04 2002
+++ edited/drivers/scsi/scsi.c Sat Nov 16 18:26:47 2002
@@ -74,13 +74,6 @@
#include <linux/kmod.h>
#endif
-struct proc_dir_entry *proc_scsi;
-
-#ifdef CONFIG_PROC_FS
-static int scsi_proc_info(char *buffer, char **start, off_t offset, int length);
-static void scsi_dump_status(int level);
-#endif
-
#define SG_MEMPOOL_NR 5
#define SG_MEMPOOL_SIZE 32
@@ -166,7 +159,7 @@
static const char * const spaces = " "; /* 16 of them */
static unsigned scsi_default_dev_flags;
-static LIST_HEAD(scsi_dev_info_list);
+LIST_HEAD(scsi_dev_info_list);
/*
* Function prototypes.
@@ -1762,7 +1755,7 @@
*
* Returns: 0 if OK, -error on failure.
**/
-static int scsi_dev_info_list_add_str (char *dev_list)
+int scsi_dev_info_list_add_str (char *dev_list)
{
char *vendor, *model, *strflags, *next;
char *next_check;
@@ -1908,367 +1901,6 @@
return scsi_default_dev_flags;
}
-#ifdef CONFIG_PROC_FS
-/*
- * proc_scsi_dev_info_read: dump the scsi_dev_info_list via
- * /proc/scsi/device_info
- */
-static int proc_scsi_dev_info_read(char *buffer, char **start, off_t offset,
- int length)
-{
- struct scsi_dev_info_list *devinfo;
- int size, len = 0;
- off_t begin = 0;
- off_t pos = 0;
-
- list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
- size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",
- devinfo->vendor, devinfo->model, devinfo->flags);
- len += size;
- pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
- }
-
-stop_output:
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- return (len);
-}
-
-/*
- * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
- * /proc.
- *
- * Use: echo "vendor:model:flag" > /proc/scsi/device_info
- *
- * To add a black/white list entry for vendor and model with an integer
- * value of flag to the scsi device info list.
- */
-static int proc_scsi_dev_info_write (struct file * file, const char * buf,
- unsigned long length, void *data)
-{
- char *buffer;
- int err = length;
-
- if (!buf || length>PAGE_SIZE)
- return -EINVAL;
- if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if(copy_from_user(buffer, buf, length)) {
- err =-EFAULT;
- goto out;
- }
-
- if (length < PAGE_SIZE)
- buffer[length] = '\0';
- else if (buffer[PAGE_SIZE-1]) {
- err = -EINVAL;
- goto out;
- }
-
- scsi_dev_info_list_add_str(buffer);
-
-out:
- free_page((unsigned long) buffer);
- return err;
-}
-
-static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
-{
- Scsi_Device *scd;
- struct Scsi_Host *HBA_ptr;
- int size, len = 0;
- off_t begin = 0;
- off_t pos = 0;
-
- /*
- * First, see if there are any attached devices or not.
- */
- for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
- HBA_ptr = scsi_host_get_next(HBA_ptr)) {
- if (HBA_ptr->host_queue != NULL) {
- break;
- }
- }
- size = sprintf(buffer + len, "Attached devices: %s\n", (HBA_ptr) ? "" : "none");
- len += size;
- pos = begin + len;
- for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
- HBA_ptr = scsi_host_get_next(HBA_ptr)) {
-#if 0
- size += sprintf(buffer + len, "scsi%2d: %s\n", (int) HBA_ptr->host_no,
- HBA_ptr->hostt->procname);
- len += size;
- pos = begin + len;
-#endif
- for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
- proc_print_scsidevice(scd, buffer, &size, len);
- len += size;
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
- }
- }
-
-stop_output:
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- return (len);
-}
-
-static int proc_scsi_gen_write(struct file * file, const char * buf,
- unsigned long length, void *data)
-{
- Scsi_Device *scd;
- struct Scsi_Host *HBA_ptr;
- char *p;
- int host, channel, id, lun;
- char * buffer;
- int err;
-
- if (!buf || length>PAGE_SIZE)
- return -EINVAL;
-
- if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if(copy_from_user(buffer, buf, length))
- {
- err =-EFAULT;
- goto out;
- }
-
- err = -EINVAL;
-
- if (length < PAGE_SIZE)
- buffer[length] = '\0';
- else if (buffer[PAGE_SIZE-1])
- goto out;
-
- if (length < 11 || strncmp("scsi", buffer, 4))
- goto out;
-
- /*
- * Usage: echo "scsi dump #N" > /proc/scsi/scsi
- * to dump status of all scsi commands. The number is used to specify the level
- * of detail in the dump.
- */
- if (!strncmp("dump", buffer + 5, 4)) {
- unsigned int level;
-
- p = buffer + 10;
-
- if (*p == '\0')
- goto out;
-
- level = simple_strtoul(p, NULL, 0);
- scsi_dump_status(level);
- }
- /*
- * Usage: echo "scsi log token #N" > /proc/scsi/scsi
- * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
- * llcomplete,hlqueue,hlcomplete]
- */
-#ifdef CONFIG_SCSI_LOGGING /* { */
-
- if (!strncmp("log", buffer + 5, 3)) {
- char *token;
- unsigned int level;
-
- p = buffer + 9;
- token = p;
- while (*p != ' ' && *p != '\t' && *p != '\0') {
- p++;
- }
-
- if (*p == '\0') {
- if (strncmp(token, "all", 3) == 0) {
- /*
- * Turn on absolutely everything.
- */
- scsi_logging_level = ~0;
- } else if (strncmp(token, "none", 4) == 0) {
- /*
- * Turn off absolutely everything.
- */
- scsi_logging_level = 0;
- } else {
- goto out;
- }
- } else {
- *p++ = '\0';
-
- level = simple_strtoul(p, NULL, 0);
-
- /*
- * Now figure out what to do with it.
- */
- if (strcmp(token, "error") == 0) {
- SCSI_SET_ERROR_RECOVERY_LOGGING(level);
- } else if (strcmp(token, "timeout") == 0) {
- SCSI_SET_TIMEOUT_LOGGING(level);
- } else if (strcmp(token, "scan") == 0) {
- SCSI_SET_SCAN_BUS_LOGGING(level);
- } else if (strcmp(token, "mlqueue") == 0) {
- SCSI_SET_MLQUEUE_LOGGING(level);
- } else if (strcmp(token, "mlcomplete") == 0) {
- SCSI_SET_MLCOMPLETE_LOGGING(level);
- } else if (strcmp(token, "llqueue") == 0) {
- SCSI_SET_LLQUEUE_LOGGING(level);
- } else if (strcmp(token, "llcomplete") == 0) {
- SCSI_SET_LLCOMPLETE_LOGGING(level);
- } else if (strcmp(token, "hlqueue") == 0) {
- SCSI_SET_HLQUEUE_LOGGING(level);
- } else if (strcmp(token, "hlcomplete") == 0) {
- SCSI_SET_HLCOMPLETE_LOGGING(level);
- } else if (strcmp(token, "ioctl") == 0) {
- SCSI_SET_IOCTL_LOGGING(level);
- } else {
- goto out;
- }
- }
-
- printk(KERN_INFO "scsi logging level set to 0x%8.8x\n", scsi_logging_level);
- }
-#endif /* CONFIG_SCSI_LOGGING */ /* } */
-
- /*
- * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
- * with "0 1 2 3" replaced by your "Host Channel Id Lun".
- * Consider this feature BETA.
- * CAUTION: This is not for hotplugging your peripherals. As
- * SCSI was not designed for this you could damage your
- * hardware !
- * However perhaps it is legal to switch on an
- * already connected device. It is perhaps not
- * guaranteed this device doesn't corrupt an ongoing data transfer.
- */
- if (!strncmp("add-single-device", buffer + 5, 17)) {
- p = buffer + 23;
-
- host = simple_strtoul(p, &p, 0);
- channel = simple_strtoul(p + 1, &p, 0);
- id = simple_strtoul(p + 1, &p, 0);
- lun = simple_strtoul(p + 1, &p, 0);
-
- printk(KERN_INFO "scsi singledevice %d %d %d %d\n", host, channel,
- id, lun);
-
- for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
- HBA_ptr = scsi_host_get_next(HBA_ptr)) {
- if (HBA_ptr->host_no == host) {
- break;
- }
- }
- err = -ENXIO;
- if (!HBA_ptr)
- goto out;
-
- for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
- if ((scd->channel == channel
- && scd->id == id
- && scd->lun == lun)) {
- break;
- }
- }
-
- err = -ENOSYS;
- if (scd)
- goto out; /* We do not yet support unplugging */
-
- scan_scsis(HBA_ptr, 1, channel, id, lun);
- err = length;
- goto out;
- }
- /*
- * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
- * with "0 1 2 3" replaced by your "Host Channel Id Lun".
- *
- * Consider this feature pre-BETA.
- *
- * CAUTION: This is not for hotplugging your peripherals. As
- * SCSI was not designed for this you could damage your
- * hardware and thoroughly confuse the SCSI subsystem.
- *
- */
- else if (!strncmp("remove-single-device", buffer + 5, 20)) {
- p = buffer + 26;
-
- host = simple_strtoul(p, &p, 0);
- channel = simple_strtoul(p + 1, &p, 0);
- id = simple_strtoul(p + 1, &p, 0);
- lun = simple_strtoul(p + 1, &p, 0);
-
-
- for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
- HBA_ptr = scsi_host_get_next(HBA_ptr)) {
- if (HBA_ptr->host_no == host) {
- break;
- }
- }
- err = -ENODEV;
- if (!HBA_ptr)
- goto out;
-
- for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
- if ((scd->channel == channel
- && scd->id == id
- && scd->lun == lun)) {
- break;
- }
- }
-
- if (scd == NULL)
- goto out; /* there is no such device attached */
-
- err = -EBUSY;
- if (scd->access_count)
- goto out;
-
- scsi_detach_device(scd);
-
- if (scd->attached == 0) {
- devfs_unregister (scd->de);
-
- /* Now we can remove the device structure */
- if (scd->next != NULL)
- scd->next->prev = scd->prev;
-
- if (scd->prev != NULL)
- scd->prev->next = scd->next;
-
- if (HBA_ptr->host_queue == scd) {
- HBA_ptr->host_queue = scd->next;
- }
- blk_cleanup_queue(&scd->request_queue);
- if (scd->inquiry)
- kfree(scd->inquiry);
- kfree((char *) scd);
- } else {
- goto out;
- }
- err = 0;
- }
-out:
-
- free_page((unsigned long) buffer);
- return err;
-}
-#endif
-
int scsi_attach_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
@@ -2470,86 +2102,6 @@
return -1;
}
-#ifdef CONFIG_PROC_FS
-/*
- * Function: scsi_dump_status
- *
- * Purpose: Brain dump of scsi system, used for problem solving.
- *
- * Arguments: level - used to indicate level of detail.
- *
- * Notes: The level isn't used at all yet, but we need to find some way
- * of sensibly logging varying degrees of information. A quick one-line
- * display of each command, plus the status would be most useful.
- *
- * This does depend upon CONFIG_SCSI_LOGGING - I do want some way of turning
- * it all off if the user wants a lean and mean kernel. It would probably
- * also be useful to allow the user to specify one single host to be dumped.
- * A second argument to the function would be useful for that purpose.
- *
- * FIXME - some formatting of the output into tables would be very handy.
- */
-static void scsi_dump_status(int level)
-{
-#ifdef CONFIG_SCSI_LOGGING /* { */
- int i;
- struct Scsi_Host *shpnt;
- Scsi_Cmnd *SCpnt;
- Scsi_Device *SDpnt;
- printk(KERN_INFO "Dump of scsi host parameters:\n");
- i = 0;
- for (shpnt = scsi_host_get_next(NULL); shpnt;
- shpnt = scsi_host_get_next(shpnt)) {
- printk(KERN_INFO " %d %d %d : %d %d\n",
- shpnt->host_failed,
- shpnt->host_busy,
- atomic_read(&shpnt->host_active),
- shpnt->host_blocked,
- shpnt->host_self_blocked);
- }
-
- printk(KERN_INFO "\n\n");
- printk(KERN_INFO "Dump of scsi command parameters:\n");
- for (shpnt = scsi_host_get_next(NULL); shpnt;
- shpnt = scsi_host_get_next(shpnt)) {
- printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n");
- for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
- for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
- /* (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x */
- printk(KERN_INFO "(%3d) %2d:%1d:%2d:%2d (%6s %4llu %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
- i++,
-
- SCpnt->host->host_no,
- SCpnt->channel,
- SCpnt->target,
- SCpnt->lun,
-
- SCpnt->request->rq_disk ?
- SCpnt->request->rq_disk->disk_name : "?",
- (unsigned long long)SCpnt->request->sector,
- SCpnt->request->nr_sectors,
- (long)SCpnt->request->current_nr_sectors,
- SCpnt->request->rq_status,
- SCpnt->use_sg,
-
- SCpnt->retries,
- SCpnt->allowed,
- SCpnt->flags,
-
- SCpnt->timeout_per_command,
- SCpnt->timeout,
- SCpnt->internal_timeout,
-
- SCpnt->cmnd[0],
- SCpnt->sense_buffer[2],
- SCpnt->result);
- }
- }
- }
-#endif /* CONFIG_SCSI_LOGGING */ /* } */
-}
-#endif /* CONFIG_PROC_FS */
-
static char *scsi_dev_flags;
MODULE_PARM(scsi_dev_flags, "s");
MODULE_PARM_DESC(scsi_dev_flags,
@@ -2671,7 +2223,6 @@
static int __init init_scsi(void)
{
- struct proc_dir_entry *generic;
int i;
printk(KERN_INFO "SCSI subsystem driver " REVISION "\n");
@@ -2692,44 +2243,11 @@
panic("SCSI: can't init sg mempool\n");
}
- /*
- * This makes /proc/scsi and /proc/scsi/scsi visible.
- */
-#ifdef CONFIG_PROC_FS
- proc_scsi = proc_mkdir("scsi", 0);
- if (!proc_scsi) {
- printk (KERN_ERR "cannot init /proc/scsi\n");
- return -ENOMEM;
- }
- generic = create_proc_info_entry ("scsi/scsi", 0, 0, scsi_proc_info);
- if (!generic) {
- printk (KERN_ERR "cannot init /proc/scsi/scsi\n");
- remove_proc_entry("scsi", 0);
- return -ENOMEM;
- }
- generic->write_proc = proc_scsi_gen_write;
-
- generic = create_proc_info_entry ("scsi/device_info", 0, 0,
- proc_scsi_dev_info_read);
- if (!generic) {
- printk (KERN_ERR "cannot init /proc/scsi/device_info\n");
- remove_proc_entry("scsi/scsi", 0);
- remove_proc_entry("scsi", 0);
- return -ENOMEM;
- }
- generic->write_proc = proc_scsi_dev_info_write;
-#endif
-
- scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", NULL);
-
+ scsi_devfs_handle = devfs_mk_dir(NULL, "scsi", NULL);
scsi_host_init();
scsi_dev_info_list_init(scsi_dev_flags);
-
bus_register(&scsi_driverfs_bus_type);
-
- /* Where we handle work queued by scsi_done */
open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
-
return 0;
}
@@ -2737,17 +2255,9 @@
{
int i;
- devfs_unregister (scsi_devfs_handle);
+ devfs_unregister(scsi_devfs_handle);
scsi_dev_info_list_delete();
-
-#ifdef CONFIG_PROC_FS
- /* No, we're not here anymore. Don't show the /proc/scsi files. */
- remove_proc_entry ("scsi/device_info", 0);
- remove_proc_entry ("scsi/scsi", 0);
- remove_proc_entry ("scsi", 0);
-#endif
-
for (i = 0; i < SG_MEMPOOL_NR; i++) {
struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
mempool_destroy(sgp->pool);
===== drivers/scsi/scsi.h 1.40 vs edited =====
--- 1.40/drivers/scsi/scsi.h Thu Nov 14 12:34:35 2002
+++ edited/drivers/scsi/scsi.h Sat Nov 16 18:27:26 2002
@@ -391,6 +391,11 @@
#include "scsi_obsolete.h"
/*
+ * Forward-declaration of structs for prototypes.
+ */
+struct Scsi_Host;
+
+/*
* Add some typedefs so that we can prototyope a bunch of the functions.
*/
typedef struct scsi_device Scsi_Device;
@@ -496,8 +501,21 @@
/*
* Prototypes for functions in scsi_proc.c
*/
-extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
+#ifdef CONFIG_PROC_FS
+extern int scsi_init_procfs(void);
+extern void scsi_exit_procfs(void);
+
+extern void scsi_proc_host_add(struct Scsi_Host *);
+extern void scsi_proc_host_rm(struct Scsi_Host *);
+
extern struct proc_dir_entry *proc_scsi;
+#else
+static inline int scsi_init_procfs(void) { return 0; };
+static inline void scsi_exit_procfs(void) { };
+
+static inline void scsi_proc_host_add(struct Scsi_Host *);
+static inline void scsi_proc_host_rm(struct Scsi_Host *);
+#endif /* CONFIG_PROC_FS */
/*
* Prototypes for functions in constants.c
@@ -536,6 +554,8 @@
unsigned flags;
unsigned compatible; /* for use with scsi_static_device_list entries */
};
+extern struct list_head scsi_dev_info_list;
+extern int scsi_dev_info_list_add_str(char *);
/*
* The scsi_device struct contains what we know about each given scsi
===== drivers/scsi/scsi_proc.c 1.7 vs edited =====
--- 1.7/drivers/scsi/scsi_proc.c Wed Oct 16 18:51:48 2002
+++ edited/drivers/scsi/scsi_proc.c Sat Nov 16 17:34:15 2002
@@ -16,9 +16,8 @@
* Michael A. Griffith <grif@acm.org>
*/
-#include <linux/config.h> /* for CONFIG_PROC_FS */
+#include <linux/config.h>
#include <linux/module.h>
-
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -26,245 +25,133 @@
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/blk.h>
-
#include <asm/uaccess.h>
#include "scsi.h"
#include "hosts.h"
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
+/* 4K page size, but our output routines, use some slack for overruns */
+#define PROC_BLOCK_SIZE (3*1024)
-#ifdef CONFIG_PROC_FS
+/* XXX: this shouldn't really be exposed to drivers. */
+struct proc_dir_entry *proc_scsi;
+EXPORT_SYMBOL(proc_scsi);
-/* generic_proc_info
- * Used if the driver currently has no own support for /proc/scsi
- */
-int generic_proc_info(char *buffer, char **start, off_t offset, int length,
- const char *(*info) (struct Scsi_Host *),
- struct Scsi_Host *sh)
-{
- int len, pos, begin;
-
- begin = 0;
- if (info && sh) {
- pos = len = sprintf(buffer, "%s\n", info(sh));
- } else {
- pos = len = sprintf(buffer,
- "The driver does not yet support the proc-fs\n");
- }
+
+/* Used if the driver currently has no own support for /proc/scsi */
+static int generic_proc_info(char *buffer, char **start, off_t offset,
+ int count, const char *(*info)(struct Scsi_Host *),
+ struct Scsi_Host *shost)
+{
+ int len, pos, begin = 0;
+ static const char noprocfs[] =
+ "The driver does not yet support the proc-fs\n";
+
+ if (info && shost)
+ len = sprintf(buffer, "%s\n", info(shost));
+ else
+ len = sprintf(buffer, "%s\n", noprocfs);
+
+ pos = len;
if (pos < offset) {
len = 0;
begin = pos;
}
- *start = buffer + (offset - begin); /* Start of wanted data */
+
+ *start = buffer + (offset - begin);
len -= (offset - begin);
- if (len > length)
- len = length;
+ if (len > count)
+ len = count;
- return (len);
+ return len;
}
-/* dispatch_scsi_info is the central dispatcher
- * It is the interface between the proc-fs and the SCSI subsystem code
- */
static int proc_scsi_read(char *buffer, char **start, off_t offset,
- int length, int *eof, void *data)
+ int length, int *eof, void *data)
{
- struct Scsi_Host *hpnt = data;
+ struct Scsi_Host *shost = data;
int n;
- if (hpnt->hostt->proc_info == NULL)
+ if (shost->hostt->proc_info == NULL)
n = generic_proc_info(buffer, start, offset, length,
- hpnt->hostt->info, hpnt);
+ shost->hostt->info, shost);
else
- n = (hpnt->hostt->proc_info(buffer, start, offset,
- length, hpnt->host_no, 0));
- *eof = (n<length);
+ n = (shost->hostt->proc_info(buffer, start, offset,
+ length, shost->host_no, 0));
+
+ *eof = (n < length);
return n;
}
-#define PROC_BLOCK_SIZE (3*1024) /* 4K page size, but our output routines
- * use some slack for overruns
- */
-
-static int proc_scsi_write(struct file * file, const char * buf,
+static int proc_scsi_write(struct file *file, const char *buf,
unsigned long count, void *data)
{
- struct Scsi_Host *hpnt = data;
- ssize_t ret = 0;
- char * page;
+ struct Scsi_Host *shost = data;
+ ssize_t ret = -ENOMEM;
+ char *page;
char *start;
- if (hpnt->hostt->proc_info == NULL)
- ret = -ENOSYS;
-
+ if (!shost->hostt->proc_info)
+ return -ENOSYS;
if (count > PROC_BLOCK_SIZE)
return -EOVERFLOW;
- if (!(page = (char *) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if(copy_from_user(page, buf, count))
- {
- free_page((ulong) page);
- return -EFAULT;
+ page = (char *)__get_free_page(GFP_KERNEL);
+ if (page) {
+ ret = -EFAULT;
+ if (copy_from_user(page, buf, count))
+ goto out;
+ ret = shost->hostt->proc_info(page, &start, 0, count,
+ shost->host_no, 1);
}
-
- ret = hpnt->hostt->proc_info(page, &start, 0, count,
- hpnt->host_no, 1);
-
- free_page((ulong) page);
- return(ret);
-}
-
-void scsi_proc_host_mkdir(Scsi_Host_Template *shost_tp)
-{
- shost_tp->proc_dir = proc_mkdir(shost_tp->proc_name, proc_scsi);
- if (!shost_tp->proc_dir) {
- printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
- __FUNCTION__, shost_tp->proc_name);
- return;
- }
- shost_tp->proc_dir->owner = shost_tp->module;
+out:
+ free_page((unsigned long)page);
+ return ret;
}
void scsi_proc_host_add(struct Scsi_Host *shost)
{
- char name[10];
+ Scsi_Host_Template *sht = shost->hostt;
struct proc_dir_entry *p;
+ char name[10];
- sprintf(name,"%d",shost->host_no);
- p = create_proc_read_entry(name,
- S_IFREG | S_IRUGO | S_IWUSR,
- shost->hostt->proc_dir,
- proc_scsi_read,
- (void *)shost);
+ if (!sht->proc_dir) {
+ sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
+ if (!sht->proc_dir) {
+ printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
+ __FUNCTION__, sht->proc_name);
+ return;
+ }
+ sht->proc_dir->owner = sht->module;
+ }
+
+ sprintf(name,"%d", shost->host_no);
+ p = create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
+ shost->hostt->proc_dir, proc_scsi_read, shost);
if (!p) {
printk(KERN_ERR "%s: Failed to register host %d in"
"%s\n", __FUNCTION__, shost->host_no,
shost->hostt->proc_name);
- } else {
- p->write_proc=proc_scsi_write;
- p->owner = shost->hostt->module;
- }
+ return;
+ }
+
+ p->write_proc = proc_scsi_write;
+ p->owner = shost->hostt->module;
}
void scsi_proc_host_rm(struct Scsi_Host *shost)
{
char name[10];
- sprintf(name,"%d",shost->host_no);
- remove_proc_entry(name, shost->hostt->proc_dir);
-}
-/*
- * parseHandle *parseInit(char *buf, char *cmdList, int cmdNum);
- * gets a pointer to a null terminated data buffer
- * and a list of commands with blanks as delimiter
- * in between.
- * The commands have to be alphanumerically sorted.
- * cmdNum has to contain the number of commands.
- * On success, a pointer to a handle structure
- * is returned, NULL on failure
- *
- * int parseOpt(parseHandle *handle, char **param);
- * processes the next parameter. On success, the
- * index of the appropriate command in the cmdList
- * is returned, starting with zero.
- * param points to the null terminated parameter string.
- * On failure, -1 is returned.
- *
- * The databuffer buf may only contain pairs of commands
- * options, separated by blanks:
- * <Command> <Parameter> [<Command> <Parameter>]*
- */
-
-typedef struct {
- char *buf, /* command buffer */
- *cmdList, /* command list */
- *bufPos, /* actual position */
- **cmdPos, /* cmdList index */
- cmdNum; /* cmd number */
-} parseHandle;
-
-inline int parseFree(parseHandle * handle)
-{ /* free memory */
- kfree(handle->cmdPos);
- kfree(handle);
-
- return -1;
-}
-
-parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
-{
- char *ptr; /* temp pointer */
- parseHandle *handle; /* new handle */
-
- if (!buf || !cmdList) /* bad input ? */
- return NULL;
- handle = (parseHandle *) kmalloc(sizeof(parseHandle), GFP_KERNEL);
- if (!handle)
- return NULL; /* out of memory */
- handle->cmdPos = (char **) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL);
- if (!handle->cmdPos) {
- kfree(handle);
- return NULL; /* out of memory */
- }
- handle->buf = handle->bufPos = buf; /* init handle */
- handle->cmdList = cmdList;
- handle->cmdNum = cmdNum;
-
- handle->cmdPos[cmdNum = 0] = cmdList;
- for (ptr = cmdList; *ptr; ptr++) { /* scan command string */
- if (*ptr == ' ') { /* and insert zeroes */
- *ptr++ = 0;
- handle->cmdPos[++cmdNum] = ptr++;
- }
- }
- return handle;
-}
-
-int parseOpt(parseHandle * handle, char **param)
-{
- int cmdIndex = 0, cmdLen = 0;
- char *startPos;
-
- if (!handle) /* invalid handle */
- return (parseFree(handle));
- /* skip spaces */
- for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
- if (!*(handle->bufPos))
- return (parseFree(handle)); /* end of data */
-
- startPos = handle->bufPos; /* store cmd start */
- for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) { /* no string end? */
- for (;;) {
- if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
- break; /* char matches ? */
- else if (memcmp(startPos, (char *) (handle->cmdPos[++cmdIndex]), cmdLen))
- return (parseFree(handle)); /* unknown command */
-
- if (cmdIndex >= handle->cmdNum)
- return (parseFree(handle)); /* unknown command */
- }
-
- cmdLen++; /* next char */
- }
-
- /* Get param. First skip all blanks, then insert zero after param */
-
- for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
- *param = handle->bufPos;
-
- for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
- *(handle->bufPos++) = 0;
-
- return (cmdIndex);
+ sprintf(name,"%d", shost->host_no);
+ remove_proc_entry(name, shost->hostt->proc_dir);
+ if (!shost->hostt->present)
+ remove_proc_entry(shost->hostt->proc_name, proc_scsi);
}
-void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
+/* XXX: this shouldn't really be exposed to drivers. */
+void proc_print_scsidevice(Scsi_Device * sdev, char *buffer, int *size, int len)
{
int x, y = *size;
@@ -272,35 +159,36 @@
y = sprintf(buffer + len,
"Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
- scd->host->host_no, scd->channel, scd->id, scd->lun);
+ sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
for (x = 0; x < 8; x++) {
- if (scd->vendor[x] >= 0x20)
- y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
+ if (sdev->vendor[x] >= 0x20)
+ y += sprintf(buffer + len + y, "%c", sdev->vendor[x]);
else
y += sprintf(buffer + len + y, " ");
}
y += sprintf(buffer + len + y, " Model: ");
for (x = 0; x < 16; x++) {
- if (scd->model[x] >= 0x20)
- y += sprintf(buffer + len + y, "%c", scd->model[x]);
+ if (sdev->model[x] >= 0x20)
+ y += sprintf(buffer + len + y, "%c", sdev->model[x]);
else
y += sprintf(buffer + len + y, " ");
}
y += sprintf(buffer + len + y, " Rev: ");
for (x = 0; x < 4; x++) {
- if (scd->rev[x] >= 0x20)
- y += sprintf(buffer + len + y, "%c", scd->rev[x]);
+ if (sdev->rev[x] >= 0x20)
+ y += sprintf(buffer + len + y, "%c", sdev->rev[x]);
else
y += sprintf(buffer + len + y, " ");
}
y += sprintf(buffer + len + y, "\n");
y += sprintf(buffer + len + y, " Type: %s ",
- scd->type < MAX_SCSI_DEVICE_CODE ?
- scsi_device_types[(int) scd->type] : "Unknown ");
+ sdev->type < MAX_SCSI_DEVICE_CODE ?
+ scsi_device_types[(int) sdev->type] : "Unknown ");
y += sprintf(buffer + len + y, " ANSI"
- " SCSI revision: %02x", (scd->scsi_level - 1) ? scd->scsi_level - 1 : 1);
- if (scd->scsi_level == 2)
+ " SCSI revision: %02x", (sdev->scsi_level - 1) ?
+ sdev->scsi_level - 1 : 1);
+ if (sdev->scsi_level == 2)
y += sprintf(buffer + len + y, " CCS\n");
else
y += sprintf(buffer + len + y, "\n");
@@ -308,30 +196,474 @@
*size = y;
return;
}
+EXPORT_SYMBOL(proc_print_scsidevice);
-#else /* if !CONFIG_PROC_FS */
+/*
+ * proc_scsi_dev_info_read: dump the scsi_dev_info_list via
+ * /proc/scsi/device_info
+ */
+static int proc_scsi_dev_info_read(char *buffer, char **start, off_t offset,
+ int length)
+{
+ struct scsi_dev_info_list *devinfo;
+ int size, len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+
+ list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
+ size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",
+ devinfo->vendor, devinfo->model, devinfo->flags);
+ len += size;
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+ }
-void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
+stop_output:
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ return (len);
+}
+
+/*
+ * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
+ * /proc.
+ *
+ * Use: echo "vendor:model:flag" > /proc/scsi/device_info
+ *
+ * To add a black/white list entry for vendor and model with an integer
+ * value of flag to the scsi device info list.
+ */
+static int proc_scsi_dev_info_write (struct file * file, const char * buf,
+ unsigned long length, void *data)
{
+ char *buffer;
+ int err = length;
+
+ if (!buf || length>PAGE_SIZE)
+ return -EINVAL;
+ if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ if (copy_from_user(buffer, buf, length)) {
+ err =-EFAULT;
+ goto out;
+ }
+
+ if (length < PAGE_SIZE)
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ scsi_dev_info_list_add_str(buffer);
+
+out:
+ free_page((unsigned long)buffer);
+ return err;
}
-#endif /* CONFIG_PROC_FS */
+static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
+{
+ struct Scsi_Host *shost;
+ Scsi_Device *sdev;
+ int size, len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+
+ /*
+ * First, see if there are any attached devices or not.
+ */
+ for (shost = scsi_host_get_next(NULL); shost;
+ shost = scsi_host_get_next(shost)) {
+ if (shost->host_queue != NULL) {
+ break;
+ }
+ }
+ size = sprintf(buffer + len, "Attached devices: %s\n",
+ (shost) ? "" : "none");
+ len += size;
+ pos = begin + len;
+ for (shost = scsi_host_get_next(NULL); shost;
+ shost = scsi_host_get_next(shost)) {
+ for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+ proc_print_scsidevice(sdev, buffer, &size, len);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+ }
+ }
+
+stop_output:
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ return (len);
+}
+#ifdef CONFIG_SCSI_LOGGING
/*
- * Overrides for Emacs so that we get a uniform tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
+ * Function: scsi_dump_status
+ *
+ * Purpose: Brain dump of scsi system, used for problem solving.
+ *
+ * Arguments: level - used to indicate level of detail.
+ *
+ * Notes: The level isn't used at all yet, but we need to find some
+ * way of sensibly logging varying degrees of information.
+ * A quick one-line display of each command, plus the status
+ * would be most useful.
+ *
+ * This does depend upon CONFIG_SCSI_LOGGING - I do want some
+ * way of turning it all off if the user wants a lean and mean
+ * kernel. It would probably also be useful to allow the user
+ * to specify one single host to be dumped. A second argument
+ * to the function would be useful for that purpose.
+ *
+ * FIXME - some formatting of the output into tables would be
+ * very handy.
*/
+static void scsi_dump_status(int level)
+{
+ int i;
+ struct Scsi_Host *shpnt;
+ Scsi_Cmnd *SCpnt;
+ Scsi_Device *SDpnt;
+ printk(KERN_INFO "Dump of scsi host parameters:\n");
+ i = 0;
+ for (shpnt = scsi_host_get_next(NULL); shpnt;
+ shpnt = scsi_host_get_next(shpnt)) {
+ printk(KERN_INFO " %d %d %d : %d %d\n",
+ shpnt->host_failed,
+ shpnt->host_busy,
+ atomic_read(&shpnt->host_active),
+ shpnt->host_blocked,
+ shpnt->host_self_blocked);
+ }
+
+ printk(KERN_INFO "\n\n");
+ printk(KERN_INFO "Dump of scsi command parameters:\n");
+ for (shpnt = scsi_host_get_next(NULL); shpnt;
+ shpnt = scsi_host_get_next(shpnt)) {
+ printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) "
+ "(ret all flg) (to/cmd to ito) cmd snse result\n");
+ for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+ /* (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x */
+ printk(KERN_INFO "(%3d) %2d:%1d:%2d:%2d (%6s %4llu %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
+ i++,
+
+ SCpnt->host->host_no,
+ SCpnt->channel,
+ SCpnt->target,
+ SCpnt->lun,
+
+ SCpnt->request->rq_disk ?
+ SCpnt->request->rq_disk->disk_name : "?",
+ (unsigned long long)SCpnt->request->sector,
+ SCpnt->request->nr_sectors,
+ (long)SCpnt->request->current_nr_sectors,
+ SCpnt->request->rq_status,
+ SCpnt->use_sg,
+
+ SCpnt->retries,
+ SCpnt->allowed,
+ SCpnt->flags,
+
+ SCpnt->timeout_per_command,
+ SCpnt->timeout,
+ SCpnt->internal_timeout,
+
+ SCpnt->cmnd[0],
+ SCpnt->sense_buffer[2],
+ SCpnt->result);
+ }
+ }
+ }
+}
+#endif /* CONFIG_SCSI_LOGGING */
+
+static int proc_scsi_gen_write(struct file * file, const char * buf,
+ unsigned long length, void *data)
+{
+ Scsi_Device *sdev;
+ struct Scsi_Host *shost;
+ char *p;
+ int host, channel, id, lun;
+ char * buffer;
+ int err;
+
+ if (!buf || length>PAGE_SIZE)
+ return -EINVAL;
+
+ buffer = (char *)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ if (copy_from_user(buffer, buf, length)) {
+ err =-EFAULT;
+ goto out;
+ }
+
+ err = -EINVAL;
+
+ if (length < PAGE_SIZE)
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1])
+ goto out;
+
+ if (length < 11 || strncmp("scsi", buffer, 4))
+ goto out;
+
+#ifdef CONFIG_SCSI_LOGGING
+ /*
+ * Usage: echo "scsi dump #N" > /proc/scsi/scsi
+ * to dump status of all scsi commands. The number is used to
+ * specify the level of detail in the dump.
+ */
+ if (!strncmp("dump", buffer + 5, 4)) {
+ unsigned int level;
+
+ p = buffer + 10;
+
+ if (*p == '\0')
+ goto out;
+
+ level = simple_strtoul(p, NULL, 0);
+ scsi_dump_status(level);
+ }
+ /*
+ * Usage: echo "scsi log token #N" > /proc/scsi/scsi
+ * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
+ * llcomplete,hlqueue,hlcomplete]
+ */
+ if (!strncmp("log", buffer + 5, 3)) {
+ char *token;
+ unsigned int level;
+
+ p = buffer + 9;
+ token = p;
+ while (*p != ' ' && *p != '\t' && *p != '\0') {
+ p++;
+ }
+
+ if (*p == '\0') {
+ if (strncmp(token, "all", 3) == 0) {
+ /*
+ * Turn on absolutely everything.
+ */
+ scsi_logging_level = ~0;
+ } else if (strncmp(token, "none", 4) == 0) {
+ /*
+ * Turn off absolutely everything.
+ */
+ scsi_logging_level = 0;
+ } else {
+ goto out;
+ }
+ } else {
+ *p++ = '\0';
+
+ level = simple_strtoul(p, NULL, 0);
+
+ /*
+ * Now figure out what to do with it.
+ */
+ if (strcmp(token, "error") == 0) {
+ SCSI_SET_ERROR_RECOVERY_LOGGING(level);
+ } else if (strcmp(token, "timeout") == 0) {
+ SCSI_SET_TIMEOUT_LOGGING(level);
+ } else if (strcmp(token, "scan") == 0) {
+ SCSI_SET_SCAN_BUS_LOGGING(level);
+ } else if (strcmp(token, "mlqueue") == 0) {
+ SCSI_SET_MLQUEUE_LOGGING(level);
+ } else if (strcmp(token, "mlcomplete") == 0) {
+ SCSI_SET_MLCOMPLETE_LOGGING(level);
+ } else if (strcmp(token, "llqueue") == 0) {
+ SCSI_SET_LLQUEUE_LOGGING(level);
+ } else if (strcmp(token, "llcomplete") == 0) {
+ SCSI_SET_LLCOMPLETE_LOGGING(level);
+ } else if (strcmp(token, "hlqueue") == 0) {
+ SCSI_SET_HLQUEUE_LOGGING(level);
+ } else if (strcmp(token, "hlcomplete") == 0) {
+ SCSI_SET_HLCOMPLETE_LOGGING(level);
+ } else if (strcmp(token, "ioctl") == 0) {
+ SCSI_SET_IOCTL_LOGGING(level);
+ } else {
+ goto out;
+ }
+ }
+
+ printk(KERN_INFO "scsi logging level set to 0x%8.8x\n", scsi_logging_level);
+ }
+#endif /* CONFIG_SCSI_LOGGING */
+
+ /*
+ * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
+ * with "0 1 2 3" replaced by your "Host Channel Id Lun".
+ * Consider this feature BETA.
+ * CAUTION: This is not for hotplugging your peripherals. As
+ * SCSI was not designed for this you could damage your
+ * hardware !
+ * However perhaps it is legal to switch on an
+ * already connected device. It is perhaps not
+ * guaranteed this device doesn't corrupt an ongoing data transfer.
+ */
+ if (!strncmp("add-single-device", buffer + 5, 17)) {
+ p = buffer + 23;
+
+ host = simple_strtoul(p, &p, 0);
+ channel = simple_strtoul(p + 1, &p, 0);
+ id = simple_strtoul(p + 1, &p, 0);
+ lun = simple_strtoul(p + 1, &p, 0);
+
+ printk(KERN_INFO "scsi singledevice %d %d %d %d\n", host, channel,
+ id, lun);
+
+ for (shost = scsi_host_get_next(NULL); shost;
+ shost = scsi_host_get_next(shost)) {
+ if (shost->host_no == host) {
+ break;
+ }
+ }
+ err = -ENXIO;
+ if (!shost)
+ goto out;
+
+ for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+ if ((sdev->channel == channel
+ && sdev->id == id
+ && sdev->lun == lun)) {
+ break;
+ }
+ }
+
+ err = -ENOSYS;
+ if (sdev)
+ goto out; /* We do not yet support unplugging */
+
+ scan_scsis(shost, 1, channel, id, lun);
+ err = length;
+ goto out;
+ }
+ /*
+ * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
+ * with "0 1 2 3" replaced by your "Host Channel Id Lun".
+ *
+ * Consider this feature pre-BETA.
+ *
+ * CAUTION: This is not for hotplugging your peripherals. As
+ * SCSI was not designed for this you could damage your
+ * hardware and thoroughly confuse the SCSI subsystem.
+ *
+ */
+ else if (!strncmp("remove-single-device", buffer + 5, 20)) {
+ p = buffer + 26;
+
+ host = simple_strtoul(p, &p, 0);
+ channel = simple_strtoul(p + 1, &p, 0);
+ id = simple_strtoul(p + 1, &p, 0);
+ lun = simple_strtoul(p + 1, &p, 0);
+
+
+ for (shost = scsi_host_get_next(NULL); shost;
+ shost = scsi_host_get_next(shost)) {
+ if (shost->host_no == host) {
+ break;
+ }
+ }
+ err = -ENODEV;
+ if (!shost)
+ goto out;
+
+ for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+ if ((sdev->channel == channel
+ && sdev->id == id
+ && sdev->lun == lun)) {
+ break;
+ }
+ }
+
+ if (sdev == NULL)
+ goto out; /* there is no such device attached */
+
+ err = -EBUSY;
+ if (sdev->access_count)
+ goto out;
+
+ scsi_detach_device(sdev);
+
+ if (sdev->attached == 0) {
+ devfs_unregister (sdev->de);
+
+ /* Now we can remove the device structure */
+ if (sdev->next != NULL)
+ sdev->next->prev = sdev->prev;
+
+ if (sdev->prev != NULL)
+ sdev->prev->next = sdev->next;
+
+ if (shost->host_queue == sdev) {
+ shost->host_queue = sdev->next;
+ }
+ blk_cleanup_queue(&sdev->request_queue);
+ if (sdev->inquiry)
+ kfree(sdev->inquiry);
+ kfree((char *) sdev);
+ } else {
+ goto out;
+ }
+ err = 0;
+ }
+out:
+
+ free_page((unsigned long)buffer);
+ return err;
+}
+
+int __init scsi_init_procfs(void)
+{
+ struct proc_dir_entry *pde;
+
+ proc_scsi = proc_mkdir("scsi", 0);
+ if (!proc_scsi)
+ goto err1;
+
+ pde = create_proc_info_entry("scsi/scsi", 0, 0, scsi_proc_info);
+ if (!pde)
+ goto err2;
+ pde->write_proc = proc_scsi_gen_write;
+
+ pde = create_proc_info_entry("scsi/device_info", 0, 0,
+ proc_scsi_dev_info_read);
+ if (!pde)
+ goto err3;
+ pde->write_proc = proc_scsi_dev_info_write;
+ return 0;
+
+err3:
+ remove_proc_entry("scsi/scsi", 0);
+err2:
+ remove_proc_entry("scsi", 0);
+err1:
+ return -ENOMEM;
+}
+
+void __exit scsi_exit_procfs(void)
+{
+ remove_proc_entry("scsi/device_info", 0);
+ remove_proc_entry("scsi/scsi", 0);
+ remove_proc_entry("scsi", 0);
+}
===== drivers/scsi/scsi_syms.c 1.18 vs edited =====
--- 1.18/drivers/scsi/scsi_syms.c Wed Nov 6 16:12:50 2002
+++ edited/drivers/scsi/scsi_syms.c Sat Nov 16 17:28:08 2002
@@ -74,9 +74,6 @@
EXPORT_SYMBOL(scsi_sleep);
-EXPORT_SYMBOL(proc_print_scsidevice);
-EXPORT_SYMBOL(proc_scsi);
-
EXPORT_SYMBOL(scsi_io_completion);
EXPORT_SYMBOL(scsi_end_request);
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] move all procfs code to scsi_proc.c
2002-11-16 19:02 [PATCH] move all procfs code to scsi_proc.c Christoph Hellwig
@ 2002-11-16 20:01 ` Patrick Mansfield
2002-11-16 20:54 ` Christoph Hellwig
0 siblings, 1 reply; 3+ messages in thread
From: Patrick Mansfield @ 2002-11-16 20:01 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: James.Bottomley, linux-scsi
On Sat, Nov 16, 2002 at 08:02:49PM +0100, Christoph Hellwig wrote:
> -extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
> +#ifdef CONFIG_PROC_FS
> +extern int scsi_init_procfs(void);
> +extern void scsi_exit_procfs(void);
> +
> +extern void scsi_proc_host_add(struct Scsi_Host *);
> +extern void scsi_proc_host_rm(struct Scsi_Host *);
> +
> extern struct proc_dir_entry *proc_scsi;
> +#else
> +static inline int scsi_init_procfs(void) { return 0; };
> +static inline void scsi_exit_procfs(void) { };
> +
> +static inline void scsi_proc_host_add(struct Scsi_Host *);
> +static inline void scsi_proc_host_rm(struct Scsi_Host *);
> +#endif /* CONFIG_PROC_FS */
Where are the calls to scsi_init_procfs and scsi_exit_procfs?
-- Patrick Mansfield
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] move all procfs code to scsi_proc.c
2002-11-16 20:01 ` Patrick Mansfield
@ 2002-11-16 20:54 ` Christoph Hellwig
0 siblings, 0 replies; 3+ messages in thread
From: Christoph Hellwig @ 2002-11-16 20:54 UTC (permalink / raw)
To: Patrick Mansfield; +Cc: James.Bottomley, linux-scsi
On Sat, Nov 16, 2002 at 12:01:48PM -0800, Patrick Mansfield wrote:
> Where are the calls to scsi_init_procfs and scsi_exit_procfs?
Left between the previous and the final version of that patch. Here's
the right diff:
--- 1.31/drivers/scsi/Makefile Fri Jun 21 06:09:54 2002
+++ edited/drivers/scsi/Makefile Sat Nov 16 20:19:18 2002
@@ -18,7 +18,7 @@
CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
-export-objs := scsi_syms.o 53c700.o
+export-objs := scsi_syms.o scsi_proc.o 53c700.o
subdir-$(CONFIG_PCMCIA) += pcmcia
@@ -123,8 +123,11 @@
obj-$(CONFIG_CHR_DEV_SG) += sg.o
scsi_mod-objs := scsi.o hosts.o scsi_ioctl.o constants.o scsicam.o \
- scsi_proc.o scsi_error.o scsi_lib.o scsi_scan.o \
- scsi_syms.o
+ scsi_error.o scsi_lib.o scsi_scan.o scsi_syms.o
+
+ifdef CONFIG_PROC_FS
+scsi_mod-objs += scsi_proc.o
+endif
sd_mod-objs := sd.o
sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o
===== drivers/scsi/hosts.c 1.27 vs edited =====
--- 1.27/drivers/scsi/hosts.c Thu Nov 14 13:19:04 2002
+++ edited/drivers/scsi/hosts.c Sat Nov 16 20:23:06 2002
@@ -352,11 +359,7 @@
shost->hostt->present--;
/* Cleanup proc and driverfs */
-#ifdef CONFIG_PROC_FS
scsi_proc_host_rm(shost);
- if (!shost->hostt->present)
- remove_proc_entry(shost->hostt->proc_name, proc_scsi);
-#endif
device_unregister(&shost->host_driverfs_dev);
kfree(shost);
@@ -470,12 +473,7 @@
found:
spin_unlock(&scsi_host_list_lock);
-#ifdef CONFIG_PROC_FS
- /* Add the new driver to /proc/scsi if not already there */
- if (!shost_tp->proc_dir)
- scsi_proc_host_mkdir(shost_tp);
scsi_proc_host_add(shost);
-#endif
strncpy(shost->host_driverfs_dev.name, shost_tp->proc_name,
DEVICE_NAME_SIZE-1);
===== drivers/scsi/hosts.h 1.36 vs edited =====
--- 1.36/drivers/scsi/hosts.h Thu Nov 14 13:07:27 2002
+++ edited/drivers/scsi/hosts.h Sat Nov 16 20:19:19 2002
@@ -509,10 +509,6 @@
unsigned short host_registered;
} Scsi_Host_Name;
-extern void scsi_proc_host_mkdir(Scsi_Host_Template *);
-extern void scsi_proc_host_add(struct Scsi_Host *);
-extern void scsi_proc_host_rm(struct Scsi_Host *);
-
extern void scsi_register_blocked_host(struct Scsi_Host *);
extern void scsi_deregister_blocked_host(struct Scsi_Host *);
===== drivers/scsi/scsi.c 1.61 vs edited =====
--- 1.61/drivers/scsi/scsi.c Thu Nov 14 13:19:04 2002
+++ edited/drivers/scsi/scsi.c Sat Nov 16 20:20:56 2002
@@ -74,13 +74,6 @@
#include <linux/kmod.h>
#endif
-struct proc_dir_entry *proc_scsi;
-
-#ifdef CONFIG_PROC_FS
-static int scsi_proc_info(char *buffer, char **start, off_t offset, int length);
-static void scsi_dump_status(int level);
-#endif
-
#define SG_MEMPOOL_NR 5
#define SG_MEMPOOL_SIZE 32
@@ -166,7 +159,7 @@
static const char * const spaces = " "; /* 16 of them */
static unsigned scsi_default_dev_flags;
-static LIST_HEAD(scsi_dev_info_list);
+LIST_HEAD(scsi_dev_info_list);
/*
* Function prototypes.
@@ -1762,7 +1755,7 @@
*
* Returns: 0 if OK, -error on failure.
**/
-static int scsi_dev_info_list_add_str (char *dev_list)
+int scsi_dev_info_list_add_str (char *dev_list)
{
char *vendor, *model, *strflags, *next;
char *next_check;
@@ -1908,367 +1901,6 @@
return scsi_default_dev_flags;
}
-#ifdef CONFIG_PROC_FS
-/*
- * proc_scsi_dev_info_read: dump the scsi_dev_info_list via
- * /proc/scsi/device_info
- */
-static int proc_scsi_dev_info_read(char *buffer, char **start, off_t offset,
- int length)
-{
- struct scsi_dev_info_list *devinfo;
- int size, len = 0;
- off_t begin = 0;
- off_t pos = 0;
-
- list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
- size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",
- devinfo->vendor, devinfo->model, devinfo->flags);
- len += size;
- pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
- }
-
-stop_output:
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- return (len);
-}
-
-/*
- * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
- * /proc.
- *
- * Use: echo "vendor:model:flag" > /proc/scsi/device_info
- *
- * To add a black/white list entry for vendor and model with an integer
- * value of flag to the scsi device info list.
- */
-static int proc_scsi_dev_info_write (struct file * file, const char * buf,
- unsigned long length, void *data)
-{
- char *buffer;
- int err = length;
-
- if (!buf || length>PAGE_SIZE)
- return -EINVAL;
- if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if(copy_from_user(buffer, buf, length)) {
- err =-EFAULT;
- goto out;
- }
-
- if (length < PAGE_SIZE)
- buffer[length] = '\0';
- else if (buffer[PAGE_SIZE-1]) {
- err = -EINVAL;
- goto out;
- }
-
- scsi_dev_info_list_add_str(buffer);
-
-out:
- free_page((unsigned long) buffer);
- return err;
-}
-
-static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
-{
- Scsi_Device *scd;
- struct Scsi_Host *HBA_ptr;
- int size, len = 0;
- off_t begin = 0;
- off_t pos = 0;
-
- /*
- * First, see if there are any attached devices or not.
- */
- for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
- HBA_ptr = scsi_host_get_next(HBA_ptr)) {
- if (HBA_ptr->host_queue != NULL) {
- break;
- }
- }
- size = sprintf(buffer + len, "Attached devices: %s\n", (HBA_ptr) ? "" : "none");
- len += size;
- pos = begin + len;
- for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
- HBA_ptr = scsi_host_get_next(HBA_ptr)) {
-#if 0
- size += sprintf(buffer + len, "scsi%2d: %s\n", (int) HBA_ptr->host_no,
- HBA_ptr->hostt->procname);
- len += size;
- pos = begin + len;
-#endif
- for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
- proc_print_scsidevice(scd, buffer, &size, len);
- len += size;
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
- }
- }
-
-stop_output:
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- return (len);
-}
-
-static int proc_scsi_gen_write(struct file * file, const char * buf,
- unsigned long length, void *data)
-{
- Scsi_Device *scd;
- struct Scsi_Host *HBA_ptr;
- char *p;
- int host, channel, id, lun;
- char * buffer;
- int err;
-
- if (!buf || length>PAGE_SIZE)
- return -EINVAL;
-
- if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if(copy_from_user(buffer, buf, length))
- {
- err =-EFAULT;
- goto out;
- }
-
- err = -EINVAL;
-
- if (length < PAGE_SIZE)
- buffer[length] = '\0';
- else if (buffer[PAGE_SIZE-1])
- goto out;
-
- if (length < 11 || strncmp("scsi", buffer, 4))
- goto out;
-
- /*
- * Usage: echo "scsi dump #N" > /proc/scsi/scsi
- * to dump status of all scsi commands. The number is used to specify the level
- * of detail in the dump.
- */
- if (!strncmp("dump", buffer + 5, 4)) {
- unsigned int level;
-
- p = buffer + 10;
-
- if (*p == '\0')
- goto out;
-
- level = simple_strtoul(p, NULL, 0);
- scsi_dump_status(level);
- }
- /*
- * Usage: echo "scsi log token #N" > /proc/scsi/scsi
- * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
- * llcomplete,hlqueue,hlcomplete]
- */
-#ifdef CONFIG_SCSI_LOGGING /* { */
-
- if (!strncmp("log", buffer + 5, 3)) {
- char *token;
- unsigned int level;
-
- p = buffer + 9;
- token = p;
- while (*p != ' ' && *p != '\t' && *p != '\0') {
- p++;
- }
-
- if (*p == '\0') {
- if (strncmp(token, "all", 3) == 0) {
- /*
- * Turn on absolutely everything.
- */
- scsi_logging_level = ~0;
- } else if (strncmp(token, "none", 4) == 0) {
- /*
- * Turn off absolutely everything.
- */
- scsi_logging_level = 0;
- } else {
- goto out;
- }
- } else {
- *p++ = '\0';
-
- level = simple_strtoul(p, NULL, 0);
-
- /*
- * Now figure out what to do with it.
- */
- if (strcmp(token, "error") == 0) {
- SCSI_SET_ERROR_RECOVERY_LOGGING(level);
- } else if (strcmp(token, "timeout") == 0) {
- SCSI_SET_TIMEOUT_LOGGING(level);
- } else if (strcmp(token, "scan") == 0) {
- SCSI_SET_SCAN_BUS_LOGGING(level);
- } else if (strcmp(token, "mlqueue") == 0) {
- SCSI_SET_MLQUEUE_LOGGING(level);
- } else if (strcmp(token, "mlcomplete") == 0) {
- SCSI_SET_MLCOMPLETE_LOGGING(level);
- } else if (strcmp(token, "llqueue") == 0) {
- SCSI_SET_LLQUEUE_LOGGING(level);
- } else if (strcmp(token, "llcomplete") == 0) {
- SCSI_SET_LLCOMPLETE_LOGGING(level);
- } else if (strcmp(token, "hlqueue") == 0) {
- SCSI_SET_HLQUEUE_LOGGING(level);
- } else if (strcmp(token, "hlcomplete") == 0) {
- SCSI_SET_HLCOMPLETE_LOGGING(level);
- } else if (strcmp(token, "ioctl") == 0) {
- SCSI_SET_IOCTL_LOGGING(level);
- } else {
- goto out;
- }
- }
-
- printk(KERN_INFO "scsi logging level set to 0x%8.8x\n", scsi_logging_level);
- }
-#endif /* CONFIG_SCSI_LOGGING */ /* } */
-
- /*
- * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
- * with "0 1 2 3" replaced by your "Host Channel Id Lun".
- * Consider this feature BETA.
- * CAUTION: This is not for hotplugging your peripherals. As
- * SCSI was not designed for this you could damage your
- * hardware !
- * However perhaps it is legal to switch on an
- * already connected device. It is perhaps not
- * guaranteed this device doesn't corrupt an ongoing data transfer.
- */
- if (!strncmp("add-single-device", buffer + 5, 17)) {
- p = buffer + 23;
-
- host = simple_strtoul(p, &p, 0);
- channel = simple_strtoul(p + 1, &p, 0);
- id = simple_strtoul(p + 1, &p, 0);
- lun = simple_strtoul(p + 1, &p, 0);
-
- printk(KERN_INFO "scsi singledevice %d %d %d %d\n", host, channel,
- id, lun);
-
- for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
- HBA_ptr = scsi_host_get_next(HBA_ptr)) {
- if (HBA_ptr->host_no == host) {
- break;
- }
- }
- err = -ENXIO;
- if (!HBA_ptr)
- goto out;
-
- for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
- if ((scd->channel == channel
- && scd->id == id
- && scd->lun == lun)) {
- break;
- }
- }
-
- err = -ENOSYS;
- if (scd)
- goto out; /* We do not yet support unplugging */
-
- scan_scsis(HBA_ptr, 1, channel, id, lun);
- err = length;
- goto out;
- }
- /*
- * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
- * with "0 1 2 3" replaced by your "Host Channel Id Lun".
- *
- * Consider this feature pre-BETA.
- *
- * CAUTION: This is not for hotplugging your peripherals. As
- * SCSI was not designed for this you could damage your
- * hardware and thoroughly confuse the SCSI subsystem.
- *
- */
- else if (!strncmp("remove-single-device", buffer + 5, 20)) {
- p = buffer + 26;
-
- host = simple_strtoul(p, &p, 0);
- channel = simple_strtoul(p + 1, &p, 0);
- id = simple_strtoul(p + 1, &p, 0);
- lun = simple_strtoul(p + 1, &p, 0);
-
-
- for (HBA_ptr = scsi_host_get_next(NULL); HBA_ptr;
- HBA_ptr = scsi_host_get_next(HBA_ptr)) {
- if (HBA_ptr->host_no == host) {
- break;
- }
- }
- err = -ENODEV;
- if (!HBA_ptr)
- goto out;
-
- for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
- if ((scd->channel == channel
- && scd->id == id
- && scd->lun == lun)) {
- break;
- }
- }
-
- if (scd == NULL)
- goto out; /* there is no such device attached */
-
- err = -EBUSY;
- if (scd->access_count)
- goto out;
-
- scsi_detach_device(scd);
-
- if (scd->attached == 0) {
- devfs_unregister (scd->de);
-
- /* Now we can remove the device structure */
- if (scd->next != NULL)
- scd->next->prev = scd->prev;
-
- if (scd->prev != NULL)
- scd->prev->next = scd->next;
-
- if (HBA_ptr->host_queue == scd) {
- HBA_ptr->host_queue = scd->next;
- }
- blk_cleanup_queue(&scd->request_queue);
- if (scd->inquiry)
- kfree(scd->inquiry);
- kfree((char *) scd);
- } else {
- goto out;
- }
- err = 0;
- }
-out:
-
- free_page((unsigned long) buffer);
- return err;
-}
-#endif
-
int scsi_attach_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
@@ -2470,86 +2102,6 @@
return -1;
}
-#ifdef CONFIG_PROC_FS
-/*
- * Function: scsi_dump_status
- *
- * Purpose: Brain dump of scsi system, used for problem solving.
- *
- * Arguments: level - used to indicate level of detail.
- *
- * Notes: The level isn't used at all yet, but we need to find some way
- * of sensibly logging varying degrees of information. A quick one-line
- * display of each command, plus the status would be most useful.
- *
- * This does depend upon CONFIG_SCSI_LOGGING - I do want some way of turning
- * it all off if the user wants a lean and mean kernel. It would probably
- * also be useful to allow the user to specify one single host to be dumped.
- * A second argument to the function would be useful for that purpose.
- *
- * FIXME - some formatting of the output into tables would be very handy.
- */
-static void scsi_dump_status(int level)
-{
-#ifdef CONFIG_SCSI_LOGGING /* { */
- int i;
- struct Scsi_Host *shpnt;
- Scsi_Cmnd *SCpnt;
- Scsi_Device *SDpnt;
- printk(KERN_INFO "Dump of scsi host parameters:\n");
- i = 0;
- for (shpnt = scsi_host_get_next(NULL); shpnt;
- shpnt = scsi_host_get_next(shpnt)) {
- printk(KERN_INFO " %d %d %d : %d %d\n",
- shpnt->host_failed,
- shpnt->host_busy,
- atomic_read(&shpnt->host_active),
- shpnt->host_blocked,
- shpnt->host_self_blocked);
- }
-
- printk(KERN_INFO "\n\n");
- printk(KERN_INFO "Dump of scsi command parameters:\n");
- for (shpnt = scsi_host_get_next(NULL); shpnt;
- shpnt = scsi_host_get_next(shpnt)) {
- printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n");
- for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
- for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
- /* (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x */
- printk(KERN_INFO "(%3d) %2d:%1d:%2d:%2d (%6s %4llu %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
- i++,
-
- SCpnt->host->host_no,
- SCpnt->channel,
- SCpnt->target,
- SCpnt->lun,
-
- SCpnt->request->rq_disk ?
- SCpnt->request->rq_disk->disk_name : "?",
- (unsigned long long)SCpnt->request->sector,
- SCpnt->request->nr_sectors,
- (long)SCpnt->request->current_nr_sectors,
- SCpnt->request->rq_status,
- SCpnt->use_sg,
-
- SCpnt->retries,
- SCpnt->allowed,
- SCpnt->flags,
-
- SCpnt->timeout_per_command,
- SCpnt->timeout,
- SCpnt->internal_timeout,
-
- SCpnt->cmnd[0],
- SCpnt->sense_buffer[2],
- SCpnt->result);
- }
- }
- }
-#endif /* CONFIG_SCSI_LOGGING */ /* } */
-}
-#endif /* CONFIG_PROC_FS */
-
static char *scsi_dev_flags;
MODULE_PARM(scsi_dev_flags, "s");
MODULE_PARM_DESC(scsi_dev_flags,
@@ -2671,7 +2223,6 @@
static int __init init_scsi(void)
{
- struct proc_dir_entry *generic;
int i;
printk(KERN_INFO "SCSI subsystem driver " REVISION "\n");
@@ -2692,44 +2243,12 @@
panic("SCSI: can't init sg mempool\n");
}
- /*
- * This makes /proc/scsi and /proc/scsi/scsi visible.
- */
-#ifdef CONFIG_PROC_FS
- proc_scsi = proc_mkdir("scsi", 0);
- if (!proc_scsi) {
- printk (KERN_ERR "cannot init /proc/scsi\n");
- return -ENOMEM;
- }
- generic = create_proc_info_entry ("scsi/scsi", 0, 0, scsi_proc_info);
- if (!generic) {
- printk (KERN_ERR "cannot init /proc/scsi/scsi\n");
- remove_proc_entry("scsi", 0);
- return -ENOMEM;
- }
- generic->write_proc = proc_scsi_gen_write;
-
- generic = create_proc_info_entry ("scsi/device_info", 0, 0,
- proc_scsi_dev_info_read);
- if (!generic) {
- printk (KERN_ERR "cannot init /proc/scsi/device_info\n");
- remove_proc_entry("scsi/scsi", 0);
- remove_proc_entry("scsi", 0);
- return -ENOMEM;
- }
- generic->write_proc = proc_scsi_dev_info_write;
-#endif
-
- scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", NULL);
-
+ scsi_init_procfs();
+ scsi_devfs_handle = devfs_mk_dir(NULL, "scsi", NULL);
scsi_host_init();
scsi_dev_info_list_init(scsi_dev_flags);
-
bus_register(&scsi_driverfs_bus_type);
-
- /* Where we handle work queued by scsi_done */
open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
-
return 0;
}
@@ -2737,17 +2256,10 @@
{
int i;
- devfs_unregister (scsi_devfs_handle);
+ devfs_unregister(scsi_devfs_handle);
+ scsi_exit_procfs();
scsi_dev_info_list_delete();
-
-#ifdef CONFIG_PROC_FS
- /* No, we're not here anymore. Don't show the /proc/scsi files. */
- remove_proc_entry ("scsi/device_info", 0);
- remove_proc_entry ("scsi/scsi", 0);
- remove_proc_entry ("scsi", 0);
-#endif
-
for (i = 0; i < SG_MEMPOOL_NR; i++) {
struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
mempool_destroy(sgp->pool);
===== drivers/scsi/scsi.h 1.40 vs edited =====
--- 1.40/drivers/scsi/scsi.h Thu Nov 14 12:34:35 2002
+++ edited/drivers/scsi/scsi.h Sat Nov 16 20:19:19 2002
@@ -391,6 +391,11 @@
#include "scsi_obsolete.h"
/*
+ * Forward-declaration of structs for prototypes.
+ */
+struct Scsi_Host;
+
+/*
* Add some typedefs so that we can prototyope a bunch of the functions.
*/
typedef struct scsi_device Scsi_Device;
@@ -496,8 +501,21 @@
/*
* Prototypes for functions in scsi_proc.c
*/
-extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
+#ifdef CONFIG_PROC_FS
+extern int scsi_init_procfs(void);
+extern void scsi_exit_procfs(void);
+
+extern void scsi_proc_host_add(struct Scsi_Host *);
+extern void scsi_proc_host_rm(struct Scsi_Host *);
+
extern struct proc_dir_entry *proc_scsi;
+#else
+static inline int scsi_init_procfs(void) { return 0; };
+static inline void scsi_exit_procfs(void) { };
+
+static inline void scsi_proc_host_add(struct Scsi_Host *);
+static inline void scsi_proc_host_rm(struct Scsi_Host *);
+#endif /* CONFIG_PROC_FS */
/*
* Prototypes for functions in constants.c
@@ -536,6 +554,8 @@
unsigned flags;
unsigned compatible; /* for use with scsi_static_device_list entries */
};
+extern struct list_head scsi_dev_info_list;
+extern int scsi_dev_info_list_add_str(char *);
/*
* The scsi_device struct contains what we know about each given scsi
===== drivers/scsi/scsi_proc.c 1.7 vs edited =====
--- 1.7/drivers/scsi/scsi_proc.c Wed Oct 16 18:51:48 2002
+++ edited/drivers/scsi/scsi_proc.c Sat Nov 16 20:19:19 2002
@@ -16,9 +16,8 @@
* Michael A. Griffith <grif@acm.org>
*/
-#include <linux/config.h> /* for CONFIG_PROC_FS */
+#include <linux/config.h>
#include <linux/module.h>
-
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -26,245 +25,133 @@
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/blk.h>
-
#include <asm/uaccess.h>
#include "scsi.h"
#include "hosts.h"
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
+/* 4K page size, but our output routines, use some slack for overruns */
+#define PROC_BLOCK_SIZE (3*1024)
-#ifdef CONFIG_PROC_FS
+/* XXX: this shouldn't really be exposed to drivers. */
+struct proc_dir_entry *proc_scsi;
+EXPORT_SYMBOL(proc_scsi);
-/* generic_proc_info
- * Used if the driver currently has no own support for /proc/scsi
- */
-int generic_proc_info(char *buffer, char **start, off_t offset, int length,
- const char *(*info) (struct Scsi_Host *),
- struct Scsi_Host *sh)
-{
- int len, pos, begin;
-
- begin = 0;
- if (info && sh) {
- pos = len = sprintf(buffer, "%s\n", info(sh));
- } else {
- pos = len = sprintf(buffer,
- "The driver does not yet support the proc-fs\n");
- }
+
+/* Used if the driver currently has no own support for /proc/scsi */
+static int generic_proc_info(char *buffer, char **start, off_t offset,
+ int count, const char *(*info)(struct Scsi_Host *),
+ struct Scsi_Host *shost)
+{
+ int len, pos, begin = 0;
+ static const char noprocfs[] =
+ "The driver does not yet support the proc-fs\n";
+
+ if (info && shost)
+ len = sprintf(buffer, "%s\n", info(shost));
+ else
+ len = sprintf(buffer, "%s\n", noprocfs);
+
+ pos = len;
if (pos < offset) {
len = 0;
begin = pos;
}
- *start = buffer + (offset - begin); /* Start of wanted data */
+
+ *start = buffer + (offset - begin);
len -= (offset - begin);
- if (len > length)
- len = length;
+ if (len > count)
+ len = count;
- return (len);
+ return len;
}
-/* dispatch_scsi_info is the central dispatcher
- * It is the interface between the proc-fs and the SCSI subsystem code
- */
static int proc_scsi_read(char *buffer, char **start, off_t offset,
- int length, int *eof, void *data)
+ int length, int *eof, void *data)
{
- struct Scsi_Host *hpnt = data;
+ struct Scsi_Host *shost = data;
int n;
- if (hpnt->hostt->proc_info == NULL)
+ if (shost->hostt->proc_info == NULL)
n = generic_proc_info(buffer, start, offset, length,
- hpnt->hostt->info, hpnt);
+ shost->hostt->info, shost);
else
- n = (hpnt->hostt->proc_info(buffer, start, offset,
- length, hpnt->host_no, 0));
- *eof = (n<length);
+ n = (shost->hostt->proc_info(buffer, start, offset,
+ length, shost->host_no, 0));
+
+ *eof = (n < length);
return n;
}
-#define PROC_BLOCK_SIZE (3*1024) /* 4K page size, but our output routines
- * use some slack for overruns
- */
-
-static int proc_scsi_write(struct file * file, const char * buf,
+static int proc_scsi_write(struct file *file, const char *buf,
unsigned long count, void *data)
{
- struct Scsi_Host *hpnt = data;
- ssize_t ret = 0;
- char * page;
+ struct Scsi_Host *shost = data;
+ ssize_t ret = -ENOMEM;
+ char *page;
char *start;
- if (hpnt->hostt->proc_info == NULL)
- ret = -ENOSYS;
-
+ if (!shost->hostt->proc_info)
+ return -ENOSYS;
if (count > PROC_BLOCK_SIZE)
return -EOVERFLOW;
- if (!(page = (char *) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- if(copy_from_user(page, buf, count))
- {
- free_page((ulong) page);
- return -EFAULT;
+ page = (char *)__get_free_page(GFP_KERNEL);
+ if (page) {
+ ret = -EFAULT;
+ if (copy_from_user(page, buf, count))
+ goto out;
+ ret = shost->hostt->proc_info(page, &start, 0, count,
+ shost->host_no, 1);
}
-
- ret = hpnt->hostt->proc_info(page, &start, 0, count,
- hpnt->host_no, 1);
-
- free_page((ulong) page);
- return(ret);
-}
-
-void scsi_proc_host_mkdir(Scsi_Host_Template *shost_tp)
-{
- shost_tp->proc_dir = proc_mkdir(shost_tp->proc_name, proc_scsi);
- if (!shost_tp->proc_dir) {
- printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
- __FUNCTION__, shost_tp->proc_name);
- return;
- }
- shost_tp->proc_dir->owner = shost_tp->module;
+out:
+ free_page((unsigned long)page);
+ return ret;
}
void scsi_proc_host_add(struct Scsi_Host *shost)
{
- char name[10];
+ Scsi_Host_Template *sht = shost->hostt;
struct proc_dir_entry *p;
+ char name[10];
- sprintf(name,"%d",shost->host_no);
- p = create_proc_read_entry(name,
- S_IFREG | S_IRUGO | S_IWUSR,
- shost->hostt->proc_dir,
- proc_scsi_read,
- (void *)shost);
+ if (!sht->proc_dir) {
+ sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
+ if (!sht->proc_dir) {
+ printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
+ __FUNCTION__, sht->proc_name);
+ return;
+ }
+ sht->proc_dir->owner = sht->module;
+ }
+
+ sprintf(name,"%d", shost->host_no);
+ p = create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
+ shost->hostt->proc_dir, proc_scsi_read, shost);
if (!p) {
printk(KERN_ERR "%s: Failed to register host %d in"
"%s\n", __FUNCTION__, shost->host_no,
shost->hostt->proc_name);
- } else {
- p->write_proc=proc_scsi_write;
- p->owner = shost->hostt->module;
- }
+ return;
+ }
+
+ p->write_proc = proc_scsi_write;
+ p->owner = shost->hostt->module;
}
void scsi_proc_host_rm(struct Scsi_Host *shost)
{
char name[10];
- sprintf(name,"%d",shost->host_no);
- remove_proc_entry(name, shost->hostt->proc_dir);
-}
-/*
- * parseHandle *parseInit(char *buf, char *cmdList, int cmdNum);
- * gets a pointer to a null terminated data buffer
- * and a list of commands with blanks as delimiter
- * in between.
- * The commands have to be alphanumerically sorted.
- * cmdNum has to contain the number of commands.
- * On success, a pointer to a handle structure
- * is returned, NULL on failure
- *
- * int parseOpt(parseHandle *handle, char **param);
- * processes the next parameter. On success, the
- * index of the appropriate command in the cmdList
- * is returned, starting with zero.
- * param points to the null terminated parameter string.
- * On failure, -1 is returned.
- *
- * The databuffer buf may only contain pairs of commands
- * options, separated by blanks:
- * <Command> <Parameter> [<Command> <Parameter>]*
- */
-
-typedef struct {
- char *buf, /* command buffer */
- *cmdList, /* command list */
- *bufPos, /* actual position */
- **cmdPos, /* cmdList index */
- cmdNum; /* cmd number */
-} parseHandle;
-
-inline int parseFree(parseHandle * handle)
-{ /* free memory */
- kfree(handle->cmdPos);
- kfree(handle);
-
- return -1;
-}
-
-parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
-{
- char *ptr; /* temp pointer */
- parseHandle *handle; /* new handle */
-
- if (!buf || !cmdList) /* bad input ? */
- return NULL;
- handle = (parseHandle *) kmalloc(sizeof(parseHandle), GFP_KERNEL);
- if (!handle)
- return NULL; /* out of memory */
- handle->cmdPos = (char **) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL);
- if (!handle->cmdPos) {
- kfree(handle);
- return NULL; /* out of memory */
- }
- handle->buf = handle->bufPos = buf; /* init handle */
- handle->cmdList = cmdList;
- handle->cmdNum = cmdNum;
-
- handle->cmdPos[cmdNum = 0] = cmdList;
- for (ptr = cmdList; *ptr; ptr++) { /* scan command string */
- if (*ptr == ' ') { /* and insert zeroes */
- *ptr++ = 0;
- handle->cmdPos[++cmdNum] = ptr++;
- }
- }
- return handle;
-}
-
-int parseOpt(parseHandle * handle, char **param)
-{
- int cmdIndex = 0, cmdLen = 0;
- char *startPos;
-
- if (!handle) /* invalid handle */
- return (parseFree(handle));
- /* skip spaces */
- for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
- if (!*(handle->bufPos))
- return (parseFree(handle)); /* end of data */
-
- startPos = handle->bufPos; /* store cmd start */
- for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) { /* no string end? */
- for (;;) {
- if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
- break; /* char matches ? */
- else if (memcmp(startPos, (char *) (handle->cmdPos[++cmdIndex]), cmdLen))
- return (parseFree(handle)); /* unknown command */
-
- if (cmdIndex >= handle->cmdNum)
- return (parseFree(handle)); /* unknown command */
- }
-
- cmdLen++; /* next char */
- }
-
- /* Get param. First skip all blanks, then insert zero after param */
-
- for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
- *param = handle->bufPos;
-
- for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
- *(handle->bufPos++) = 0;
-
- return (cmdIndex);
+ sprintf(name,"%d", shost->host_no);
+ remove_proc_entry(name, shost->hostt->proc_dir);
+ if (!shost->hostt->present)
+ remove_proc_entry(shost->hostt->proc_name, proc_scsi);
}
-void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
+/* XXX: this shouldn't really be exposed to drivers. */
+void proc_print_scsidevice(Scsi_Device * sdev, char *buffer, int *size, int len)
{
int x, y = *size;
@@ -272,35 +159,36 @@
y = sprintf(buffer + len,
"Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
- scd->host->host_no, scd->channel, scd->id, scd->lun);
+ sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
for (x = 0; x < 8; x++) {
- if (scd->vendor[x] >= 0x20)
- y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
+ if (sdev->vendor[x] >= 0x20)
+ y += sprintf(buffer + len + y, "%c", sdev->vendor[x]);
else
y += sprintf(buffer + len + y, " ");
}
y += sprintf(buffer + len + y, " Model: ");
for (x = 0; x < 16; x++) {
- if (scd->model[x] >= 0x20)
- y += sprintf(buffer + len + y, "%c", scd->model[x]);
+ if (sdev->model[x] >= 0x20)
+ y += sprintf(buffer + len + y, "%c", sdev->model[x]);
else
y += sprintf(buffer + len + y, " ");
}
y += sprintf(buffer + len + y, " Rev: ");
for (x = 0; x < 4; x++) {
- if (scd->rev[x] >= 0x20)
- y += sprintf(buffer + len + y, "%c", scd->rev[x]);
+ if (sdev->rev[x] >= 0x20)
+ y += sprintf(buffer + len + y, "%c", sdev->rev[x]);
else
y += sprintf(buffer + len + y, " ");
}
y += sprintf(buffer + len + y, "\n");
y += sprintf(buffer + len + y, " Type: %s ",
- scd->type < MAX_SCSI_DEVICE_CODE ?
- scsi_device_types[(int) scd->type] : "Unknown ");
+ sdev->type < MAX_SCSI_DEVICE_CODE ?
+ scsi_device_types[(int) sdev->type] : "Unknown ");
y += sprintf(buffer + len + y, " ANSI"
- " SCSI revision: %02x", (scd->scsi_level - 1) ? scd->scsi_level - 1 : 1);
- if (scd->scsi_level == 2)
+ " SCSI revision: %02x", (sdev->scsi_level - 1) ?
+ sdev->scsi_level - 1 : 1);
+ if (sdev->scsi_level == 2)
y += sprintf(buffer + len + y, " CCS\n");
else
y += sprintf(buffer + len + y, "\n");
@@ -308,30 +196,474 @@
*size = y;
return;
}
+EXPORT_SYMBOL(proc_print_scsidevice);
-#else /* if !CONFIG_PROC_FS */
+/*
+ * proc_scsi_dev_info_read: dump the scsi_dev_info_list via
+ * /proc/scsi/device_info
+ */
+static int proc_scsi_dev_info_read(char *buffer, char **start, off_t offset,
+ int length)
+{
+ struct scsi_dev_info_list *devinfo;
+ int size, len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+
+ list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
+ size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",
+ devinfo->vendor, devinfo->model, devinfo->flags);
+ len += size;
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+ }
-void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
+stop_output:
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ return (len);
+}
+
+/*
+ * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
+ * /proc.
+ *
+ * Use: echo "vendor:model:flag" > /proc/scsi/device_info
+ *
+ * To add a black/white list entry for vendor and model with an integer
+ * value of flag to the scsi device info list.
+ */
+static int proc_scsi_dev_info_write (struct file * file, const char * buf,
+ unsigned long length, void *data)
{
+ char *buffer;
+ int err = length;
+
+ if (!buf || length>PAGE_SIZE)
+ return -EINVAL;
+ if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ if (copy_from_user(buffer, buf, length)) {
+ err =-EFAULT;
+ goto out;
+ }
+
+ if (length < PAGE_SIZE)
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ scsi_dev_info_list_add_str(buffer);
+
+out:
+ free_page((unsigned long)buffer);
+ return err;
}
-#endif /* CONFIG_PROC_FS */
+static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
+{
+ struct Scsi_Host *shost;
+ Scsi_Device *sdev;
+ int size, len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+
+ /*
+ * First, see if there are any attached devices or not.
+ */
+ for (shost = scsi_host_get_next(NULL); shost;
+ shost = scsi_host_get_next(shost)) {
+ if (shost->host_queue != NULL) {
+ break;
+ }
+ }
+ size = sprintf(buffer + len, "Attached devices: %s\n",
+ (shost) ? "" : "none");
+ len += size;
+ pos = begin + len;
+ for (shost = scsi_host_get_next(NULL); shost;
+ shost = scsi_host_get_next(shost)) {
+ for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+ proc_print_scsidevice(sdev, buffer, &size, len);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+ }
+ }
+
+stop_output:
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ return (len);
+}
+#ifdef CONFIG_SCSI_LOGGING
/*
- * Overrides for Emacs so that we get a uniform tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
+ * Function: scsi_dump_status
+ *
+ * Purpose: Brain dump of scsi system, used for problem solving.
+ *
+ * Arguments: level - used to indicate level of detail.
+ *
+ * Notes: The level isn't used at all yet, but we need to find some
+ * way of sensibly logging varying degrees of information.
+ * A quick one-line display of each command, plus the status
+ * would be most useful.
+ *
+ * This does depend upon CONFIG_SCSI_LOGGING - I do want some
+ * way of turning it all off if the user wants a lean and mean
+ * kernel. It would probably also be useful to allow the user
+ * to specify one single host to be dumped. A second argument
+ * to the function would be useful for that purpose.
+ *
+ * FIXME - some formatting of the output into tables would be
+ * very handy.
*/
+static void scsi_dump_status(int level)
+{
+ int i;
+ struct Scsi_Host *shpnt;
+ Scsi_Cmnd *SCpnt;
+ Scsi_Device *SDpnt;
+ printk(KERN_INFO "Dump of scsi host parameters:\n");
+ i = 0;
+ for (shpnt = scsi_host_get_next(NULL); shpnt;
+ shpnt = scsi_host_get_next(shpnt)) {
+ printk(KERN_INFO " %d %d %d : %d %d\n",
+ shpnt->host_failed,
+ shpnt->host_busy,
+ atomic_read(&shpnt->host_active),
+ shpnt->host_blocked,
+ shpnt->host_self_blocked);
+ }
+
+ printk(KERN_INFO "\n\n");
+ printk(KERN_INFO "Dump of scsi command parameters:\n");
+ for (shpnt = scsi_host_get_next(NULL); shpnt;
+ shpnt = scsi_host_get_next(shpnt)) {
+ printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) "
+ "(ret all flg) (to/cmd to ito) cmd snse result\n");
+ for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+ /* (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x */
+ printk(KERN_INFO "(%3d) %2d:%1d:%2d:%2d (%6s %4llu %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
+ i++,
+
+ SCpnt->host->host_no,
+ SCpnt->channel,
+ SCpnt->target,
+ SCpnt->lun,
+
+ SCpnt->request->rq_disk ?
+ SCpnt->request->rq_disk->disk_name : "?",
+ (unsigned long long)SCpnt->request->sector,
+ SCpnt->request->nr_sectors,
+ (long)SCpnt->request->current_nr_sectors,
+ SCpnt->request->rq_status,
+ SCpnt->use_sg,
+
+ SCpnt->retries,
+ SCpnt->allowed,
+ SCpnt->flags,
+
+ SCpnt->timeout_per_command,
+ SCpnt->timeout,
+ SCpnt->internal_timeout,
+
+ SCpnt->cmnd[0],
+ SCpnt->sense_buffer[2],
+ SCpnt->result);
+ }
+ }
+ }
+}
+#endif /* CONFIG_SCSI_LOGGING */
+
+static int proc_scsi_gen_write(struct file * file, const char * buf,
+ unsigned long length, void *data)
+{
+ Scsi_Device *sdev;
+ struct Scsi_Host *shost;
+ char *p;
+ int host, channel, id, lun;
+ char * buffer;
+ int err;
+
+ if (!buf || length>PAGE_SIZE)
+ return -EINVAL;
+
+ buffer = (char *)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ if (copy_from_user(buffer, buf, length)) {
+ err =-EFAULT;
+ goto out;
+ }
+
+ err = -EINVAL;
+
+ if (length < PAGE_SIZE)
+ buffer[length] = '\0';
+ else if (buffer[PAGE_SIZE-1])
+ goto out;
+
+ if (length < 11 || strncmp("scsi", buffer, 4))
+ goto out;
+
+#ifdef CONFIG_SCSI_LOGGING
+ /*
+ * Usage: echo "scsi dump #N" > /proc/scsi/scsi
+ * to dump status of all scsi commands. The number is used to
+ * specify the level of detail in the dump.
+ */
+ if (!strncmp("dump", buffer + 5, 4)) {
+ unsigned int level;
+
+ p = buffer + 10;
+
+ if (*p == '\0')
+ goto out;
+
+ level = simple_strtoul(p, NULL, 0);
+ scsi_dump_status(level);
+ }
+ /*
+ * Usage: echo "scsi log token #N" > /proc/scsi/scsi
+ * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
+ * llcomplete,hlqueue,hlcomplete]
+ */
+ if (!strncmp("log", buffer + 5, 3)) {
+ char *token;
+ unsigned int level;
+
+ p = buffer + 9;
+ token = p;
+ while (*p != ' ' && *p != '\t' && *p != '\0') {
+ p++;
+ }
+
+ if (*p == '\0') {
+ if (strncmp(token, "all", 3) == 0) {
+ /*
+ * Turn on absolutely everything.
+ */
+ scsi_logging_level = ~0;
+ } else if (strncmp(token, "none", 4) == 0) {
+ /*
+ * Turn off absolutely everything.
+ */
+ scsi_logging_level = 0;
+ } else {
+ goto out;
+ }
+ } else {
+ *p++ = '\0';
+
+ level = simple_strtoul(p, NULL, 0);
+
+ /*
+ * Now figure out what to do with it.
+ */
+ if (strcmp(token, "error") == 0) {
+ SCSI_SET_ERROR_RECOVERY_LOGGING(level);
+ } else if (strcmp(token, "timeout") == 0) {
+ SCSI_SET_TIMEOUT_LOGGING(level);
+ } else if (strcmp(token, "scan") == 0) {
+ SCSI_SET_SCAN_BUS_LOGGING(level);
+ } else if (strcmp(token, "mlqueue") == 0) {
+ SCSI_SET_MLQUEUE_LOGGING(level);
+ } else if (strcmp(token, "mlcomplete") == 0) {
+ SCSI_SET_MLCOMPLETE_LOGGING(level);
+ } else if (strcmp(token, "llqueue") == 0) {
+ SCSI_SET_LLQUEUE_LOGGING(level);
+ } else if (strcmp(token, "llcomplete") == 0) {
+ SCSI_SET_LLCOMPLETE_LOGGING(level);
+ } else if (strcmp(token, "hlqueue") == 0) {
+ SCSI_SET_HLQUEUE_LOGGING(level);
+ } else if (strcmp(token, "hlcomplete") == 0) {
+ SCSI_SET_HLCOMPLETE_LOGGING(level);
+ } else if (strcmp(token, "ioctl") == 0) {
+ SCSI_SET_IOCTL_LOGGING(level);
+ } else {
+ goto out;
+ }
+ }
+
+ printk(KERN_INFO "scsi logging level set to 0x%8.8x\n", scsi_logging_level);
+ }
+#endif /* CONFIG_SCSI_LOGGING */
+
+ /*
+ * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
+ * with "0 1 2 3" replaced by your "Host Channel Id Lun".
+ * Consider this feature BETA.
+ * CAUTION: This is not for hotplugging your peripherals. As
+ * SCSI was not designed for this you could damage your
+ * hardware !
+ * However perhaps it is legal to switch on an
+ * already connected device. It is perhaps not
+ * guaranteed this device doesn't corrupt an ongoing data transfer.
+ */
+ if (!strncmp("add-single-device", buffer + 5, 17)) {
+ p = buffer + 23;
+
+ host = simple_strtoul(p, &p, 0);
+ channel = simple_strtoul(p + 1, &p, 0);
+ id = simple_strtoul(p + 1, &p, 0);
+ lun = simple_strtoul(p + 1, &p, 0);
+
+ printk(KERN_INFO "scsi singledevice %d %d %d %d\n", host, channel,
+ id, lun);
+
+ for (shost = scsi_host_get_next(NULL); shost;
+ shost = scsi_host_get_next(shost)) {
+ if (shost->host_no == host) {
+ break;
+ }
+ }
+ err = -ENXIO;
+ if (!shost)
+ goto out;
+
+ for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+ if ((sdev->channel == channel
+ && sdev->id == id
+ && sdev->lun == lun)) {
+ break;
+ }
+ }
+
+ err = -ENOSYS;
+ if (sdev)
+ goto out; /* We do not yet support unplugging */
+
+ scan_scsis(shost, 1, channel, id, lun);
+ err = length;
+ goto out;
+ }
+ /*
+ * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
+ * with "0 1 2 3" replaced by your "Host Channel Id Lun".
+ *
+ * Consider this feature pre-BETA.
+ *
+ * CAUTION: This is not for hotplugging your peripherals. As
+ * SCSI was not designed for this you could damage your
+ * hardware and thoroughly confuse the SCSI subsystem.
+ *
+ */
+ else if (!strncmp("remove-single-device", buffer + 5, 20)) {
+ p = buffer + 26;
+
+ host = simple_strtoul(p, &p, 0);
+ channel = simple_strtoul(p + 1, &p, 0);
+ id = simple_strtoul(p + 1, &p, 0);
+ lun = simple_strtoul(p + 1, &p, 0);
+
+
+ for (shost = scsi_host_get_next(NULL); shost;
+ shost = scsi_host_get_next(shost)) {
+ if (shost->host_no == host) {
+ break;
+ }
+ }
+ err = -ENODEV;
+ if (!shost)
+ goto out;
+
+ for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+ if ((sdev->channel == channel
+ && sdev->id == id
+ && sdev->lun == lun)) {
+ break;
+ }
+ }
+
+ if (sdev == NULL)
+ goto out; /* there is no such device attached */
+
+ err = -EBUSY;
+ if (sdev->access_count)
+ goto out;
+
+ scsi_detach_device(sdev);
+
+ if (sdev->attached == 0) {
+ devfs_unregister (sdev->de);
+
+ /* Now we can remove the device structure */
+ if (sdev->next != NULL)
+ sdev->next->prev = sdev->prev;
+
+ if (sdev->prev != NULL)
+ sdev->prev->next = sdev->next;
+
+ if (shost->host_queue == sdev) {
+ shost->host_queue = sdev->next;
+ }
+ blk_cleanup_queue(&sdev->request_queue);
+ if (sdev->inquiry)
+ kfree(sdev->inquiry);
+ kfree((char *) sdev);
+ } else {
+ goto out;
+ }
+ err = 0;
+ }
+out:
+
+ free_page((unsigned long)buffer);
+ return err;
+}
+
+int __init scsi_init_procfs(void)
+{
+ struct proc_dir_entry *pde;
+
+ proc_scsi = proc_mkdir("scsi", 0);
+ if (!proc_scsi)
+ goto err1;
+
+ pde = create_proc_info_entry("scsi/scsi", 0, 0, scsi_proc_info);
+ if (!pde)
+ goto err2;
+ pde->write_proc = proc_scsi_gen_write;
+
+ pde = create_proc_info_entry("scsi/device_info", 0, 0,
+ proc_scsi_dev_info_read);
+ if (!pde)
+ goto err3;
+ pde->write_proc = proc_scsi_dev_info_write;
+ return 0;
+
+err3:
+ remove_proc_entry("scsi/scsi", 0);
+err2:
+ remove_proc_entry("scsi", 0);
+err1:
+ return -ENOMEM;
+}
+
+void __exit scsi_exit_procfs(void)
+{
+ remove_proc_entry("scsi/device_info", 0);
+ remove_proc_entry("scsi/scsi", 0);
+ remove_proc_entry("scsi", 0);
+}
===== drivers/scsi/scsi_syms.c 1.18 vs edited =====
--- 1.18/drivers/scsi/scsi_syms.c Wed Nov 6 16:12:50 2002
+++ edited/drivers/scsi/scsi_syms.c Sat Nov 16 20:19:19 2002
@@ -74,9 +74,6 @@
EXPORT_SYMBOL(scsi_sleep);
-EXPORT_SYMBOL(proc_print_scsidevice);
-EXPORT_SYMBOL(proc_scsi);
-
EXPORT_SYMBOL(scsi_io_completion);
EXPORT_SYMBOL(scsi_end_request);
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2002-11-16 20:54 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-11-16 19:02 [PATCH] move all procfs code to scsi_proc.c Christoph Hellwig
2002-11-16 20:01 ` Patrick Mansfield
2002-11-16 20:54 ` Christoph Hellwig
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.