I'm not sure if people care about /proc/scsi, but here is a patch so you can cat /proc/scsi/scsi when you have a large number of scsi devices. I have over 4000 devices configured and when I would cat /proc/scsi/scsi I would see a memory allocation error. I instead used the seq_file iterator to display the devices. The patch is a little brute force, but it only took about 2.5 seconds to display 4000 devices. Applies to scsi-misc-2.6 git tree Signed-off-by: Mark Haverkamp <markh@xxxxxxxx> Index: scsi-misc-aac-2/drivers/scsi/scsi_proc.c =================================================================== --- scsi-misc-aac-2.orig/drivers/scsi/scsi_proc.c 2005-08-22 11:53:41.000000000 -0700 +++ scsi-misc-aac-2/drivers/scsi/scsi_proc.c 2005-08-23 08:45:09.000000000 -0700 @@ -43,6 +43,10 @@ /* Protect sht->present and sht->proc_dir */ static DECLARE_MUTEX(global_host_template_sem); +static struct device *proc_dev; +static loff_t dev_skip; +static DECLARE_MUTEX(proc_dev_sem); + static int proc_scsi_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { @@ -142,53 +146,6 @@ remove_proc_entry(name, shost->hostt->proc_dir); } -static int proc_print_scsidevice(struct device *dev, void *data) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct seq_file *s = data; - int i; - - seq_printf(s, - "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ", - sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - for (i = 0; i < 8; i++) { - if (sdev->vendor[i] >= 0x20) - seq_printf(s, "%c", sdev->vendor[i]); - else - seq_printf(s, " "); - } - - seq_printf(s, " Model: "); - for (i = 0; i < 16; i++) { - if (sdev->model[i] >= 0x20) - seq_printf(s, "%c", sdev->model[i]); - else - seq_printf(s, " "); - } - - seq_printf(s, " Rev: "); - for (i = 0; i < 4; i++) { - if (sdev->rev[i] >= 0x20) - seq_printf(s, "%c", sdev->rev[i]); - else - seq_printf(s, " "); - } - - seq_printf(s, "\n"); - - seq_printf(s, " Type: %s ", - sdev->type < MAX_SCSI_DEVICE_CODE ? - scsi_device_types[(int) sdev->type] : "Unknown "); - seq_printf(s, " ANSI" - " SCSI revision: %02x", (sdev->scsi_level - 1) ? - sdev->scsi_level - 1 : 1); - if (sdev->scsi_level == 2) - seq_printf(s, " CCS\n"); - else - seq_printf(s, "\n"); - - return 0; -} static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) { @@ -284,20 +241,101 @@ return err; } -static int proc_scsi_show(struct seq_file *s, void *p) + +static int proc_set_scsidevice(struct device *dev, void *data) +{ + if (dev_skip--) + return 0; + + proc_dev = dev; + return -ENXIO; +} + +static void *proc_dev_start(struct seq_file *s, loff_t *pos) { - seq_printf(s, "Attached devices:\n"); - bus_for_each_dev(&scsi_bus_type, NULL, s, proc_print_scsidevice); + down(&proc_dev_sem); + proc_dev = NULL; + dev_skip = *pos; + bus_for_each_dev(&scsi_bus_type, NULL, + NULL, proc_set_scsidevice); + return proc_dev; +} + +static void *proc_dev_next(struct seq_file *part, void *v, loff_t *pos) +{ + dev_skip = ++*pos; + proc_dev = NULL; + bus_for_each_dev(&scsi_bus_type, NULL, + NULL, proc_set_scsidevice); + return proc_dev; +} + +static void proc_dev_stop(struct seq_file *part, void *v) +{ + up(&proc_dev_sem); +} + +static int proc_dev_show(struct seq_file *s, void *data) +{ + struct scsi_device *sdev = to_scsi_device((struct device*)data); + int i; + + seq_printf(s, + "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ", + sdev->host->host_no, sdev->channel, + sdev->id, sdev->lun); + for (i = 0; i < 8; i++) { + if (sdev->vendor[i] >= 0x20) + seq_printf(s, "%c", sdev->vendor[i]); + else + seq_printf(s, " "); + } + + seq_printf(s, " Model: "); + for (i = 0; i < 16; i++) { + if (sdev->model[i] >= 0x20) + seq_printf(s, "%c", sdev->model[i]); + else + seq_printf(s, " "); + } + + seq_printf(s, " Rev: "); + for (i = 0; i < 4; i++) { + if (sdev->rev[i] >= 0x20) + seq_printf(s, "%c", sdev->rev[i]); + else + seq_printf(s, " "); + } + + seq_printf(s, "\n"); + + seq_printf(s, " Type: %s ", + sdev->type < MAX_SCSI_DEVICE_CODE ? + scsi_device_types[(int) sdev->type] : "Unknown "); + seq_printf(s, " ANSI" + " SCSI revision: %02x", (sdev->scsi_level - 1) ? + sdev->scsi_level - 1 : 1); + if (sdev->scsi_level == 2) + seq_printf(s, " CCS\n"); + else + seq_printf(s, "\n"); + return 0; } +struct seq_operations proc_dev_op = { + .start =proc_dev_start, + .next = proc_dev_next, + .stop = proc_dev_stop, + .show = proc_dev_show +}; static int proc_scsi_open(struct inode *inode, struct file *file) { /* * We don't really needs this for the write case but it doesn't * harm either. */ - return single_open(file, proc_scsi_show, NULL); + return seq_open(file, &proc_dev_op); } static struct file_operations proc_scsi_operations = { @@ -305,7 +343,7 @@ .read = seq_read, .write = proc_scsi_write, .llseek = seq_lseek, - .release = single_release, + .release = seq_release }; int __init scsi_init_procfs(void) -- Mark Haverkamp <markh@xxxxxxxx> - : send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html