From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christoph Hellwig Subject: [PATCH] move all procfs code to scsi_proc.c Date: Sat, 16 Nov 2002 20:02:49 +0100 Sender: linux-scsi-owner@vger.kernel.org Message-ID: <20021116200249.A23459@lst.de> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Return-path: Content-Disposition: inline List-Id: linux-scsi@vger.kernel.org To: James.Bottomley@steeleye.com Cc: linux-scsi@vger.kernel.org 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 #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 */ -#include /* for CONFIG_PROC_FS */ +#include #include - #include #include #include @@ -26,245 +25,133 @@ #include #include #include - #include #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 = (nhostt->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: - * [ ]* - */ - -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);