From: Markus Lidel <Markus.Lidel@shadowconnect.com>

The patch converts i2o_proc to seq_file, thereby fixing a bug in the
i2o_proc.c module, where the kernel panics, if you access /proc/i2o/iop0/lct
and read more then 1024 bytes of it.


---

 25-akpm/drivers/message/i2o/i2o_proc.c |  401 ++++++++++++++++-----------------
 1 files changed, 206 insertions(+), 195 deletions(-)

diff -puN drivers/message/i2o/i2o_proc.c~to-fix-i2o_proc-kernel-panic-on-access-of-proc-i2o-iop0-lct drivers/message/i2o/i2o_proc.c
--- 25/drivers/message/i2o/i2o_proc.c~to-fix-i2o_proc-kernel-panic-on-access-of-proc-i2o-iop0-lct	2004-05-08 23:23:35.691190488 -0700
+++ 25-akpm/drivers/message/i2o/i2o_proc.c	2004-05-08 23:23:35.701188968 -0700
@@ -43,6 +43,7 @@
 #include <linux/pci.h>
 #include <linux/i2o.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -64,13 +65,14 @@ typedef struct _i2o_proc_entry_t
 	mode_t mode;			/* mode */
 	read_proc_t *read_proc;		/* read func */
 	write_proc_t *write_proc;	/* write func */
+	struct file_operations *fops_proc;	/* file operations func */
 } i2o_proc_entry;
 
 // #define DRIVERDEBUG
 
-static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *);
+static int i2o_seq_show_lct(struct seq_file *, void *);
+static int i2o_seq_show_hrt(struct seq_file *, void *);
+static int i2o_seq_show_status(struct seq_file *, void *);
 
 static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *);
@@ -151,20 +153,56 @@ static struct i2o_handler i2o_proc_handl
 	0xffffffff	// All classes
 };
 
