/*
* procfs handler for Linux I2O subsystem
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This is an initial test release. The code is based on the design of the
* ide procfs system (drivers/block/ide-proc.c). Some code taken from
* i2o-core module by Alan Cox.
*
* DISCLAIMER: This code is still under development/test and may cause
* your system to behave unpredictably. Use at your own discretion.
*
*
* Fixes/additions:
* Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
* Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
* University of Helsinki, Department of Computer Science
* LAN entries
* Markus Lidel <Markus.Lidel@shadowconnect.com>
* Changes for new I2O API
*/
#define OSM_NAME "proc-osm"
#define OSM_VERSION "1.316"
#define OSM_DESCRIPTION "I2O ProcFS OSM"
#define I2O_MAX_MODULES 4
// FIXME!
#define FMT_U64_HEX "0x%08x%08x"
#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64))
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/i2o.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
/* Structure used to define /proc entries */
typedef struct _i2o_proc_entry_t {
char *name; /* entry name */
mode_t mode; /* mode */
const struct file_operations *fops; /* open function */
} i2o_proc_entry;
/* global I2O /proc/i2o entry */
static struct proc_dir_entry *i2o_proc_dir_root;
/* proc OSM driver struct */
static struct i2o_driver i2o_proc_driver = {
.name = OSM_NAME,
};
static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len)
{
int i;
/* 19990419 -sralston
* The I2O v1.5 (and v2.0 so far) "official specification"
* got serial numbers WRONG!
* Apparently, and despite what Section 3.4.4 says and
* Figure 3-35 shows (pg 3-39 in the pdf doc),
* the convention / consensus seems to be:
* + First byte is SNFormat
* + Second byte is SNLen (but only if SNFormat==7 (?))
* + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format
*/
switch (serialno[0]) {
case I2O_SNFORMAT_BINARY: /* Binary */
seq_printf(seq, "0x");
for (i = 0; i < serialno[1]; i++) {
seq_printf(seq, "%02X", serialno[2 + i]);
}
break;
case I2O_SNFORMAT_ASCII: /* ASCII */
if (serialno[1] < ' ') { /* printable or SNLen? */
/* sanity */
max_len =
(max_len < serialno[1]) ? max_len : serialno[1];
serialno[1 + max_len] = '\0';
/* just print it */
seq_printf(seq, "%s", &serialno[2]);
} else {
/* print chars for specified length */
for (i = 0; i < serialno[1]; i++) {
seq_printf(seq, "%c", serialno[2 + i]);
}
}
break;
case I2O_SNFORMAT_UNICODE: /* UNICODE */
seq_printf(seq, "UNICODE Format. Can't Display\n");
break;
case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */
seq_printf(seq, "LAN-48 MAC address @ %pM", &serialno[2]);
break;
case I2O_SNFORMAT_WAN: /* WAN MAC Address */
/* FIXME: Figure out what a WAN access address looks like?? */
seq_printf(seq, "WAN Access Address");
break;
/* plus new in v2.0 */
case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */
/* FIXME: Figure out what a LAN-64 address really looks like?? */
seq_printf(seq,
"LAN-64 MAC address @ [?:%02X:%02X:?] %pM",
serialno[8], serialno[9], &serialno[2]);
break;
case I2O_SNFORMAT_DDM: /* I2O DDM */
seq_printf(seq,
"DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh",
*(u16 *) & serialno[2],
*(u16 *) & serialno[4], *(u16 *) & serialno[6]);
break;
case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */
case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */
/* FIXME: Figure if this is even close?? */
seq_printf(seq,
"IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n",
*(u32 *) & serialno[2],
*(u32 *) & serialno[6],
*(u32 *) & serialno[10], *(u32 *) & serialno[14]);
break;
case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */
case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */
default:
seq_printf(seq, "Unknown data format (0x%02x)", serialno[0]);
break;
}
return 0;
}
/**
* i2o_get_class_name - do i2o class name lookup
* @class: class number
*
* Return a descriptive string for an i2o class.
*/
static const char *i2o_get_class_name(int class)
{
int idx = 16;
static char *i2o_class_name[] = {
"Executive",
"Device Driver Module",
"Block Device",
"Tape Device",
"LAN Interface",
"WAN Interface",
"Fibre Channel Port",
"Fibre Channel Device",
"SCSI Device",
"ATE Port",
"ATE Device",
"Floppy Controller",
"Floppy Device",
"Secondary Bus Port",
"Peer Transport Agent",
"Peer Transport",
"Unknown"
};
switch (class & 0xfff) {
case I2O_CLASS_EXECUTIVE:
idx = 0;
break;
case I2O_CLASS_DDM:
idx = 1;
break;
case I2O_CLASS_RANDOM_BLOCK_STORAGE:
idx = 2;
break;
case I2O_CLASS_SEQUENTIAL_STORAGE:
idx = 3;
break;
case I2O_CLASS_LAN:
idx = 4;
break;
case I2O_CLASS_WAN:
idx = 5;
break;
case I2O_CLASS_FIBRE_CHANNEL_PORT:
idx = 6;
break;
case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
idx = 7;
break;
case I2O_CLASS_SCSI_PERIPHERAL:
idx = 8;
break;
case I2O_CLASS_ATE_PORT:
idx = 9;
break;
case I2O_CLASS_ATE_PERIPHERAL:
idx = 10;
break;
case I2O_CLASS_FLOPPY_CONTROLLER:
idx = 11;
break;
case I2O_CLASS_FLOPPY_DEVICE:
idx = 12;
break;
case I2O_CLASS_BUS_ADAPTER:
idx = 13;
break;
case I2O_CLASS_PEER_TRANSPORT_AGENT:
idx = 14;
break;
case I2O_CLASS_PEER_TRANSPORT:
idx = 15;
break;
}
return i2o_class_name[idx];
}
#define SCSI_TABLE_SIZE 13
static char *scsi_devices[] = {
"Direct-Access Read/Write",
"Sequential-Access Storage",
"Printer",
"Processor",
"WORM Device",
"CD-ROM Device",
"Scanner Device",
"Optical Memory Device",
"Medium Changer Device",
"Communications Device",
"Graphics Art Pre-Press Device",
"Graphics Art Pre-Press Device",
"Array Controller Device"
};
static char *chtostr(u8 * chars, int n)
{
char tmp[256];
tmp[0] = 0;
return strncat(tmp, (char *)chars, n);
}
static int i2o_report_query_status(struct seq_file *seq, int block_status,
char *group)
{
switch (block_status) {
case -ETIMEDOUT:
return seq_printf(seq, "Timeout reading group %s.\n", group);
case -ENOMEM:
return seq_printf(seq, "No free memory to read the table.\n");
case -I2O_PARAMS_STATUS_INVALID_GROUP_ID:
return seq_printf(seq, "Group %s not supported.\n", group);
default:
return seq_printf(seq,
"Error reading group %s. BlockStatus 0x%02X\n",
group, -block_status);
}
}
static char *bus_strings[] = {
"Local Bus",
"ISA",
"EISA",
"MCA",
"PCI",
"PCMCIA",
"NUBUS",
"CARDBUS"
};
static int i2o_seq_show_hrt(struct seq_file *seq, void *v)
{
struct i2o_controller *c = (struct i2o_controller *)seq->private;
i2o_hrt *hrt = (i2o_hrt *) c->hrt.virt;
u32 bus;
int i;
if (hrt->hrt_version) {
seq_printf(seq,
"HRT table for controller is too new a version.\n");
return 0;
}
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; i++) {
seq_printf(seq, "Entry %d:\n", i);
seq_printf(seq, " Adapter ID: %0#10x\n",
hrt->hrt_entry[i].adapter_id);
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;
seq_printf(seq, " %s Information\n",
bus_strings[bus]);
switch (bus) {
case I2O_BUS_LOCAL:
seq_printf(seq, " IOBase