Commit 5bb8577f authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Fix i2o_proc kernel panic on access of /proc/i2o/iop0/lct

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.
parent c36b18ac
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/i2o.h> #include <linux/i2o.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -64,13 +65,14 @@ typedef struct _i2o_proc_entry_t ...@@ -64,13 +65,14 @@ typedef struct _i2o_proc_entry_t
mode_t mode; /* mode */ mode_t mode; /* mode */
read_proc_t *read_proc; /* read func */ read_proc_t *read_proc; /* read func */
write_proc_t *write_proc; /* write func */ write_proc_t *write_proc; /* write func */
struct file_operations *fops_proc; /* file operations func */
} i2o_proc_entry; } i2o_proc_entry;
// #define DRIVERDEBUG // #define DRIVERDEBUG
static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *); static int i2o_seq_show_lct(struct seq_file *, void *);
static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *); static int i2o_seq_show_hrt(struct seq_file *, void *);
static int i2o_proc_read_status(char *, char **, off_t, int, int *, 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_hw(char *, char **, off_t, int, int *, void *);
static int i2o_proc_read_ddm_table(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_handler = ...@@ -151,20 +153,56 @@ static struct i2o_handler i2o_proc_handler =
0xffffffff // All classes 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 * IOP specific entries...write field just in case someone
* ever wants one. * ever wants one.
*/ */
static i2o_proc_entry generic_iop_entries[] = static i2o_proc_entry generic_iop_entries[] =
{ {
{"hrt", S_IFREG|S_IRUGO, i2o_proc_read_hrt, NULL}, {"hrt", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_hrt},
{"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL}, {"lct", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_lct},
{"status", S_IFREG|S_IRUGO, i2o_proc_read_status, NULL}, {"status", S_IFREG|S_IRUGO, NULL, NULL, &i2o_seq_fops_status},
{"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL}, {"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL, NULL},
{"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, 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}, {"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}, {"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL, NULL},
{NULL, 0, NULL, NULL} {NULL, 0, NULL, NULL, NULL}
}; };
/* /*
...@@ -172,18 +210,18 @@ static i2o_proc_entry generic_iop_entries[] = ...@@ -172,18 +210,18 @@ static i2o_proc_entry generic_iop_entries[] =
*/ */
static i2o_proc_entry generic_dev_entries[] = static i2o_proc_entry generic_dev_entries[] =
{ {
{"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL}, {"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL, NULL},
{"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL}, {"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL, NULL},
{"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL}, {"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL, NULL},
{"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL}, {"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL, NULL},
{"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, 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}, {"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}, {"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}, {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL, NULL},
{"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, 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}, {"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL, NULL},
{"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL}, {"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL, NULL},
{NULL, 0, NULL, NULL} {NULL, 0, NULL, NULL, NULL}
}; };
/* /*
...@@ -191,7 +229,7 @@ static i2o_proc_entry generic_dev_entries[] = ...@@ -191,7 +229,7 @@ static i2o_proc_entry generic_dev_entries[] =
*/ */
static i2o_proc_entry rbs_dev_entries[] = 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} {NULL, 0, NULL, NULL}
}; };
...@@ -223,21 +261,21 @@ static char *scsi_devices[] = ...@@ -223,21 +261,21 @@ static char *scsi_devices[] =
*/ */
static i2o_proc_entry lan_entries[] = static i2o_proc_entry lan_entries[] =
{ {
{"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, 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}, {"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL, NULL},
{"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR, {"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, {"lan_batch_ctrl", S_IFREG|S_IRUGO|S_IWUSR,
i2o_proc_read_lan_batch_control, NULL}, i2o_proc_read_lan_batch_control, NULL, NULL},
{"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL}, {"lan_operation", S_IFREG|S_IRUGO, i2o_proc_read_lan_operation, NULL, NULL},
{"lan_media_operation", S_IFREG|S_IRUGO, {"lan_media_operation", S_IFREG|S_IRUGO,
i2o_proc_read_lan_media_operation, NULL}, i2o_proc_read_lan_media_operation, NULL, NULL},
{"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, 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}, {"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}, {"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}, {"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL, NULL},
{NULL, 0, NULL, NULL} {NULL, 0, NULL, NULL, NULL}
}; };
/* /*
...@@ -246,20 +284,20 @@ static i2o_proc_entry lan_entries[] = ...@@ -246,20 +284,20 @@ static i2o_proc_entry lan_entries[] =
*/ */
static i2o_proc_entry lan_eth_entries[] = static i2o_proc_entry lan_eth_entries[] =
{ {
{"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL}, {"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL, NULL},
{NULL, 0, NULL, NULL} {NULL, 0, NULL, NULL, NULL}
}; };
static i2o_proc_entry lan_tr_entries[] = static i2o_proc_entry lan_tr_entries[] =
{ {
{"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL}, {"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL, NULL},
{NULL, 0, NULL, NULL} {NULL, 0, NULL, NULL, NULL}
}; };
static i2o_proc_entry lan_fddi_entries[] = static i2o_proc_entry lan_fddi_entries[] =
{ {
{"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL}, {"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL, NULL},
{NULL, 0, NULL, NULL} {NULL, 0, NULL, NULL, NULL}
}; };
...@@ -300,116 +338,98 @@ static char* bus_strings[] = ...@@ -300,116 +338,98 @@ static char* bus_strings[] =
static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED; static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int count, int i2o_seq_show_hrt(struct seq_file *seq, void *v)
int *eof, void *data)
{ {
struct i2o_controller *c = (struct i2o_controller *)data; struct i2o_controller *c = (struct i2o_controller *)seq->private;
i2o_hrt *hrt = (i2o_hrt *)c->hrt; i2o_hrt *hrt = (i2o_hrt *)c->hrt;
u32 bus; u32 bus;
int len, i; int i;
spin_lock(&i2o_proc_lock);
len = 0;
if(hrt->hrt_version) if(hrt->hrt_version)
{ {
len += sprintf(buf+len, seq_printf(seq, "HRT table for controller is too new a version.\n");
"HRT table for controller is too new a version.\n"); return 0;
spin_unlock(&i2o_proc_lock);
return len;
} }
if((hrt->num_entries * hrt->entry_len + 8) > 2048) { seq_printf(seq, "HRT has %d entries of %d bytes each.\n",
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",
hrt->num_entries, hrt->entry_len << 2); 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); seq_printf(seq, "Entry %d:\n", i);
len += sprintf(buf+len, " Adapter ID: %0#10x\n", seq_printf(seq, " Adapter ID: %0#10x\n",
hrt->hrt_entry[i].adapter_id); 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); hrt->hrt_entry[i].parent_tid);
if(hrt->hrt_entry[i].bus_type != 0x80) if(hrt->hrt_entry[i].bus_type != 0x80)
{ {
bus = hrt->hrt_entry[i].bus_type; 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) switch(bus)
{ {
case I2O_BUS_LOCAL: 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); 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); hrt->hrt_entry[i].bus.local_bus.LbBaseMemoryAddress);
break; break;
case I2O_BUS_ISA: 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); 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); 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); hrt->hrt_entry[i].bus.isa_bus.CSN);
break; break;
case I2O_BUS_EISA: 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); 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); 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); hrt->hrt_entry[i].bus.eisa_bus.EisaSlotNumber);
break; break;
case I2O_BUS_MCA: 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); 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); 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); hrt->hrt_entry[i].bus.mca_bus.McaSlotNumber);
break; break;
case I2O_BUS_PCI: 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); 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); 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); 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); 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); hrt->hrt_entry[i].bus.pci_bus.PciDeviceID);
break; break;
default: default:
len += sprintf(buf+len, " Unsupported Bus Type\n"); seq_printf(seq, " Unsupported Bus Type\n");
} }
} }
else 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 i2o_seq_show_lct(struct seq_file *seq, void *v)
int *eof, void *data)
{ {
struct i2o_controller *c = (struct i2o_controller*)data; struct i2o_controller *c = (struct i2o_controller*)seq->private;
i2o_lct *lct = (i2o_lct *)c->lct; i2o_lct *lct = (i2o_lct *)c->lct;
int entries; int entries;
int i; int i;
...@@ -422,23 +442,19 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len, ...@@ -422,23 +442,19 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
"Fibre Channel Bus" "Fibre Channel Bus"
}; };
spin_lock(&i2o_proc_lock);
len = 0;
entries = (lct->table_size - 3)/9; 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"); entries == 1 ? "entry" : "entries");
if(lct->boot_tid) 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 += seq_printf(seq, "Current Change Indicator: %#10x\n", lct->change_ind);
sprintf(buf+len, "Current Change Indicator: %#10x\n", lct->change_ind);
for(i = 0; i < entries; i++) for(i = 0; i < entries; i++)
{ {
len += sprintf(buf+len, "Entry %d\n", i); seq_printf(seq, "Entry %d\n", i);
len += sprintf(buf+len, " Class, SubClass : %s", i2o_get_class_name(lct->lct_entry[i].class_id)); seq_printf(seq, " Class, SubClass : %s", i2o_get_class_name(lct->lct_entry[i].class_id));
/* /*
* Classes which we'll print subclass info for * Classes which we'll print subclass info for
...@@ -449,23 +465,23 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len, ...@@ -449,23 +465,23 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
switch(lct->lct_entry[i].sub_class) switch(lct->lct_entry[i].sub_class)
{ {
case 0x00: case 0x00:
len += sprintf(buf+len, ", Direct-Access Read/Write"); seq_printf(seq, ", Direct-Access Read/Write");
break; break;
case 0x04: case 0x04:
len += sprintf(buf+len, ", WORM Drive"); seq_printf(seq, ", WORM Drive");
break; break;
case 0x05: case 0x05:
len += sprintf(buf+len, ", CD-ROM Drive"); seq_printf(seq, ", CD-ROM Drive");
break; break;
case 0x07: case 0x07:
len += sprintf(buf+len, ", Optical Memory Device"); seq_printf(seq, ", Optical Memory Device");
break; break;
default: default:
len += sprintf(buf+len, ", Unknown (0x%02x)", seq_printf(seq, ", Unknown (0x%02x)",
lct->lct_entry[i].sub_class); lct->lct_entry[i].sub_class);
break; break;
} }
...@@ -475,27 +491,27 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len, ...@@ -475,27 +491,27 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
switch(lct->lct_entry[i].sub_class & 0xFF) switch(lct->lct_entry[i].sub_class & 0xFF)
{ {
case 0x30: case 0x30:
len += sprintf(buf+len, ", Ethernet"); seq_printf(seq, ", Ethernet");
break; break;
case 0x40: case 0x40:
len += sprintf(buf+len, ", 100base VG"); seq_printf(seq, ", 100base VG");
break; break;
case 0x50: case 0x50:
len += sprintf(buf+len, ", IEEE 802.5/Token-Ring"); seq_printf(seq, ", IEEE 802.5/Token-Ring");
break; break;
case 0x60: case 0x60:
len += sprintf(buf+len, ", ANSI X3T9.5 FDDI"); seq_printf(seq, ", ANSI X3T9.5 FDDI");
break; break;
case 0x70: case 0x70:
len += sprintf(buf+len, ", Fibre Channel"); seq_printf(seq, ", Fibre Channel");
break; break;
default: 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); lct->lct_entry[i].sub_class & 0xFF);
break; break;
} }
...@@ -503,27 +519,27 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len, ...@@ -503,27 +519,27 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
case I2O_CLASS_SCSI_PERIPHERAL: case I2O_CLASS_SCSI_PERIPHERAL:
if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE) 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]); scsi_devices[lct->lct_entry[i].sub_class]);
else else
len += sprintf(buf+len, ", Unknown Device Type"); seq_printf(seq, ", Unknown Device Type");
break; break;
case I2O_CLASS_BUS_ADAPTER_PORT: case I2O_CLASS_BUS_ADAPTER_PORT:
if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE) 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]); bus_ports[lct->lct_entry[i].sub_class]);
else else
len += sprintf(buf+len, ", Unknown Bus Type"); seq_printf(seq, ", Unknown Bus Type");
break; break;
} }
len += sprintf(buf+len, "\n"); seq_printf(seq, "\n");
len += sprintf(buf+len, " Local TID : 0x%03x\n", lct->lct_entry[i].tid); seq_printf(seq, " 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); seq_printf(seq, " User TID : 0x%03x\n", lct->lct_entry[i].user_tid);
len += sprintf(buf+len, " Parent TID : 0x%03x\n", seq_printf(seq, " Parent TID : 0x%03x\n",
lct->lct_entry[i].parent_tid); 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[0],
lct->lct_entry[i].identity_tag[1], lct->lct_entry[i].identity_tag[1],
lct->lct_entry[i].identity_tag[2], lct->lct_entry[i].identity_tag[2],
...@@ -532,214 +548,207 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len, ...@@ -532,214 +548,207 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
lct->lct_entry[i].identity_tag[5], lct->lct_entry[i].identity_tag[5],
lct->lct_entry[i].identity_tag[6], lct->lct_entry[i].identity_tag[6],
lct->lct_entry[i].identity_tag[7]); 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); 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); lct->lct_entry[i].device_flags);
} }
spin_unlock(&i2o_proc_lock); return 0;
return len;
} }
int i2o_proc_read_status(char *buf, char **start, off_t offset, int len, int i2o_seq_show_status(struct seq_file *seq, void *v)
int *eof, void *data)
{ {
struct i2o_controller *c = (struct i2o_controller*)data; struct i2o_controller *c = (struct i2o_controller*)seq->private;
char prodstr[25]; char prodstr[25];
int version; int version;
spin_lock(&i2o_proc_lock);
len = 0;
i2o_status_get(c); // reread the status block 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); c->status_block->org_id);
version = c->status_block->i2o_version; version = c->status_block->i2o_version;
/* FIXME for Spec 2.0 /* FIXME for Spec 2.0
if (version == 0x02) { if (version == 0x02) {
len += sprintf(buf+len,"Lowest I2O version supported: "); seq_printf(seq, "Lowest I2O version supported: ");
switch(workspace[2]) { switch(workspace[2]) {
case 0x00: case 0x00:
len += sprintf(buf+len,"1.0\n"); seq_printf(seq, "1.0\n");
break; break;
case 0x01: case 0x01:
len += sprintf(buf+len,"1.5\n"); seq_printf(seq, "1.5\n");
break; break;
case 0x02: case 0x02:
len += sprintf(buf+len,"2.0\n"); seq_printf(seq, "2.0\n");
break; break;
} }
len += sprintf(buf+len, "Highest I2O version supported: "); seq_printf(seq, "Highest I2O version supported: ");
switch(workspace[3]) { switch(workspace[3]) {
case 0x00: case 0x00:
len += sprintf(buf+len,"1.0\n"); seq_printf(seq, "1.0\n");
break; break;
case 0x01: case 0x01:
len += sprintf(buf+len,"1.5\n"); seq_printf(seq, "1.5\n");
break; break;
case 0x02: case 0x02:
len += sprintf(buf+len,"2.0\n"); seq_printf(seq, "2.0\n");
break; break;
} }
} }
*/ */
len += sprintf(buf+len,"IOP ID : %0#5x\n", seq_printf(seq, "IOP ID : %0#5x\n",
c->status_block->iop_id); 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); 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); c->status_block->segment_number);
len += sprintf(buf+len, "I2O version : "); seq_printf(seq, "I2O version : ");
switch (version) { switch (version) {
case 0x00: case 0x00:
len += sprintf(buf+len,"1.0\n"); seq_printf(seq, "1.0\n");
break; break;
case 0x01: case 0x01:
len += sprintf(buf+len,"1.5\n"); seq_printf(seq, "1.5\n");
break; break;
case 0x02: case 0x02:
len += sprintf(buf+len,"2.0\n"); seq_printf(seq, "2.0\n");
break; break;
default: 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) { switch (c->status_block->iop_state) {
case 0x01: case 0x01:
len += sprintf(buf+len,"INIT\n"); seq_printf(seq, "INIT\n");
break; break;
case 0x02: case 0x02:
len += sprintf(buf+len,"RESET\n"); seq_printf(seq, "RESET\n");
break; break;
case 0x04: case 0x04:
len += sprintf(buf+len,"HOLD\n"); seq_printf(seq, "HOLD\n");
break; break;
case 0x05: case 0x05:
len += sprintf(buf+len,"READY\n"); seq_printf(seq, "READY\n");
break; break;
case 0x08: case 0x08:
len += sprintf(buf+len,"OPERATIONAL\n"); seq_printf(seq, "OPERATIONAL\n");
break; break;
case 0x10: case 0x10:
len += sprintf(buf+len,"FAILED\n"); seq_printf(seq, "FAILED\n");
break; break;
case 0x11: case 0x11:
len += sprintf(buf+len,"FAULTED\n"); seq_printf(seq, "FAULTED\n");
break; break;
default: default:
len += sprintf(buf+len,"Unknown\n"); seq_printf(seq, "Unknown\n");
break; break;
} }
len += sprintf(buf+len,"Messenger Type : "); seq_printf(seq, "Messenger Type : ");
switch (c->status_block->msg_type) { switch (c->status_block->msg_type) {
case 0x00: case 0x00:
len += sprintf(buf+len,"Memory mapped\n"); seq_printf(seq, "Memory mapped\n");
break; break;
case 0x01: case 0x01:
len += sprintf(buf+len,"Memory mapped only\n"); seq_printf(seq, "Memory mapped only\n");
break; break;
case 0x02: case 0x02:
len += sprintf(buf+len,"Remote only\n"); seq_printf(seq,"Remote only\n");
break; break;
case 0x03: case 0x03:
len += sprintf(buf+len,"Memory mapped and remote\n"); seq_printf(seq, "Memory mapped and remote\n");
break; break;
default: 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); 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); 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); 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); c->status_block->max_outbound_frames);
/* Spec doesn't say if NULL terminated or not... */ /* Spec doesn't say if NULL terminated or not... */
memcpy(prodstr, c->status_block->product_id, 24); memcpy(prodstr, c->status_block->product_id, 24);
prodstr[24] = '\0'; prodstr[24] = '\0';
len += sprintf(buf+len,"Product ID : %s\n", prodstr); seq_printf(seq, "Product ID : %s\n", prodstr);
len += sprintf(buf+len,"Expected LCT Size : %d bytes\n", seq_printf(seq, "Expected LCT Size : %d bytes\n",
c->status_block->expected_lct_size); c->status_block->expected_lct_size);
len += sprintf(buf+len,"IOP Capabilities\n"); seq_printf(seq, "IOP Capabilities\n");
len += sprintf(buf+len," Context Field Size Support : "); seq_printf(seq, " Context Field Size Support : ");
switch (c->status_block->iop_capabilities & 0x0000003) { switch (c->status_block->iop_capabilities & 0x0000003) {
case 0: case 0:
len += sprintf(buf+len,"Supports only 32-bit context fields\n"); seq_printf(seq, "Supports only 32-bit context fields\n");
break; break;
case 1: case 1:
len += sprintf(buf+len,"Supports only 64-bit context fields\n"); seq_printf(seq, "Supports only 64-bit context fields\n");
break; break;
case 2: 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"); "but not concurrently\n");
break; break;
case 3: 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"); "concurrently\n");
break; break;
default: 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) { switch (c->status_block->iop_capabilities & 0x0000000C) {
case 0: case 0:
len += sprintf(buf+len,"not configured\n"); seq_printf(seq, "not configured\n");
break; break;
case 4: case 4:
len += sprintf(buf+len,"Supports only 32-bit context fields\n"); seq_printf(seq, "Supports only 32-bit context fields\n");
break; break;
case 8: case 8:
len += sprintf(buf+len,"Supports only 64-bit context fields\n"); seq_printf(seq, "Supports only 64-bit context fields\n");
break; break;
case 12: 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"); "concurrently\n");
break; break;
default: 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"); (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"); (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"); (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); 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); 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); 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); 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); 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); c->status_block->current_io_base);
spin_unlock(&i2o_proc_lock); return 0;
return len;
} }
int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len, 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 *data, i2o_proc_entry *pentry, ...@@ -3146,6 +3155,9 @@ static int i2o_proc_create_entries(void *data, i2o_proc_entry *pentry,
ent->data = data; ent->data = data;
ent->read_proc = pentry->read_proc; ent->read_proc = pentry->read_proc;
ent->write_proc = pentry->write_proc; ent->write_proc = pentry->write_proc;
if(pentry->fops_proc)
ent->proc_fops = pentry->fops_proc;
ent->nlink = 1; ent->nlink = 1;
pentry++; pentry++;
...@@ -3266,7 +3278,6 @@ static void i2o_proc_remove_controller(struct i2o_controller *pctrl, ...@@ -3266,7 +3278,6 @@ static void i2o_proc_remove_controller(struct i2o_controller *pctrl,
sprintf(buff, "iop%d", pctrl->unit); sprintf(buff, "iop%d", pctrl->unit);
i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry); i2o_proc_remove_entries(generic_iop_entries, pctrl->proc_entry);
remove_proc_entry(buff, parent); remove_proc_entry(buff, parent);
pctrl->proc_entry = NULL; pctrl->proc_entry = NULL;
} }
...@@ -3306,8 +3317,8 @@ void i2o_proc_remove_device(struct i2o_device *dev) ...@@ -3306,8 +3317,8 @@ void i2o_proc_remove_device(struct i2o_device *dev)
break; break;
} }
} }
remove_proc_entry(dev_id, dev->controller->proc_entry);
} }
remove_proc_entry(dev_id, dev->controller->proc_entry);
} }
} }
......
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