+static int i2o_seq_open_hrt(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_hrt, PDE(inode)->data);
+};
+
+struct file_operations i2o_seq_fops_hrt = {
+	.open	= i2o_seq_open_hrt,
+	.read	= seq_read,
+	.llseek	= seq_lseek,
+	.release = single_release
+};
+
+static int i2o_seq_open_lct(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_lct, PDE(inode)->data);
+};
+
+struct file_operations i2o_seq_fops_lct = {
+	.open	= i2o_seq_open_lct,
+	.read	= seq_read,
+	.llseek	= seq_lseek,
+	.release = single_release
+};
+
+static int i2o_seq_open_status(struct inode *inode, struct file *file)
+{
+	return single_open(file, i2o_seq_show_status, PDE(inode)->data);
+};
+
+struct file_operations i2o_seq_fops_status = {
+	.open	= i2o_seq_open_status,
+	.read	= seq_read,
+	.llseek	= seq_lseek,
+	.release = single_release
+};
+
 /*
  * IOP specific entries...write field just in case someone 
  * ever wants one.
  */
 static i2o_proc_entry generic_iop_entries[] = 
 {
-	{"hrt", S_IFREG|S_IRUGO, i2o_proc_read_hrt, NULL},
-	{"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL},
-	{"status", S_IFREG|S_IRUGO, i2o_proc_read_status, NULL},
-	{"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL},
-	{"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL},
-	{"driver_store", S_IFREG|S_IRUGO, i2o_proc_read_driver_store, NULL},
-	{"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL},
-	{NULL, 0, NULL, NULL}
+	{"hrt", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_hrt},
+	{"lct", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_lct},
+	{"status", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_status},
+	{"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL, NULL},
+	{"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL, NULL},
+	{"driver_store", S_IFREG|S_IRUGO, i2o_proc_read_driver_store, NULL, NULL},
+	{"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL, NULL},
+	{NULL, 0, NULL, NULL, NULL}
 };
 
 /*
@@ -172,18 +210,18 @@ static i2o_proc_entry generic_iop_entrie
  */
 static i2o_proc_entry generic_dev_entries[] = 
 {
-	{"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL},
-	{"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL},
-	{"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL},
-	{"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL},
-	{"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL},
-	{"authorized_users", S_IFREG|S_IRUGO, i2o_proc_read_authorized_users, NULL},
-	{"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev_identity, NULL},
-	{"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL},
-	{"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL},
-	{"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL},
-	{"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL},
-	{NULL, 0, NULL, NULL}
+	{"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL, NULL},
+	{"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL, NULL},
+	{"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL, NULL},
+	{"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL, NULL},
+	{"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL, NULL},
+	{"authorized_users", S_IFREG|S_IRUGO, i2o_proc_read_authorized_users, NULL, NULL},
+	{"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev_identity, NULL, NULL},
+	{"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL, NULL},
+	{"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL, NULL},
+	{"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL, NULL},
+	{"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL, NULL},
+	{NULL, 0, NULL, NULL, NULL}
 };
 
 /*
@@ -191,7 +229,7 @@ static i2o_proc_entry generic_dev_entrie
  */
 static i2o_proc_entry rbs_dev_entries[] = 
 {
-	{"dev_name", S_IFREG|S_IRUGO, i2o_proc_read_dev_name, NULL},
+	{"dev_name", S_IFREG|S_IRUGO, i2o_proc_read_dev_name, NULL, NULL},
 	{NULL, 0, NULL, NULL}
 };
 
@@ -223,21 +261,21 @@ static char *scsi_devices[] = 
  */
 static i2o_proc_entry lan_entries[] = 
 {
-	{"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL},
-	{"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL},
+	{"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL, NULL},
+	{"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL, NULL},
 	{"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR,
-	 i2o_proc_read_lan_mcast_addr, NULL},
+	 i2o_proc_read_lan_mcast_addr, NULL, NULL},
 	{"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR,
-	 i2o_proc_read_lan_batch_control, NULL},
-	{"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL},
+	 i2o_proc_read_lan_batch_control, NULL, NULL},
+	{"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL, NULL},
 	{"lan_media_operation", S_IFREG|S_IRUGO,
-	 i2o_proc_read_lan_media_operation, NULL},
-	{"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL},
-	{"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL},
-	{"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL},
+	 i2o_proc_read_lan_media_operation, NULL, NULL},
+	{"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL, NULL},
+	{"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL, NULL},
+	{"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL, NULL},
 
-	{"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL},
-	{NULL, 0, NULL, NULL}
+	{"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL, NULL},
+	{NULL, 0, NULL, NULL, NULL}
 };
 
 /*
@@ -246,20 +284,20 @@ static i2o_proc_entry lan_entries[] = 
  */
 static i2o_proc_entry lan_eth_entries[] = 
 {
-	{"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL},
-	{NULL, 0, NULL, NULL}
+	{"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL, NULL},
+	{NULL, 0, NULL, NULL, NULL}
 };
 
 static i2o_proc_entry lan_tr_entries[] = 
 {
-	{"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL},
-	{NULL, 0, NULL, NULL}
+	{"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL, NULL},
+	{NULL, 0, NULL, NULL, NULL}
 };
 
 static i2o_proc_entry lan_fddi_entries[] = 
 {
-	{"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL},
-	{NULL, 0, NULL, NULL}
+	{"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL, NULL},
+	{NULL, 0, NULL, NULL, NULL}
 };
 
 
@@ -300,116 +338,98 @@ static char* bus_strings[] = 
 
 static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
 
-int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int count, 
-		      int *eof, void *data)
+int i2o_seq_show_hrt(struct seq_file *seq, void *v)
 {
-	struct i2o_controller *c = (struct i2o_controller *)data;
+	struct i2o_controller *c = (struct i2o_controller *)seq->private;
 	i2o_hrt *hrt = (i2o_hrt *)c->hrt;
 	u32 bus;
-	int len, i;
-
-	spin_lock(&i2o_proc_lock);
-
-	len = 0;
+	int i;
 
 	if(hrt->hrt_version)
 	{
-		len += sprintf(buf+len, 
-			       "HRT table for controller is too new a version.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
+		seq_printf(seq, "HRT table for controller is too new a version.\n");
+		return 0;
 	}
 
-	if((hrt->num_entries * hrt->entry_len + 8) > 2048) {
-		printk(KERN_WARNING "i2o_proc: HRT does not fit into buffer\n");
-		len += sprintf(buf+len,
-			       "HRT table too big to fit in buffer.\n");
-		spin_unlock(&i2o_proc_lock);
-		return len;
-	}
-	
-	len += sprintf(buf+len, "HRT has %d entries of %d bytes each.\n",
+	seq_printf(seq, "HRT has %d entries of %d bytes each.\n",
 		       hrt->num_entries, hrt->entry_len << 2);
 
-	for(i = 0; i < hrt->num_entries && len < count; i++)
+	for(i = 0; i < hrt->num_entries; i++)
 	{
-		len += sprintf(buf+len, "Entry %d:\n", i);
-		len += sprintf(buf+len, "   Adapter ID: %0#10x\n", 
+		seq_printf(seq, "Entry %d:\n", i);
+		seq_printf(seq, "   Adapter ID: %0#10x\n",
 					hrt->hrt_entry[i].adapter_id);
-		len += sprintf(buf+len, "   Controlling tid: %0#6x\n",
+		seq_printf(seq, "   Controlling tid: %0#6x\n",
 					hrt->hrt_entry[i].parent_tid);
 
 		if(hrt->hrt_entry[i].bus_type != 0x80)
 		{
 			bus = hrt->hrt_entry[i].bus_type;
-			len += sprintf(buf+len, "   %s Information\n", bus_strings[bus]);
+			seq_printf(seq, "   %s Information\n", bus_strings[bus]);
 
 			switch(bus)
 			{
 				case I2O_BUS_LOCAL:
-					len += sprintf(buf+len, "     IOBase: %0#6x,",
+					seq_printf(seq, "     IOBase: %0#6x,",
 								hrt->hrt_entry[i].bus.local_bus.LbBaseIOPort);
-					len += sprintf(buf+len, " MemoryBase: %0#10x\n",
+					seq_printf(seq, " MemoryBase: %0#10x\n",
 								hrt->hrt_entry[i].bus.local_bus.LbBaseMemoryAddress);
 					break;
 
 				case I2O_BUS_ISA:
-					len += sprintf(buf+len, "     IOBase: %0#6x,",
+					seq_printf(seq, "     IOBase: %0#6x,",
 								hrt->hrt_entry[i].bus.isa_bus.IsaBaseIOPort);
-					len += sprintf(buf+len, " MemoryBase: %0#10x,",
+					seq_printf(seq, " MemoryBase: %0#10x,",
 								hrt->hrt_entry[i].bus.isa_bus.IsaBaseMemoryAddress);
-					len += sprintf(buf+len, " CSN: %0#4x,",
+					seq_printf(seq, " CSN: %0#4x,",
 								hrt->hrt_entry[i].bus.isa_bus.CSN);
 					break;
 
 				case I2O_BUS_EISA:
-					len += sprintf(buf+len, "     IOBase: %0#6x,",
+					seq_printf(seq, "     IOBase: %0#6x,",
 								hrt->hrt_entry[i].bus.eisa_bus.EisaBaseIOPort);
-					len += sprintf(buf+len, " MemoryBase: %0#10x,",
+					seq_printf(seq, " MemoryBase: %0#10x,",
 								hrt->hrt_entry[i].bus.eisa_bus.EisaBaseMemoryAddress);
-					len += sprintf(buf+len, " Slot: %0#4x,",
+					seq_printf(seq, " Slot: %0#4x,",
 								hrt->hrt_entry[i].bus.eisa_bus.EisaSlotNumber);
 					break;
 			 
 				case I2O_BUS_MCA:
-					len += sprintf(buf+len, "     IOBase: %0#6x,",
+					seq_printf(seq, "     IOBase: %0#6x,",
 								hrt->hrt_entry[i].bus.mca_bus.McaBaseIOPort);
-					len += sprintf(buf+len, " MemoryBase: %0#10x,",
+					seq_printf(seq, " MemoryBase: %0#10x,",
 								hrt->hrt_entry[i].bus.mca_bus.McaBaseMemoryAddress);
-					len += sprintf(buf+len, " Slot: %0#4x,",
+					seq_printf(seq, " Slot: %0#4x,",
 								hrt->hrt_entry[i].bus.mca_bus.McaSlotNumber);
 					break;
 
 				case I2O_BUS_PCI:
-					len += sprintf(buf+len, "     Bus: %0#4x",
+					seq_printf(seq, "     Bus: %0#4x",
 								hrt->hrt_entry[i].bus.pci_bus.PciBusNumber);
-					len += sprintf(buf+len, " Dev: %0#4x",
+					seq_printf(seq, " Dev: %0#4x",
 								hrt->hrt_entry[i].bus.pci_bus.PciDeviceNumber);
-					len += sprintf(buf+len, " Func: %0#4x",
+					seq_printf(seq, " Func: %0#4x",
 								hrt->hrt_entry[i].bus.pci_bus.PciFunctionNumber);
-					len += sprintf(buf+len, " Vendor: %0#6x",
+					seq_printf(seq, " Vendor: %0#6x",
 								hrt->hrt_entry[i].bus.pci_bus.PciVendorID);
-					len += sprintf(buf+len, " Device: %0#6x\n",
+					seq_printf(seq, " Device: %0#6x\n",
 								hrt->hrt_entry[i].bus.pci_bus.PciDeviceID);
 					break;
 
 				default:
-					len += sprintf(buf+len, "      Unsupported Bus Type\n");
+					seq_printf(seq, "      Unsupported Bus Type\n");
 			}
 		}
 		else
-			len += sprintf(buf+len, "   Unknown Bus Type\n");
+			seq_printf(seq, "   Unknown Bus Type\n");
 	}
-
-	spin_unlock(&i2o_proc_lock);
 	
-	return len;
+	return 0;
 }
 
-int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
-	int *eof, void *data)
+int i2o_seq_show_lct(struct seq_file *seq, void *v)
 {
-	struct i2o_controller *c = (struct i2o_controller*)data;
+	struct i2o_controller *c = (struct i2o_controller*)seq->private;
 	i2o_lct *lct = (i2o_lct *)c->lct;
 	int entries;
 	int i;
@@ -422,23 +442,19 @@ int i2o_proc_read_lct(char *buf, char **
 		"Fibre Channel Bus"
 	};
 
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
 	entries = (lct->table_size - 3)/9;
 
-	len += sprintf(buf, "LCT contains %d %s\n", entries,
+	seq_printf(seq, "LCT contains %d %s\n", entries,
 						entries == 1 ? "entry" : "entries");
 	if(lct->boot_tid)	
-		len += sprintf(buf+len, "Boot Device @ ID %d\n", lct->boot_tid);
+		seq_printf(seq, "Boot Device @ ID %d\n", lct->boot_tid);
 
-	len += 
-		sprintf(buf+len, "Current Change Indicator: %#10x\n", lct->change_ind);
+	seq_printf(seq, "Current Change Indicator: %#10x\n", lct->change_ind);
 
 	for(i = 0; i < entries; i++)
 	{
-		len += sprintf(buf+len, "Entry %d\n", i);
-		len += sprintf(buf+len, "  Class, SubClass  : %s", i2o_get_class_name(lct->lct_entry[i].class_id));
+		seq_printf(seq, "Entry %d\n", i);
+		seq_printf(seq, "  Class, SubClass  : %s", i2o_get_class_name(lct->lct_entry[i].class_id));
 	
 		/*
 		 *	Classes which we'll print subclass info for
@@ -449,23 +465,23 @@ int i2o_proc_read_lct(char *buf, char **
 				switch(lct->lct_entry[i].sub_class)
 				{
 					case 0x00:
-						len += sprintf(buf+len, ", Direct-Access Read/Write");
+						seq_printf(seq, ", Direct-Access Read/Write");
 						break;
 
 					case 0x04:
-						len += sprintf(buf+len, ", WORM Drive");
+						seq_printf(seq, ", WORM Drive");
 						break;
 	
 					case 0x05:
-						len += sprintf(buf+len, ", CD-ROM Drive");
+						seq_printf(seq, ", CD-ROM Drive");
 						break;
 
 					case 0x07:
-						len += sprintf(buf+len, ", Optical Memory Device");
+						seq_printf(seq, ", Optical Memory Device");
 						break;
 
 					default:
-						len += sprintf(buf+len, ", Unknown (0x%02x)",
+						seq_printf(seq, ", Unknown (0x%02x)",
 							       lct->lct_entry[i].sub_class);
 						break;
 				}
@@ -475,27 +491,27 @@ int i2o_proc_read_lct(char *buf, char **
 				switch(lct->lct_entry[i].sub_class & 0xFF)
 				{
 					case 0x30:
-						len += sprintf(buf+len, ", Ethernet");
+						seq_printf(seq, ", Ethernet");
 						break;
 
 					case 0x40:
-						len += sprintf(buf+len, ", 100base VG");
+						seq_printf(seq, ", 100base VG");
 						break;
 
 					case 0x50:
-						len += sprintf(buf+len, ", IEEE 802.5/Token-Ring");
+						seq_printf(seq, ", IEEE 802.5/Token-Ring");
 						break;
 
 					case 0x60:
-						len += sprintf(buf+len, ", ANSI X3T9.5 FDDI");
+						seq_printf(seq, ", ANSI X3T9.5 FDDI");
 						break;
 		
 					case 0x70:
-						len += sprintf(buf+len, ", Fibre Channel");
+						seq_printf(seq, ", Fibre Channel");
 						break;
 
 					default:
-						len += sprintf(buf+len, ", Unknown Sub-Class (0x%02x)",
+						seq_printf(seq, ", Unknown Sub-Class (0x%02x)",
 							       lct->lct_entry[i].sub_class & 0xFF);
 						break;
 				}
@@ -503,27 +519,27 @@ int i2o_proc_read_lct(char *buf, char **
 
 			case I2O_CLASS_SCSI_PERIPHERAL:
 				if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE)
-					len += sprintf(buf+len, ", %s", 
+					seq_printf(seq, ", %s",
 								scsi_devices[lct->lct_entry[i].sub_class]);
 				else
-					len += sprintf(buf+len, ", Unknown Device Type");
+					seq_printf(seq, ", Unknown Device Type");
 				break;
 
 			case I2O_CLASS_BUS_ADAPTER_PORT:
 				if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
-					len += sprintf(buf+len, ", %s", 
+					seq_printf(seq, ", %s",
 								bus_ports[lct->lct_entry[i].sub_class]);
 				else
-					len += sprintf(buf+len, ", Unknown Bus Type");
+					seq_printf(seq, ", Unknown Bus Type");
 				break;
 		}
-		len += sprintf(buf+len, "\n");
+		seq_printf(seq, "\n");
 		
-		len += sprintf(buf+len, "  Local TID        : 0x%03x\n", lct->lct_entry[i].tid);
-		len += sprintf(buf+len, "  User TID         : 0x%03x\n", lct->lct_entry[i].user_tid);
-		len += sprintf(buf+len, "  Parent TID       : 0x%03x\n", 
+		seq_printf(seq, "  Local TID        : 0x%03x\n", lct->lct_entry[i].tid);
+		seq_printf(seq, "  User TID         : 0x%03x\n", lct->lct_entry[i].user_tid);
+		seq_printf(seq, "  Parent TID       : 0x%03x\n",
 					lct->lct_entry[i].parent_tid);
-		len += sprintf(buf+len, "  Identity Tag     : 0x%x%x%x%x%x%x%x%x\n",
+		seq_printf(seq, "  Identity Tag     : 0x%x%x%x%x%x%x%x%x\n",
 					lct->lct_entry[i].identity_tag[0],
 					lct->lct_entry[i].identity_tag[1],
 					lct->lct_entry[i].identity_tag[2],
@@ -532,214 +548,207 @@ int i2o_proc_read_lct(char *buf, char **
 					lct->lct_entry[i].identity_tag[5],
 					lct->lct_entry[i].identity_tag[6],
 					lct->lct_entry[i].identity_tag[7]);
-		len += sprintf(buf+len, "  Change Indicator : %0#10x\n", 
+		seq_printf(seq, "  Change Indicator : %0#10x\n",
 				lct->lct_entry[i].change_ind);
-		len += sprintf(buf+len, "  Event Capab Mask : %0#10x\n", 
+		seq_printf(seq, "  Event Capab Mask : %0#10x\n",
 				lct->lct_entry[i].device_flags);
 	}
 
-	spin_unlock(&i2o_proc_lock);
-	return len;
+	return 0;
 }
 
-int i2o_proc_read_status(char *buf, char **start, off_t offset, int len, 
-			 int *eof, void *data)
+int i2o_seq_show_status(struct seq_file *seq, void *v)
 {
-	struct i2o_controller *c = (struct i2o_controller*)data;
+	struct i2o_controller *c = (struct i2o_controller*)seq->private;
 	char prodstr[25];
 	int version;
 	
-	spin_lock(&i2o_proc_lock);
-	len = 0;
-
 	i2o_status_get(c); // reread the status block
 
-	len += sprintf(buf+len,"Organization ID        : %0#6x\n", 
+	seq_printf(seq, "Organization ID        : %0#6x\n",
 				c->status_block->org_id);
 
 	version = c->status_block->i2o_version;
 	
 /* FIXME for Spec 2.0
 	if (version == 0x02) {
-		len += sprintf(buf+len,"Lowest I2O version supported: ");
+		seq_printf(seq, "Lowest I2O version supported: ");
 		switch(workspace[2]) {
 			case 0x00:
-				len += sprintf(buf+len,"1.0\n");
+				seq_printf(seq, "1.0\n");
 				break;
 			case 0x01:
-				len += sprintf(buf+len,"1.5\n");
+				seq_printf(seq, "1.5\n");
 				break;
 			case 0x02:
-				len += sprintf(buf+len,"2.0\n");
+				seq_printf(seq, "2.0\n");
 				break;
 		}
 
-		len += sprintf(buf+len, "Highest I2O version supported: ");
+		seq_printf(seq, "Highest I2O version supported: ");
 		switch(workspace[3]) {
 			case 0x00:
-				len += sprintf(buf+len,"1.0\n");
+				seq_printf(seq, "1.0\n");
 				break;
 			case 0x01:
-				len += sprintf(buf+len,"1.5\n");
+				seq_printf(seq, "1.5\n");
 				break;
 			case 0x02:
-				len += sprintf(buf+len,"2.0\n");
+				seq_printf(seq, "2.0\n");
 				break;
 		}
 	}
 */
-	len += sprintf(buf+len,"IOP ID                 : %0#5x\n", 
+	seq_printf(seq, "IOP ID                 : %0#5x\n",
 				c->status_block->iop_id);
-	len += sprintf(buf+len,"Host Unit ID           : %0#6x\n",
+	seq_printf(seq, "Host Unit ID           : %0#6x\n",
 				c->status_block->host_unit_id);
-	len += sprintf(buf+len,"Segment Number         : %0#5x\n",
+	seq_printf(seq, "Segment Number         : %0#5x\n",
 				c->status_block->segment_number);
 
-	len += sprintf(buf+len, "I2O version            : ");
+	seq_printf(seq, "I2O version            : ");
 	switch (version) {
 		case 0x00:
-			len += sprintf(buf+len,"1.0\n");
+			seq_printf(seq, "1.0\n");
 			break;
 		case 0x01:
-			len += sprintf(buf+len,"1.5\n");
+			seq_printf(seq, "1.5\n");
 			break;
 		case 0x02:
-			len += sprintf(buf+len,"2.0\n");
+			seq_printf(seq, "2.0\n");
 			break;
 		default:
-			len += sprintf(buf+len,"Unknown version\n");
+			seq_printf(seq, "Unknown version\n");
 	}
 
-	len += sprintf(buf+len, "IOP State              : ");
+	seq_printf(seq, "IOP State              : ");
 	switch (c->status_block->iop_state) {
 		case 0x01:
-			len += sprintf(buf+len,"INIT\n");
+			seq_printf(seq, "INIT\n");
 			break;
 
 		case 0x02:
-			len += sprintf(buf+len,"RESET\n");
+			seq_printf(seq, "RESET\n");
 			break;
 
 		case 0x04:
-			len += sprintf(buf+len,"HOLD\n");
+			seq_printf(seq, "HOLD\n");
 			break;
 
 		case 0x05:
-			len += sprintf(buf+len,"READY\n");
+			seq_printf(seq, "READY\n");
 			break;
 
 		case 0x08:
-			len += sprintf(buf+len,"OPERATIONAL\n");
+			seq_printf(seq, "OPERATIONAL\n");
 			break;
 
 		case 0x10:
-			len += sprintf(buf+len,"FAILED\n");
+			seq_printf(seq, "FAILED\n");
 			break;
 
 		case 0x11:
-			len += sprintf(buf+len,"FAULTED\n");
+			seq_printf(seq, "FAULTED\n");
 			break;
 
 		default:
-			len += sprintf(buf+len,"Unknown\n");
+			seq_printf(seq, "Unknown\n");
 			break;
 	}
 
-	len += sprintf(buf+len,"Messenger Type         : ");
+	seq_printf(seq, "Messenger Type         : ");
 	switch (c->status_block->msg_type) { 
 		case 0x00:
-			len += sprintf(buf+len,"Memory mapped\n");
+			seq_printf(seq, "Memory mapped\n");
 			break;
 		case 0x01:
-			len += sprintf(buf+len,"Memory mapped only\n");
+			seq_printf(seq, "Memory mapped only\n");
 			break;
 		case 0x02:
-			len += sprintf(buf+len,"Remote only\n");
+			seq_printf(seq,"Remote only\n");
 			break;
 		case 0x03:
-			len += sprintf(buf+len,"Memory mapped and remote\n");
+			seq_printf(seq, "Memory mapped and remote\n");
 			break;
 		default:
-			len += sprintf(buf+len,"Unknown\n");
+			seq_printf(seq, "Unknown\n");
 	}
 
-	len += sprintf(buf+len,"Inbound Frame Size     : %d bytes\n", 
+	seq_printf(seq, "Inbound Frame Size     : %d bytes\n",
 				c->status_block->inbound_frame_size<<2);
-	len += sprintf(buf+len,"Max Inbound Frames     : %d\n", 
+	seq_printf(seq, "Max Inbound Frames     : %d\n",
 				c->status_block->max_inbound_frames);
-	len += sprintf(buf+len,"Current Inbound Frames : %d\n", 
+	seq_printf(seq, "Current Inbound Frames : %d\n",
 				c->status_block->cur_inbound_frames);
-	len += sprintf(buf+len,"Max Outbound Frames    : %d\n", 
+	seq_printf(seq, "Max Outbound Frames    : %d\n",
 				c->status_block->max_outbound_frames);
 
 	/* Spec doesn't say if NULL terminated or not... */
 	memcpy(prodstr, c->status_block->product_id, 24);
 	prodstr[24] = '\0';
-	len += sprintf(buf+len,"Product ID             : %s\n", prodstr);
-	len += sprintf(buf+len,"Expected LCT Size      : %d bytes\n", 
+	seq_printf(seq, "Product ID             : %s\n", prodstr);
+	seq_printf(seq, "Expected LCT Size      : %d bytes\n",
 				c->status_block->expected_lct_size);
 
-	len += sprintf(buf+len,"IOP Capabilities\n");
-	len += sprintf(buf+len,"    Context Field Size Support : ");
+	seq_printf(seq, "IOP Capabilities\n");
+	seq_printf(seq, "    Context Field Size Support : ");
 	switch (c->status_block->iop_capabilities & 0x0000003) {
 		case 0:
-			len += sprintf(buf+len,"Supports only 32-bit context fields\n");
+			seq_printf(seq, "Supports only 32-bit context fields\n");
 			break;
 		case 1:
-			len += sprintf(buf+len,"Supports only 64-bit context fields\n");
+			seq_printf(seq, "Supports only 64-bit context fields\n");
 			break;
 		case 2:
-			len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields, "
+			seq_printf(seq, "Supports 32-bit and 64-bit context fields, "
 						"but not concurrently\n");
 			break;
 		case 3:
-			len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields "
+			seq_printf(seq, "Supports 32-bit and 64-bit context fields "
 						"concurrently\n");
 			break;
 		default:
-			len += sprintf(buf+len,"0x%08x\n",c->status_block->iop_capabilities);
+			seq_printf(seq, "0x%08x\n",c->status_block->iop_capabilities);
 	}
-	len += sprintf(buf+len,"    Current Context Field Size : ");
+	seq_printf(seq, "    Current Context Field Size : ");
 	switch (c->status_block->iop_capabilities & 0x0000000C) {
 		case 0:
-			len += sprintf(buf+len,"not configured\n");
+			seq_printf(seq, "not configured\n");
 			break;
 		case 4:
-			len += sprintf(buf+len,"Supports only 32-bit context fields\n");
+			seq_printf(seq, "Supports only 32-bit context fields\n");
 			break;
 		case 8:
-			len += sprintf(buf+len,"Supports only 64-bit context fields\n");
+			seq_printf(seq, "Supports only 64-bit context fields\n");
 			break;
 		case 12:
-			len += sprintf(buf+len,"Supports both 32-bit or 64-bit context fields "
+			seq_printf(seq, "Supports both 32-bit or 64-bit context fields "
 						"concurrently\n");
 			break;
 		default:
-			len += sprintf(buf+len,"\n");
+			seq_printf(seq, "\n");
 	}
-	len += sprintf(buf+len,"    Inbound Peer Support       : %s\n",
+	seq_printf(seq, "    Inbound Peer Support       : %s\n",
 			(c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported");
-	len += sprintf(buf+len,"    Outbound Peer Support      : %s\n",
+	seq_printf(seq, "    Outbound Peer Support      : %s\n",
 			(c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported");
-	len += sprintf(buf+len,"    Peer to Peer Support       : %s\n",
+	seq_printf(seq, "    Peer to Peer Support       : %s\n",
 			(c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported");
 
-	len += sprintf(buf+len, "Desired private memory size   : %d kB\n", 
+	seq_printf(seq, "Desired private memory size   : %d kB\n",
 				c->status_block->desired_mem_size>>10);
-	len += sprintf(buf+len, "Allocated private memory size : %d kB\n", 
+	seq_printf(seq, "Allocated private memory size : %d kB\n",
 				c->status_block->current_mem_size>>10);
-	len += sprintf(buf+len, "Private memory base address   : %0#10x\n", 
+	seq_printf(seq, "Private memory base address   : %0#10x\n",
 				c->status_block->current_mem_base);
-	len += sprintf(buf+len, "Desired private I/O size      : %d kB\n", 
+	seq_printf(seq, "Desired private I/O size      : %d kB\n",
 				c->status_block->desired_io_size>>10);
-	len += sprintf(buf+len, "Allocated private I/O size    : %d kB\n", 
+	seq_printf(seq, "Allocated private I/O size    : %d kB\n",
 				c->status_block->current_io_size>>10);
-	len += sprintf(buf+len, "Private I/O base address      : %0#10x\n", 
+	seq_printf(seq, "Private I/O base address      : %0#10x\n",
 				c->status_block->current_io_base);
 
-	spin_unlock(&i2o_proc_lock);
-
-	return len;
+	return 0;
 }
 
 int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, 
@@ -3146,6 +3155,9 @@ static int i2o_proc_create_entries(void 
 		ent->data = data;
 		ent->read_proc = pentry->read_proc;
 		ent->write_proc = pentry->write_proc;
+		if(pentry->fops_proc)
+			ent->proc_fops = pentry->fops_proc;
+
 		ent->nlink = 1;
 
 		pentry++;
@@ -3266,7 +3278,6 @@ static void i2o_proc_remove_controller(s
 		sprintf(buff, "iop%d", pctrl->unit);
 
 		i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
-
 		remove_proc_entry(buff, parent);
 		pctrl->proc_entry = NULL;
 	}
@@ -3306,8 +3317,8 @@ void i2o_proc_remove_device(struct i2o_d
 					break;
 				}
 			}
-			remove_proc_entry(dev_id, dev->controller->proc_entry);
 		}
+		remove_proc_entry(dev_id, dev->controller->proc_entry);
 	}
 }
 	

_