Commit 8bd14260 authored by Christoph Hellwig's avatar Christoph Hellwig

[PATCH] make scsi logging level a sysctl

The logging level is now controlled by a
/proc/sys/dev/scsi/logging_level sysctl instead of /proc/scsi/scsi.
The format is the same as the logging_level module parameter.
parent 2a1464ac
...@@ -126,6 +126,7 @@ scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ ...@@ -126,6 +126,7 @@ scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
scsicam.o scsi_error.o scsi_lib.o \ scsicam.o scsi_error.o scsi_lib.o \
scsi_scan.o scsi_syms.o scsi_sysfs.o \ scsi_scan.o scsi_syms.o scsi_sysfs.o \
scsi_devinfo.o scsi_devinfo.o
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_PROC_FS) += scsi_proc.o scsi_mod-$(CONFIG_PROC_FS) += scsi_proc.o
scsi_mod-$(CONFIG_X86_PC9800) += scsi_pc98.o scsi_mod-$(CONFIG_X86_PC9800) += scsi_pc98.o
......
...@@ -1006,9 +1006,12 @@ static int __init init_scsi(void) ...@@ -1006,9 +1006,12 @@ static int __init init_scsi(void)
error = scsi_init_hosts(); error = scsi_init_hosts();
if (error) if (error)
goto cleanup_devlist; goto cleanup_devlist;
error = scsi_sysfs_register(); error = scsi_init_sysctl();
if (error) if (error)
goto cleanup_hosts; goto cleanup_hosts;
error = scsi_sysfs_register();
if (error)
goto cleanup_sysctl;
for (i = 0; i < NR_CPUS; i++) for (i = 0; i < NR_CPUS; i++)
INIT_LIST_HEAD(&done_q[i]); INIT_LIST_HEAD(&done_q[i]);
...@@ -1018,6 +1021,8 @@ static int __init init_scsi(void) ...@@ -1018,6 +1021,8 @@ static int __init init_scsi(void)
printk(KERN_NOTICE "SCSI subsystem initialized\n"); printk(KERN_NOTICE "SCSI subsystem initialized\n");
return 0; return 0;
cleanup_sysctl:
scsi_exit_sysctl();
cleanup_hosts: cleanup_hosts:
scsi_exit_hosts(); scsi_exit_hosts();
cleanup_devlist: cleanup_devlist:
...@@ -1034,6 +1039,7 @@ static int __init init_scsi(void) ...@@ -1034,6 +1039,7 @@ static int __init init_scsi(void)
static void __exit exit_scsi(void) static void __exit exit_scsi(void)
{ {
scsi_sysfs_unregister(); scsi_sysfs_unregister();
scsi_exit_sysctl();
scsi_exit_hosts(); scsi_exit_hosts();
scsi_exit_devinfo(); scsi_exit_devinfo();
devfs_remove("scsi"); devfs_remove("scsi");
......
...@@ -46,30 +46,14 @@ extern unsigned int scsi_logging_level; ...@@ -46,30 +46,14 @@ extern unsigned int scsi_logging_level;
if (((scsi_logging_level >> (SHIFT)) & mask) > (LEVEL)) \ if (((scsi_logging_level >> (SHIFT)) & mask) > (LEVEL)) \
(CMD); \ (CMD); \
} }
#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL) \
{ \
unsigned int mask = ((1 << (BITS)) - 1) << SHIFT; \
scsi_logging_level = ((scsi_logging_level & ~mask) \
| ((LEVEL << SHIFT) & mask)); \
}
#else #else
/*
* With no logging enabled, stub these out so they don't do anything.
*/
#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD) #define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)
#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)
#endif /* CONFIG_SCSI_LOGGING */ #endif /* CONFIG_SCSI_LOGGING */
/* /*
* These are the macros that are actually used throughout the code to * These are the macros that are actually used throughout the code to
* log events. If logging isn't enabled, they are no-ops and will be * log events. If logging isn't enabled, they are no-ops and will be
* completely absent from the user's code. * completely absent from the user's code.
*
* The 'set' versions of the macros are really intended to only be called
* from the /proc filesystem, and in production kernels this will be about
* all that is ever used. It could be useful in a debugging environment to
* bump the logging level when certain strange events are detected, however.
*/ */
#define SCSI_LOG_ERROR_RECOVERY(LEVEL,CMD) \ #define SCSI_LOG_ERROR_RECOVERY(LEVEL,CMD) \
SCSI_CHECK_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD); SCSI_CHECK_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD);
...@@ -92,26 +76,4 @@ extern unsigned int scsi_logging_level; ...@@ -92,26 +76,4 @@ extern unsigned int scsi_logging_level;
#define SCSI_LOG_IOCTL(LEVEL,CMD) \ #define SCSI_LOG_IOCTL(LEVEL,CMD) \
SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD); SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD);
#define SCSI_SET_ERROR_RECOVERY_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL);
#define SCSI_SET_TIMEOUT_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL);
#define SCSI_SET_SCAN_BUS_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL);
#define SCSI_SET_MLQUEUE_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL);
#define SCSI_SET_MLCOMPLETE_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL);
#define SCSI_SET_LLQUEUE_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL);
#define SCSI_SET_LLCOMPLETE_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL);
#define SCSI_SET_HLQUEUE_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL);
#define SCSI_SET_HLCOMPLETE_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL);
#define SCSI_SET_IOCTL_LOGGING(LEVEL) \
SCSI_SET_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL);
#endif /* _SCSI_LOGGING_H */ #endif /* _SCSI_LOGGING_H */
...@@ -132,6 +132,15 @@ extern void scsi_forget_host(struct Scsi_Host *); ...@@ -132,6 +132,15 @@ extern void scsi_forget_host(struct Scsi_Host *);
extern void scsi_free_sdev(struct scsi_device *); extern void scsi_free_sdev(struct scsi_device *);
extern void scsi_rescan_device(struct device *); extern void scsi_rescan_device(struct device *);
/* scsi_sysctl.c */
#ifdef CONFIG_SYSCTL
extern int scsi_init_sysctl(void);
extern void scsi_exit_sysctl(void);
#else
# define scsi_init_sysctl() (0)
# define scsi_exit_sysctl() do { } while (0)
#endif /* CONFIG_SYSCTL */
/* scsi_sysfs.c */ /* scsi_sysfs.c */
extern int scsi_device_register(struct scsi_device *); extern int scsi_device_register(struct scsi_device *);
extern int scsi_sysfs_add_host(struct Scsi_Host *); extern int scsi_sysfs_add_host(struct Scsi_Host *);
......
...@@ -235,106 +235,28 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, ...@@ -235,106 +235,28 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
char *buffer, *p; char *buffer, *p;
int err; int err;
if (!buf || length>PAGE_SIZE) if (!buf || length > PAGE_SIZE)
return -EINVAL; return -EINVAL;
buffer = (char *)__get_free_page(GFP_KERNEL); buffer = (char *)__get_free_page(GFP_KERNEL);
if (!buffer) if (!buffer)
return -ENOMEM; return -ENOMEM;
if (copy_from_user(buffer, buf, length)) {
err =-EFAULT; err = -EFAULT;
if (copy_from_user(buffer, buf, length))
goto out; goto out;
}
err = -EINVAL; err = -EINVAL;
if (length < PAGE_SIZE) if (length < PAGE_SIZE)
buffer[length] = '\0'; buffer[length] = '\0';
else if (buffer[PAGE_SIZE-1]) else if (buffer[PAGE_SIZE-1])
goto out; goto out;
if (length < 11 || strncmp("scsi", buffer, 4))
goto out;
#ifdef CONFIG_SCSI_LOGGING
/*
* 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 * 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". * 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)) { if (!strncmp("scsi add-single-device", buffer, 22)) {
p = buffer + 23; p = buffer + 23;
host = simple_strtoul(p, &p, 0); host = simple_strtoul(p, &p, 0);
...@@ -345,18 +267,12 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, ...@@ -345,18 +267,12 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
err = scsi_add_single_device(host, channel, id, lun); err = scsi_add_single_device(host, channel, id, lun);
if (err >= 0) if (err >= 0)
err = length; err = length;
/* /*
* Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi * 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". * 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)) { } else if (!strncmp("scsi remove-single-device", buffer, 25)) {
p = buffer + 26; p = buffer + 26;
host = simple_strtoul(p, &p, 0); host = simple_strtoul(p, &p, 0);
...@@ -366,8 +282,8 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, ...@@ -366,8 +282,8 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
err = scsi_remove_single_device(host, channel, id, lun); err = scsi_remove_single_device(host, channel, id, lun);
} }
out:
out:
free_page((unsigned long)buffer); free_page((unsigned long)buffer);
return err; return err;
} }
......
/*
* Copyright (C) 2003 Christoph Hellwig.
* Released under GPL v2.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sysctl.h>
#include "scsi_logging.h"
static ctl_table scsi_table[] = {
{ .ctl_name = DEV_SCSI_LOGGING_LEVEL,
.procname = "logging_level",
.data = &scsi_logging_level,
.maxlen = sizeof(scsi_logging_level),
.mode = 0644,
.proc_handler = &proc_dointvec },
{ }
};
static ctl_table scsi_dir_table[] = {
{ .ctl_name = DEV_SCSI,
.procname = "scsi",
.mode = 0555,
.child = scsi_table },
{ }
};
static ctl_table scsi_root_table[] = {
{ .ctl_name = CTL_DEV,
.procname = "dev",
.mode = 0555,
.child = scsi_dir_table },
{ }
};
static struct ctl_table_header *scsi_table_header;
int __init scsi_init_sysctl(void)
{
scsi_table_header = register_sysctl_table(scsi_root_table, 1);
if (!scsi_table_header)
return -ENOMEM;
return 0;
}
void scsi_exit_sysctl(void)
{
unregister_sysctl_table(scsi_table_header);
}
...@@ -603,7 +603,8 @@ enum { ...@@ -603,7 +603,8 @@ enum {
DEV_HWMON=2, DEV_HWMON=2,
DEV_PARPORT=3, DEV_PARPORT=3,
DEV_RAID=4, DEV_RAID=4,
DEV_MAC_HID=5 DEV_MAC_HID=5,
DEV_SCSI=6,
}; };
/* /proc/sys/dev/cdrom */ /* /proc/sys/dev/cdrom */
...@@ -664,6 +665,11 @@ enum { ...@@ -664,6 +665,11 @@ enum {
DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES=6 DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES=6
}; };
/* /proc/sys/dev/scsi */
enum {
DEV_SCSI_LOGGING_LEVEL=1,
};
/* /proc/sys/abi */ /* /proc/sys/abi */
enum enum
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment