Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
This commit is contained in:
Linus Torvalds
2005-04-16 15:20:36 -07:00
commit 1da177e4c3
17291 changed files with 6718755 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
menu "I2O device support"
config I2O
tristate "I2O support"
depends on PCI
---help---
The Intelligent Input/Output (I2O) architecture allows hardware
drivers to be split into two parts: an operating system specific
module called the OSM and an hardware specific module called the
HDM. The OSM can talk to a whole range of HDM's, and ideally the
HDM's are not OS dependent. This allows for the same HDM driver to
be used under different operating systems if the relevant OSM is in
place. In order for this to work, you need to have an I2O interface
adapter card in your computer. This card contains a special I/O
processor (IOP), thus allowing high speeds since the CPU does not
have to deal with I/O.
If you say Y here, you will get a choice of interface adapter
drivers and OSM's with the following questions.
To compile this support as a module, choose M here: the
modules will be called i2o_core.
If unsure, say N.
config I2O_CONFIG
tristate "I2O Configuration support"
depends on PCI && I2O
help
Say Y for support of the configuration interface for the I2O adapters.
If you have a RAID controller from Adaptec and you want to use the
raidutils to manage your RAID array, you have to say Y here.
To compile this support as a module, choose M here: the
module will be called i2o_config.
config I2O_BLOCK
tristate "I2O Block OSM"
depends on I2O
help
Include support for the I2O Block OSM. The Block OSM presents disk
and other structured block devices to the operating system. If you
are using an RAID controller, you could access the array only by
the Block OSM driver. But it is possible to access the single disks
by the SCSI OSM driver, for example to monitor the disks.
To compile this support as a module, choose M here: the
module will be called i2o_block.
config I2O_SCSI
tristate "I2O SCSI OSM"
depends on I2O && SCSI
help
Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
I2O controller. You can use both the SCSI and Block OSM together if
you wish. To access a RAID array, you must use the Block OSM driver.
But you could use the SCSI OSM driver to monitor the single disks.
To compile this support as a module, choose M here: the
module will be called i2o_scsi.
config I2O_PROC
tristate "I2O /proc support"
depends on I2O
help
If you say Y here and to "/proc file system support", you will be
able to read I2O related information from the virtual directory
/proc/i2o.
To compile this support as a module, choose M here: the
module will be called i2o_proc.
endmenu

View File

@@ -0,0 +1,13 @@
#
# Makefile for the kernel I2O OSM.
#
# Note : at this point, these files are compiled on all systems.
# In the future, some of these should be built conditionally.
#
i2o_core-y += iop.o driver.o device.o debug.o pci.o exec-osm.o
obj-$(CONFIG_I2O) += i2o_core.o
obj-$(CONFIG_I2O_CONFIG)+= i2o_config.o
obj-$(CONFIG_I2O_BLOCK) += i2o_block.o
obj-$(CONFIG_I2O_SCSI) += i2o_scsi.o
obj-$(CONFIG_I2O_PROC) += i2o_proc.o

View File

@@ -0,0 +1,98 @@
Linux I2O Support (c) Copyright 1999 Red Hat Software
and others.
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.
AUTHORS (so far)
Alan Cox, Building Number Three Ltd.
Core code, SCSI and Block OSMs
Steve Ralston, LSI Logic Corp.
Debugging SCSI and Block OSM
Deepak Saxena, Intel Corp.
Various core/block extensions
/proc interface, bug fixes
Ioctl interfaces for control
Debugging LAN OSM
Philip Rumpf
Fixed assorted dumb SMP locking bugs
Juha Sievanen, University of Helsinki Finland
LAN OSM code
/proc interface to LAN class
Bug fixes
Core code extensions
Auvo H<>kkinen, University of Helsinki Finland
LAN OSM code
/Proc interface to LAN class
Bug fixes
Core code extensions
Taneli V<>h<EFBFBD>kangas, University of Helsinki Finland
Fixes to i2o_config
CREDITS
This work was made possible by
Red Hat Software
Funding for the Building #3 part of the project
Symbios Logic (Now LSI)
Host adapters, hints, known to work platforms when I hit
compatibility problems
BoxHill Corporation
Loan of initial FibreChannel disk array used for development work.
European Comission
Funding the work done by the University of Helsinki
SysKonnect
Loan of FDDI and Gigabit Ethernet cards
ASUSTeK
Loan of I2O motherboard
STATUS:
o The core setup works within limits.
o The scsi layer seems to almost work.
I'm still chasing down the hang bug.
o The block OSM is mostly functional
o LAN OSM works with FDDI and Ethernet cards.
TO DO:
General:
o Provide hidden address space if asked
o Long term message flow control
o PCI IOP's without interrupts are not supported yet
o Push FAIL handling into the core
o DDM control interfaces for module load etc
o Add I2O 2.0 support (Deffered to 2.5 kernel)
Block:
o Multiple major numbers
o Read ahead and cache handling stuff. Talk to Ingo and people
o Power management
o Finish Media changers
SCSI:
o Find the right way to associate drives/luns/busses
Lan:
o Performance tuning
o Test Fibre Channel code
Tape:
o Anyone seen anything implementing this ?
(D.S: Will attempt to do so if spare cycles permit)

View File

@@ -0,0 +1,394 @@
Linux I2O User Space Interface
rev 0.3 - 04/20/99
=============================================================================
Originally written by Deepak Saxena(deepak@plexity.net)
Currently maintained by Deepak Saxena(deepak@plexity.net)
=============================================================================
I. Introduction
The Linux I2O subsystem provides a set of ioctl() commands that can be
utilized by user space applications to communicate with IOPs and devices
on individual IOPs. This document defines the specific ioctl() commands
that are available to the user and provides examples of their uses.
This document assumes the reader is familiar with or has access to the
I2O specification as no I2O message parameters are outlined. For information
on the specification, see http://www.i2osig.org
This document and the I2O user space interface are currently maintained
by Deepak Saxena. Please send all comments, errata, and bug fixes to
deepak@csociety.purdue.edu
II. IOP Access
Access to the I2O subsystem is provided through the device file named
/dev/i2o/ctl. This file is a character file with major number 10 and minor
number 166. It can be created through the following command:
mknod /dev/i2o/ctl c 10 166
III. Determining the IOP Count
SYNOPSIS
ioctl(fd, I2OGETIOPS, int *count);
u8 count[MAX_I2O_CONTROLLERS];
DESCRIPTION
This function returns the system's active IOP table. count should
point to a buffer containing MAX_I2O_CONTROLLERS entries. Upon
returning, each entry will contain a non-zero value if the given
IOP unit is active, and NULL if it is inactive or non-existent.
RETURN VALUE.
Returns 0 if no errors occur, and -1 otherwise. If an error occurs,
errno is set appropriately:
EFAULT Invalid user space pointer was passed
IV. Getting Hardware Resource Table
SYNOPSIS
ioctl(fd, I2OHRTGET, struct i2o_cmd_hrt *hrt);
struct i2o_cmd_hrtlct
{
u32 iop; /* IOP unit number */
void *resbuf; /* Buffer for result */
u32 *reslen; /* Buffer length in bytes */
};
DESCRIPTION
This function returns the Hardware Resource Table of the IOP specified
by hrt->iop in the buffer pointed to by hrt->resbuf. The actual size of
the data is written into *(hrt->reslen).
RETURNS
This function returns 0 if no errors occur. If an error occurs, -1
is returned and errno is set appropriately:
EFAULT Invalid user space pointer was passed
ENXIO Invalid IOP number
ENOBUFS Buffer not large enough. If this occurs, the required
buffer length is written into *(hrt->reslen)
V. Getting Logical Configuration Table
SYNOPSIS
ioctl(fd, I2OLCTGET, struct i2o_cmd_lct *lct);
struct i2o_cmd_hrtlct
{
u32 iop; /* IOP unit number */
void *resbuf; /* Buffer for result */
u32 *reslen; /* Buffer length in bytes */
};
DESCRIPTION
This function returns the Logical Configuration Table of the IOP specified
by lct->iop in the buffer pointed to by lct->resbuf. The actual size of
the data is written into *(lct->reslen).
RETURNS
This function returns 0 if no errors occur. If an error occurs, -1
is returned and errno is set appropriately:
EFAULT Invalid user space pointer was passed
ENXIO Invalid IOP number
ENOBUFS Buffer not large enough. If this occurs, the required
buffer length is written into *(lct->reslen)
VI. Settting Parameters
SYNOPSIS
ioctl(fd, I2OPARMSET, struct i2o_parm_setget *ops);
struct i2o_cmd_psetget
{
u32 iop; /* IOP unit number */
u32 tid; /* Target device TID */
void *opbuf; /* Operation List buffer */
u32 oplen; /* Operation List buffer length in bytes */
void *resbuf; /* Result List buffer */
u32 *reslen; /* Result List buffer length in bytes */
};
DESCRIPTION
This function posts a UtilParamsSet message to the device identified
by ops->iop and ops->tid. The operation list for the message is
sent through the ops->opbuf buffer, and the result list is written
into the buffer pointed to by ops->resbuf. The number of bytes
written is placed into *(ops->reslen).
RETURNS
The return value is the size in bytes of the data written into
ops->resbuf if no errors occur. If an error occurs, -1 is returned
and errno is set appropriatly:
EFAULT Invalid user space pointer was passed
ENXIO Invalid IOP number
ENOBUFS Buffer not large enough. If this occurs, the required
buffer length is written into *(ops->reslen)
ETIMEDOUT Timeout waiting for reply message
ENOMEM Kernel memory allocation error
A return value of 0 does not mean that the value was actually
changed properly on the IOP. The user should check the result
list to determine the specific status of the transaction.
VII. Getting Parameters
SYNOPSIS
ioctl(fd, I2OPARMGET, struct i2o_parm_setget *ops);
struct i2o_parm_setget
{
u32 iop; /* IOP unit number */
u32 tid; /* Target device TID */
void *opbuf; /* Operation List buffer */
u32 oplen; /* Operation List buffer length in bytes */
void *resbuf; /* Result List buffer */
u32 *reslen; /* Result List buffer length in bytes */
};
DESCRIPTION
This function posts a UtilParamsGet message to the device identified
by ops->iop and ops->tid. The operation list for the message is
sent through the ops->opbuf buffer, and the result list is written
into the buffer pointed to by ops->resbuf. The actual size of data
written is placed into *(ops->reslen).
RETURNS
EFAULT Invalid user space pointer was passed
ENXIO Invalid IOP number
ENOBUFS Buffer not large enough. If this occurs, the required
buffer length is written into *(ops->reslen)
ETIMEDOUT Timeout waiting for reply message
ENOMEM Kernel memory allocation error
A return value of 0 does not mean that the value was actually
properly retreived. The user should check the result list
to determine the specific status of the transaction.
VIII. Downloading Software
SYNOPSIS
ioctl(fd, I2OSWDL, struct i2o_sw_xfer *sw);
struct i2o_sw_xfer
{
u32 iop; /* IOP unit number */
u8 flags; /* DownloadFlags field */
u8 sw_type; /* Software type */
u32 sw_id; /* Software ID */
void *buf; /* Pointer to software buffer */
u32 *swlen; /* Length of software buffer */
u32 *maxfrag; /* Number of fragments */
u32 *curfrag; /* Current fragment number */
};
DESCRIPTION
This function downloads a software fragment pointed by sw->buf
to the iop identified by sw->iop. The DownloadFlags, SwID, SwType
and SwSize fields of the ExecSwDownload message are filled in with
the values of sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen).
The fragments _must_ be sent in order and be 8K in size. The last
fragment _may_ be shorter, however. The kernel will compute its
size based on information in the sw->swlen field.
Please note that SW transfers can take a long time.
RETURNS
This function returns 0 no errors occur. If an error occurs, -1
is returned and errno is set appropriatly:
EFAULT Invalid user space pointer was passed
ENXIO Invalid IOP number
ETIMEDOUT Timeout waiting for reply message
ENOMEM Kernel memory allocation error
IX. Uploading Software
SYNOPSIS
ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw);
struct i2o_sw_xfer
{
u32 iop; /* IOP unit number */
u8 flags; /* UploadFlags */
u8 sw_type; /* Software type */
u32 sw_id; /* Software ID */
void *buf; /* Pointer to software buffer */
u32 *swlen; /* Length of software buffer */
u32 *maxfrag; /* Number of fragments */
u32 *curfrag; /* Current fragment number */
};
DESCRIPTION
This function uploads a software fragment from the IOP identified
by sw->iop, sw->sw_type, sw->sw_id and optionally sw->swlen fields.
The UploadFlags, SwID, SwType and SwSize fields of the ExecSwUpload
message are filled in with the values of sw->flags, sw->sw_id,
sw->sw_type and *(sw->swlen).
The fragments _must_ be requested in order and be 8K in size. The
user is responsible for allocating memory pointed by sw->buf. The
last fragment _may_ be shorter.
Please note that SW transfers can take a long time.
RETURNS
This function returns 0 if no errors occur. If an error occurs, -1
is returned and errno is set appropriatly:
EFAULT Invalid user space pointer was passed
ENXIO Invalid IOP number
ETIMEDOUT Timeout waiting for reply message
ENOMEM Kernel memory allocation error
X. Removing Software
SYNOPSIS
ioctl(fd, I2OSWDEL, struct i2o_sw_xfer *sw);
struct i2o_sw_xfer
{
u32 iop; /* IOP unit number */
u8 flags; /* RemoveFlags */
u8 sw_type; /* Software type */
u32 sw_id; /* Software ID */
void *buf; /* Unused */
u32 *swlen; /* Length of the software data */
u32 *maxfrag; /* Unused */
u32 *curfrag; /* Unused */
};
DESCRIPTION
This function removes software from the IOP identified by sw->iop.
The RemoveFlags, SwID, SwType and SwSize fields of the ExecSwRemove message
are filled in with the values of sw->flags, sw->sw_id, sw->sw_type and
*(sw->swlen). Give zero in *(sw->len) if the value is unknown. IOP uses
*(sw->swlen) value to verify correct identication of the module to remove.
The actual size of the module is written into *(sw->swlen).
RETURNS
This function returns 0 if no errors occur. If an error occurs, -1
is returned and errno is set appropriatly:
EFAULT Invalid user space pointer was passed
ENXIO Invalid IOP number
ETIMEDOUT Timeout waiting for reply message
ENOMEM Kernel memory allocation error
X. Validating Configuration
SYNOPSIS
ioctl(fd, I2OVALIDATE, int *iop);
u32 iop;
DESCRIPTION
This function posts an ExecConfigValidate message to the controller
identified by iop. This message indicates that the current
configuration is accepted. The iop changes the status of suspect drivers
to valid and may delete old drivers from its store.
RETURNS
This function returns 0 if no erro occur. If an error occurs, -1 is
returned and errno is set appropriatly:
ETIMEDOUT Timeout waiting for reply message
ENXIO Invalid IOP number
XI. Configuration Dialog
SYNOPSIS
ioctl(fd, I2OHTML, struct i2o_html *htquery);
struct i2o_html
{
u32 iop; /* IOP unit number */
u32 tid; /* Target device ID */
u32 page; /* HTML page */
void *resbuf; /* Buffer for reply HTML page */
u32 *reslen; /* Length in bytes of reply buffer */
void *qbuf; /* Pointer to HTTP query string */
u32 qlen; /* Length in bytes of query string buffer */
};
DESCRIPTION
This function posts an UtilConfigDialog message to the device identified
by htquery->iop and htquery->tid. The requested HTML page number is
provided by the htquery->page field, and the resultant data is stored
in the buffer pointed to by htquery->resbuf. If there is an HTTP query
string that is to be sent to the device, it should be sent in the buffer
pointed to by htquery->qbuf. If there is no query string, this field
should be set to NULL. The actual size of the reply received is written
into *(htquery->reslen).
RETURNS
This function returns 0 if no error occur. If an error occurs, -1
is returned and errno is set appropriatly:
EFAULT Invalid user space pointer was passed
ENXIO Invalid IOP number
ENOBUFS Buffer not large enough. If this occurs, the required
buffer length is written into *(ops->reslen)
ETIMEDOUT Timeout waiting for reply message
ENOMEM Kernel memory allocation error
XII. Events
In the process of determining this. Current idea is to have use
the select() interface to allow user apps to periodically poll
the /dev/i2o/ctl device for events. When select() notifies the user
that an event is available, the user would call read() to retrieve
a list of all the events that are pending for the specific device.
=============================================================================
Revision History
=============================================================================
Rev 0.1 - 04/01/99
- Initial revision
Rev 0.2 - 04/06/99
- Changed return values to match UNIX ioctl() standard. Only return values
are 0 and -1. All errors are reported through errno.
- Added summary of proposed possible event interfaces
Rev 0.3 - 04/20/99
- Changed all ioctls() to use pointers to user data instead of actual data
- Updated error values to match the code

481
drivers/message/i2o/debug.c Normal file
View File

@@ -0,0 +1,481 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/i2o.h>
extern struct i2o_driver **i2o_drivers;
extern unsigned int i2o_max_drivers;
static void i2o_report_util_cmd(u8 cmd);
static void i2o_report_exec_cmd(u8 cmd);
static void i2o_report_fail_status(u8 req_status, u32 * msg);
static void i2o_report_common_status(u8 req_status);
static void i2o_report_common_dsc(u16 detailed_status);
/*
* Used for error reporting/debugging purposes.
* Report Cmd name, Request status, Detailed Status.
*/
void i2o_report_status(const char *severity, const char *str,
struct i2o_message *m)
{
u32 *msg = (u32 *) m;
u8 cmd = (msg[1] >> 24) & 0xFF;
u8 req_status = (msg[4] >> 24) & 0xFF;
u16 detailed_status = msg[4] & 0xFFFF;
//struct i2o_driver *h = i2o_drivers[msg[2] & (i2o_max_drivers-1)];
if (cmd == I2O_CMD_UTIL_EVT_REGISTER)
return; // No status in this reply
printk(KERN_DEBUG "%s%s: ", severity, str);
if (cmd < 0x1F) // Utility cmd
i2o_report_util_cmd(cmd);
else if (cmd >= 0xA0 && cmd <= 0xEF) // Executive cmd
i2o_report_exec_cmd(cmd);
else
printk(KERN_DEBUG "Cmd = %0#2x, ", cmd); // Other cmds
if (msg[0] & MSG_FAIL) {
i2o_report_fail_status(req_status, msg);
return;
}
i2o_report_common_status(req_status);
if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
i2o_report_common_dsc(detailed_status);
else
printk(KERN_DEBUG " / DetailedStatus = %0#4x.\n",
detailed_status);
}
/* Used to dump a message to syslog during debugging */
void i2o_dump_message(struct i2o_message *m)
{
#ifdef DEBUG
u32 *msg = (u32 *) m;
int i;
printk(KERN_INFO "Dumping I2O message size %d @ %p\n",
msg[0] >> 16 & 0xffff, msg);
for (i = 0; i < ((msg[0] >> 16) & 0xffff); i++)
printk(KERN_INFO " msg[%d] = %0#10x\n", i, msg[i]);
#endif
}
/*
* Used for error reporting/debugging purposes.
* Following fail status are common to all classes.
* The preserved message must be handled in the reply handler.
*/
static void i2o_report_fail_status(u8 req_status, u32 * msg)
{
static char *FAIL_STATUS[] = {
"0x80", /* not used */
"SERVICE_SUSPENDED", /* 0x81 */
"SERVICE_TERMINATED", /* 0x82 */
"CONGESTION",
"FAILURE",
"STATE_ERROR",
"TIME_OUT",
"ROUTING_FAILURE",
"INVALID_VERSION",
"INVALID_OFFSET",
"INVALID_MSG_FLAGS",
"FRAME_TOO_SMALL",
"FRAME_TOO_LARGE",
"INVALID_TARGET_ID",
"INVALID_INITIATOR_ID",
"INVALID_INITIATOR_CONTEX", /* 0x8F */
"UNKNOWN_FAILURE" /* 0xFF */
};
if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
printk(KERN_DEBUG "TRANSPORT_UNKNOWN_FAILURE (%0#2x)\n.",
req_status);
else
printk(KERN_DEBUG "TRANSPORT_%s.\n",
FAIL_STATUS[req_status & 0x0F]);
/* Dump some details */
printk(KERN_ERR " InitiatorId = %d, TargetId = %d\n",
(msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
printk(KERN_ERR " LowestVersion = 0x%02X, HighestVersion = 0x%02X\n",
(msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n",
msg[5] >> 16, msg[5] & 0xFFF);
printk(KERN_ERR " Severity: 0x%02X ", (msg[4] >> 16) & 0xFF);
if (msg[4] & (1 << 16))
printk(KERN_DEBUG "(FormatError), "
"this msg can never be delivered/processed.\n");
if (msg[4] & (1 << 17))
printk(KERN_DEBUG "(PathError), "
"this msg can no longer be delivered/processed.\n");
if (msg[4] & (1 << 18))
printk(KERN_DEBUG "(PathState), "
"the system state does not allow delivery.\n");
if (msg[4] & (1 << 19))
printk(KERN_DEBUG
"(Congestion), resources temporarily not available;"
"do not retry immediately.\n");
}
/*
* Used for error reporting/debugging purposes.
* Following reply status are common to all classes.
*/
static void i2o_report_common_status(u8 req_status)
{
static char *REPLY_STATUS[] = {
"SUCCESS",
"ABORT_DIRTY",
"ABORT_NO_DATA_TRANSFER",
"ABORT_PARTIAL_TRANSFER",
"ERROR_DIRTY",
"ERROR_NO_DATA_TRANSFER",
"ERROR_PARTIAL_TRANSFER",
"PROCESS_ABORT_DIRTY",
"PROCESS_ABORT_NO_DATA_TRANSFER",
"PROCESS_ABORT_PARTIAL_TRANSFER",
"TRANSACTION_ERROR",
"PROGRESS_REPORT"
};
if (req_status >= ARRAY_SIZE(REPLY_STATUS))
printk(KERN_DEBUG "RequestStatus = %0#2x", req_status);
else
printk(KERN_DEBUG "%s", REPLY_STATUS[req_status]);
}
/*
* Used for error reporting/debugging purposes.
* Following detailed status are valid for executive class,
* utility class, DDM class and for transaction error replies.
*/
static void i2o_report_common_dsc(u16 detailed_status)
{
static char *COMMON_DSC[] = {
"SUCCESS",
"0x01", // not used
"BAD_KEY",
"TCL_ERROR",
"REPLY_BUFFER_FULL",
"NO_SUCH_PAGE",
"INSUFFICIENT_RESOURCE_SOFT",
"INSUFFICIENT_RESOURCE_HARD",
"0x08", // not used
"CHAIN_BUFFER_TOO_LARGE",
"UNSUPPORTED_FUNCTION",
"DEVICE_LOCKED",
"DEVICE_RESET",
"INAPPROPRIATE_FUNCTION",
"INVALID_INITIATOR_ADDRESS",
"INVALID_MESSAGE_FLAGS",
"INVALID_OFFSET",
"INVALID_PARAMETER",
"INVALID_REQUEST",
"INVALID_TARGET_ADDRESS",
"MESSAGE_TOO_LARGE",
"MESSAGE_TOO_SMALL",
"MISSING_PARAMETER",
"TIMEOUT",
"UNKNOWN_ERROR",
"UNKNOWN_FUNCTION",
"UNSUPPORTED_VERSION",
"DEVICE_BUSY",
"DEVICE_NOT_AVAILABLE"
};
if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
printk(KERN_DEBUG " / DetailedStatus = %0#4x.\n",
detailed_status);
else
printk(KERN_DEBUG " / %s.\n", COMMON_DSC[detailed_status]);
}
/*
* Used for error reporting/debugging purposes
*/
static void i2o_report_util_cmd(u8 cmd)
{
switch (cmd) {
case I2O_CMD_UTIL_NOP:
printk(KERN_DEBUG "UTIL_NOP, ");
break;
case I2O_CMD_UTIL_ABORT:
printk(KERN_DEBUG "UTIL_ABORT, ");
break;
case I2O_CMD_UTIL_CLAIM:
printk(KERN_DEBUG "UTIL_CLAIM, ");
break;
case I2O_CMD_UTIL_RELEASE:
printk(KERN_DEBUG "UTIL_CLAIM_RELEASE, ");
break;
case I2O_CMD_UTIL_CONFIG_DIALOG:
printk(KERN_DEBUG "UTIL_CONFIG_DIALOG, ");
break;
case I2O_CMD_UTIL_DEVICE_RESERVE:
printk(KERN_DEBUG "UTIL_DEVICE_RESERVE, ");
break;
case I2O_CMD_UTIL_DEVICE_RELEASE:
printk(KERN_DEBUG "UTIL_DEVICE_RELEASE, ");
break;
case I2O_CMD_UTIL_EVT_ACK:
printk(KERN_DEBUG "UTIL_EVENT_ACKNOWLEDGE, ");
break;
case I2O_CMD_UTIL_EVT_REGISTER:
printk(KERN_DEBUG "UTIL_EVENT_REGISTER, ");
break;
case I2O_CMD_UTIL_LOCK:
printk(KERN_DEBUG "UTIL_LOCK, ");
break;
case I2O_CMD_UTIL_LOCK_RELEASE:
printk(KERN_DEBUG "UTIL_LOCK_RELEASE, ");
break;
case I2O_CMD_UTIL_PARAMS_GET:
printk(KERN_DEBUG "UTIL_PARAMS_GET, ");
break;
case I2O_CMD_UTIL_PARAMS_SET:
printk(KERN_DEBUG "UTIL_PARAMS_SET, ");
break;
case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
printk(KERN_DEBUG "UTIL_REPLY_FAULT_NOTIFY, ");
break;
default:
printk(KERN_DEBUG "Cmd = %0#2x, ", cmd);
}
}
/*
* Used for error reporting/debugging purposes
*/
static void i2o_report_exec_cmd(u8 cmd)
{
switch (cmd) {
case I2O_CMD_ADAPTER_ASSIGN:
printk(KERN_DEBUG "EXEC_ADAPTER_ASSIGN, ");
break;
case I2O_CMD_ADAPTER_READ:
printk(KERN_DEBUG "EXEC_ADAPTER_READ, ");
break;
case I2O_CMD_ADAPTER_RELEASE:
printk(KERN_DEBUG "EXEC_ADAPTER_RELEASE, ");
break;
case I2O_CMD_BIOS_INFO_SET:
printk(KERN_DEBUG "EXEC_BIOS_INFO_SET, ");
break;
case I2O_CMD_BOOT_DEVICE_SET:
printk(KERN_DEBUG "EXEC_BOOT_DEVICE_SET, ");
break;
case I2O_CMD_CONFIG_VALIDATE:
printk(KERN_DEBUG "EXEC_CONFIG_VALIDATE, ");
break;
case I2O_CMD_CONN_SETUP:
printk(KERN_DEBUG "EXEC_CONN_SETUP, ");
break;
case I2O_CMD_DDM_DESTROY:
printk(KERN_DEBUG "EXEC_DDM_DESTROY, ");
break;
case I2O_CMD_DDM_ENABLE:
printk(KERN_DEBUG "EXEC_DDM_ENABLE, ");
break;
case I2O_CMD_DDM_QUIESCE:
printk(KERN_DEBUG "EXEC_DDM_QUIESCE, ");
break;
case I2O_CMD_DDM_RESET:
printk(KERN_DEBUG "EXEC_DDM_RESET, ");
break;
case I2O_CMD_DDM_SUSPEND:
printk(KERN_DEBUG "EXEC_DDM_SUSPEND, ");
break;
case I2O_CMD_DEVICE_ASSIGN:
printk(KERN_DEBUG "EXEC_DEVICE_ASSIGN, ");
break;
case I2O_CMD_DEVICE_RELEASE:
printk(KERN_DEBUG "EXEC_DEVICE_RELEASE, ");
break;
case I2O_CMD_HRT_GET:
printk(KERN_DEBUG "EXEC_HRT_GET, ");
break;
case I2O_CMD_ADAPTER_CLEAR:
printk(KERN_DEBUG "EXEC_IOP_CLEAR, ");
break;
case I2O_CMD_ADAPTER_CONNECT:
printk(KERN_DEBUG "EXEC_IOP_CONNECT, ");
break;
case I2O_CMD_ADAPTER_RESET:
printk(KERN_DEBUG "EXEC_IOP_RESET, ");
break;
case I2O_CMD_LCT_NOTIFY:
printk(KERN_DEBUG "EXEC_LCT_NOTIFY, ");
break;
case I2O_CMD_OUTBOUND_INIT:
printk(KERN_DEBUG "EXEC_OUTBOUND_INIT, ");
break;
case I2O_CMD_PATH_ENABLE:
printk(KERN_DEBUG "EXEC_PATH_ENABLE, ");
break;
case I2O_CMD_PATH_QUIESCE:
printk(KERN_DEBUG "EXEC_PATH_QUIESCE, ");
break;
case I2O_CMD_PATH_RESET:
printk(KERN_DEBUG "EXEC_PATH_RESET, ");
break;
case I2O_CMD_STATIC_MF_CREATE:
printk(KERN_DEBUG "EXEC_STATIC_MF_CREATE, ");
break;
case I2O_CMD_STATIC_MF_RELEASE:
printk(KERN_DEBUG "EXEC_STATIC_MF_RELEASE, ");
break;
case I2O_CMD_STATUS_GET:
printk(KERN_DEBUG "EXEC_STATUS_GET, ");
break;
case I2O_CMD_SW_DOWNLOAD:
printk(KERN_DEBUG "EXEC_SW_DOWNLOAD, ");
break;
case I2O_CMD_SW_UPLOAD:
printk(KERN_DEBUG "EXEC_SW_UPLOAD, ");
break;
case I2O_CMD_SW_REMOVE:
printk(KERN_DEBUG "EXEC_SW_REMOVE, ");
break;
case I2O_CMD_SYS_ENABLE:
printk(KERN_DEBUG "EXEC_SYS_ENABLE, ");
break;
case I2O_CMD_SYS_MODIFY:
printk(KERN_DEBUG "EXEC_SYS_MODIFY, ");
break;
case I2O_CMD_SYS_QUIESCE:
printk(KERN_DEBUG "EXEC_SYS_QUIESCE, ");
break;
case I2O_CMD_SYS_TAB_SET:
printk(KERN_DEBUG "EXEC_SYS_TAB_SET, ");
break;
default:
printk(KERN_DEBUG "Cmd = %#02x, ", cmd);
}
}
void i2o_debug_state(struct i2o_controller *c)
{
printk(KERN_INFO "%s: State = ", c->name);
switch (((i2o_status_block *) c->status_block.virt)->iop_state) {
case 0x01:
printk(KERN_DEBUG "INIT\n");
break;
case 0x02:
printk(KERN_DEBUG "RESET\n");
break;
case 0x04:
printk(KERN_DEBUG "HOLD\n");
break;
case 0x05:
printk(KERN_DEBUG "READY\n");
break;
case 0x08:
printk(KERN_DEBUG "OPERATIONAL\n");
break;
case 0x10:
printk(KERN_DEBUG "FAILED\n");
break;
case 0x11:
printk(KERN_DEBUG "FAULTED\n");
break;
default:
printk(KERN_DEBUG "%x (unknown !!)\n",
((i2o_status_block *) c->status_block.virt)->iop_state);
}
};
void i2o_dump_hrt(struct i2o_controller *c)
{
u32 *rows = (u32 *) c->hrt.virt;
u8 *p = (u8 *) c->hrt.virt;
u8 *d;
int count;
int length;
int i;
int state;
if (p[3] != 0) {
printk(KERN_ERR
"%s: HRT table for controller is too new a version.\n",
c->name);
return;
}
count = p[0] | (p[1] << 8);
length = p[2];
printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
c->name, count, length << 2);
rows += 2;
for (i = 0; i < count; i++) {
printk(KERN_INFO "Adapter %08X: ", rows[0]);
p = (u8 *) (rows + 1);
d = (u8 *) (rows + 2);
state = p[1] << 8 | p[0];
printk(KERN_DEBUG "TID %04X:[", state & 0xFFF);
state >>= 12;
if (state & (1 << 0))
printk(KERN_DEBUG "H"); /* Hidden */
if (state & (1 << 2)) {
printk(KERN_DEBUG "P"); /* Present */
if (state & (1 << 1))
printk(KERN_DEBUG "C"); /* Controlled */
}
if (state > 9)
printk(KERN_DEBUG "*"); /* Hard */
printk(KERN_DEBUG "]:");
switch (p[3] & 0xFFFF) {
case 0:
/* Adapter private bus - easy */
printk(KERN_DEBUG
"Local bus %d: I/O at 0x%04X Mem 0x%08X", p[2],
d[1] << 8 | d[0], *(u32 *) (d + 4));
break;
case 1:
/* ISA bus */
printk(KERN_DEBUG
"ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", p[2],
d[2], d[1] << 8 | d[0], *(u32 *) (d + 4));
break;
case 2: /* EISA bus */
printk(KERN_DEBUG
"EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
break;
case 3: /* MCA bus */
printk(KERN_DEBUG
"MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", p[2],
d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
break;
case 4: /* PCI bus */
printk(KERN_DEBUG
"PCI %d: Bus %d Device %d Function %d", p[2],
d[2], d[1], d[0]);
break;
case 0x80: /* Other */
default:
printk(KERN_DEBUG "Unsupported bus type.");
break;
}
printk(KERN_DEBUG "\n");
rows += length;
}
}
EXPORT_SYMBOL(i2o_dump_message);

View File

@@ -0,0 +1,634 @@
/*
* Functions to handle I2O devices
*
* Copyright (C) 2004 Markus Lidel <Markus.Lidel@shadowconnect.com>
*
* 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.
*
* Fixes/additions:
* Markus Lidel <Markus.Lidel@shadowconnect.com>
* initial version.
*/
#include <linux/module.h>
#include <linux/i2o.h>
#include <linux/delay.h>
/* Exec OSM functions */
extern struct bus_type i2o_bus_type;
/**
* i2o_device_issue_claim - claim or release a device
* @dev: I2O device to claim or release
* @cmd: claim or release command
* @type: type of claim
*
* Issue I2O UTIL_CLAIM or UTIL_RELEASE messages. The message to be sent
* is set by cmd. dev is the I2O device which should be claim or
* released and the type is the claim type (see the I2O spec).
*
* Returs 0 on success or negative error code on failure.
*/
static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd,
u32 type)
{
struct i2o_message __iomem *msg;
u32 m;
m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
return -ETIMEDOUT;
writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
writel(cmd << 24 | HOST_TID << 12 | dev->lct_data.tid, &msg->u.head[1]);
writel(type, &msg->body[0]);
return i2o_msg_post_wait(dev->iop, m, 60);
};
/**
* i2o_device_claim - claim a device for use by an OSM
* @dev: I2O device to claim
* @drv: I2O driver which wants to claim the device
*
* Do the leg work to assign a device to a given OSM. If the claim succeed
* the owner of the rimary. If the attempt fails a negative errno code
* is returned. On success zero is returned.
*/
int i2o_device_claim(struct i2o_device *dev)
{
int rc = 0;
down(&dev->lock);
rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY);
if (!rc)
pr_debug("i2o: claim of device %d succeded\n",
dev->lct_data.tid);
else
pr_debug("i2o: claim of device %d failed %d\n",
dev->lct_data.tid, rc);
up(&dev->lock);
return rc;
};
/**
* i2o_device_claim_release - release a device that the OSM is using
* @dev: device to release
* @drv: driver which claimed the device
*
* Drop a claim by an OSM on a given I2O device.
*
* AC - some devices seem to want to refuse an unclaim until they have
* finished internal processing. It makes sense since you don't want a
* new device to go reconfiguring the entire system until you are done.
* Thus we are prepared to wait briefly.
*
* Returns 0 on success or negative error code on failure.
*/
int i2o_device_claim_release(struct i2o_device *dev)
{
int tries;
int rc = 0;
down(&dev->lock);
/*
* If the controller takes a nonblocking approach to
* releases we have to sleep/poll for a few times.
*/
for (tries = 0; tries < 10; tries++) {
rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_RELEASE,
I2O_CLAIM_PRIMARY);
if (!rc)
break;
ssleep(1);
}
if (!rc)
pr_debug("i2o: claim release of device %d succeded\n",
dev->lct_data.tid);
else
pr_debug("i2o: claim release of device %d failed %d\n",
dev->lct_data.tid, rc);
up(&dev->lock);
return rc;
};
/**
* i2o_device_release - release the memory for a I2O device
* @dev: I2O device which should be released
*
* Release the allocated memory. This function is called if refcount of
* device reaches 0 automatically.
*/
static void i2o_device_release(struct device *dev)
{
struct i2o_device *i2o_dev = to_i2o_device(dev);
pr_debug("i2o: device %s released\n", dev->bus_id);
kfree(i2o_dev);
};
/**
* i2o_device_class_release - Remove I2O device attributes
* @cd: I2O class device which is added to the I2O device class
*
* Removes attributes from the I2O device again. Also search each device
* on the controller for I2O devices which refert to this device as parent
* or user and remove this links also.
*/
static void i2o_device_class_release(struct class_device *cd)
{
struct i2o_device *i2o_dev, *tmp;
struct i2o_controller *c;
i2o_dev = to_i2o_device(cd->dev);
c = i2o_dev->iop;
sysfs_remove_link(&i2o_dev->device.kobj, "parent");
sysfs_remove_link(&i2o_dev->device.kobj, "user");
list_for_each_entry(tmp, &c->devices, list) {
if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
sysfs_remove_link(&tmp->device.kobj, "parent");
if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
sysfs_remove_link(&tmp->device.kobj, "user");
}
};
/* I2O device class */
static struct class i2o_device_class = {
.name = "i2o_device",
.release = i2o_device_class_release
};
/**
* i2o_device_alloc - Allocate a I2O device and initialize it
*
* Allocate the memory for a I2O device and initialize locks and lists
*
* Returns the allocated I2O device or a negative error code if the device
* could not be allocated.
*/
static struct i2o_device *i2o_device_alloc(void)
{
struct i2o_device *dev;
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);
memset(dev, 0, sizeof(*dev));
INIT_LIST_HEAD(&dev->list);
init_MUTEX(&dev->lock);
dev->device.bus = &i2o_bus_type;
dev->device.release = &i2o_device_release;
dev->classdev.class = &i2o_device_class;
dev->classdev.dev = &dev->device;
return dev;
};
/**
* i2o_device_add - allocate a new I2O device and add it to the IOP
* @iop: I2O controller where the device is on
* @entry: LCT entry of the I2O device
*
* Allocate a new I2O device and initialize it with the LCT entry. The
* device is appended to the device list of the controller.
*
* Returns a pointer to the I2O device on success or negative error code
* on failure.
*/
static struct i2o_device *i2o_device_add(struct i2o_controller *c,
i2o_lct_entry * entry)
{
struct i2o_device *dev;
dev = i2o_device_alloc();
if (IS_ERR(dev)) {
printk(KERN_ERR "i2o: unable to allocate i2o device\n");
return dev;
}
dev->lct_data = *entry;
snprintf(dev->device.bus_id, BUS_ID_SIZE, "%d:%03x", c->unit,
dev->lct_data.tid);
snprintf(dev->classdev.class_id, BUS_ID_SIZE, "%d:%03x", c->unit,
dev->lct_data.tid);
dev->iop = c;
dev->device.parent = &c->device;
device_register(&dev->device);
list_add_tail(&dev->list, &c->devices);
class_device_register(&dev->classdev);
i2o_driver_notify_device_add_all(dev);
pr_debug("i2o: device %s added\n", dev->device.bus_id);
return dev;
};
/**
* i2o_device_remove - remove an I2O device from the I2O core
* @dev: I2O device which should be released
*
* Is used on I2O controller removal or LCT modification, when the device
* is removed from the system. Note that the device could still hang
* around until the refcount reaches 0.
*/
void i2o_device_remove(struct i2o_device *i2o_dev)
{
i2o_driver_notify_device_remove_all(i2o_dev);
class_device_unregister(&i2o_dev->classdev);
list_del(&i2o_dev->list);
device_unregister(&i2o_dev->device);
};
/**
* i2o_device_parse_lct - Parse a previously fetched LCT and create devices
* @c: I2O controller from which the LCT should be parsed.
*
* The Logical Configuration Table tells us what we can talk to on the
* board. For every entry we create an I2O device, which is registered in
* the I2O core.
*
* Returns 0 on success or negative error code on failure.
*/
int i2o_device_parse_lct(struct i2o_controller *c)
{
struct i2o_device *dev, *tmp;
i2o_lct *lct;
int i;
int max;
down(&c->lct_lock);
if (c->lct)
kfree(c->lct);
lct = c->dlct.virt;
c->lct = kmalloc(lct->table_size * 4, GFP_KERNEL);
if (!c->lct) {
up(&c->lct_lock);
return -ENOMEM;
}
if (lct->table_size * 4 > c->dlct.len) {
memcpy_fromio(c->lct, c->dlct.virt, c->dlct.len);
up(&c->lct_lock);
return -EAGAIN;
}
memcpy_fromio(c->lct, c->dlct.virt, lct->table_size * 4);
lct = c->lct;
max = (lct->table_size - 3) / 9;
pr_debug("%s: LCT has %d entries (LCT size: %d)\n", c->name, max,
lct->table_size);
/* remove devices, which are not in the LCT anymore */
list_for_each_entry_safe(dev, tmp, &c->devices, list) {
int found = 0;
for (i = 0; i < max; i++) {
if (lct->lct_entry[i].tid == dev->lct_data.tid) {
found = 1;
break;
}
}
if (!found)
i2o_device_remove(dev);
}
/* add new devices, which are new in the LCT */
for (i = 0; i < max; i++) {
int found = 0;
list_for_each_entry_safe(dev, tmp, &c->devices, list) {
if (lct->lct_entry[i].tid == dev->lct_data.tid) {
found = 1;
break;
}
}
if (!found)
i2o_device_add(c, &lct->lct_entry[i]);
}
up(&c->lct_lock);
return 0;
};
/**
* i2o_device_class_show_class_id - Displays class id of I2O device
* @cd: class device of which the class id should be displayed
* @buf: buffer into which the class id should be printed
*
* Returns the number of bytes which are printed into the buffer.
*/
static ssize_t i2o_device_class_show_class_id(struct class_device *cd,
char *buf)
{
struct i2o_device *dev = to_i2o_device(cd->dev);
sprintf(buf, "%03x\n", dev->lct_data.class_id);
return strlen(buf) + 1;
};
/**
* i2o_device_class_show_tid - Displays TID of I2O device
* @cd: class device of which the TID should be displayed
* @buf: buffer into which the class id should be printed
*
* Returns the number of bytes which are printed into the buffer.
*/
static ssize_t i2o_device_class_show_tid(struct class_device *cd, char *buf)
{
struct i2o_device *dev = to_i2o_device(cd->dev);
sprintf(buf, "%03x\n", dev->lct_data.tid);
return strlen(buf) + 1;
};
/* I2O device class attributes */
static CLASS_DEVICE_ATTR(class_id, S_IRUGO, i2o_device_class_show_class_id,
NULL);
static CLASS_DEVICE_ATTR(tid, S_IRUGO, i2o_device_class_show_tid, NULL);
/**
* i2o_device_class_add - Adds attributes to the I2O device
* @cd: I2O class device which is added to the I2O device class
*
* This function get called when a I2O device is added to the class. It
* creates the attributes for each device and creates user/parent symlink
* if necessary.
*
* Returns 0 on success or negative error code on failure.
*/
static int i2o_device_class_add(struct class_device *cd)
{
struct i2o_device *i2o_dev, *tmp;
struct i2o_controller *c;
i2o_dev = to_i2o_device(cd->dev);
c = i2o_dev->iop;
class_device_create_file(cd, &class_device_attr_class_id);
class_device_create_file(cd, &class_device_attr_tid);
/* create user entries for this device */
tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid);
if (tmp)
sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj,
"user");
/* create user entries refering to this device */
list_for_each_entry(tmp, &c->devices, list)
if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
sysfs_create_link(&tmp->device.kobj,
&i2o_dev->device.kobj, "user");
/* create parent entries for this device */
tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid);
if (tmp)
sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj,
"parent");
/* create parent entries refering to this device */
list_for_each_entry(tmp, &c->devices, list)
if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
sysfs_create_link(&tmp->device.kobj,
&i2o_dev->device.kobj, "parent");
return 0;
};
/* I2O device class interface */
static struct class_interface i2o_device_class_interface = {
.class = &i2o_device_class,
.add = i2o_device_class_add
};
/*
* Run time support routines
*/
/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
*
* This function can be used for all UtilParamsGet/Set operations.
* The OperationList is given in oplist-buffer,
* and results are returned in reslist-buffer.
* Note that the minimum sized reslist is 8 bytes and contains
* ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
*/
int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
int oplen, void *reslist, int reslen)
{
struct i2o_message __iomem *msg;
u32 m;
u32 *res32 = (u32 *) reslist;
u32 *restmp = (u32 *) reslist;
int len = 0;
int i = 0;
int rc;
struct i2o_dma res;
struct i2o_controller *c = i2o_dev->iop;
struct device *dev = &c->pdev->dev;
res.virt = NULL;
if (i2o_dma_alloc(dev, &res, reslen, GFP_KERNEL))
return -ENOMEM;
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY) {
i2o_dma_free(dev, &res);
return -ETIMEDOUT;
}
i = 0;
writel(cmd << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid,
&msg->u.head[1]);
writel(0, &msg->body[i++]);
writel(0x4C000000 | oplen, &msg->body[i++]); /* OperationList */
memcpy_toio(&msg->body[i], oplist, oplen);
i += (oplen / 4 + (oplen % 4 ? 1 : 0));
writel(0xD0000000 | res.len, &msg->body[i++]); /* ResultList */
writel(res.phys, &msg->body[i++]);
writel(I2O_MESSAGE_SIZE(i + sizeof(struct i2o_message) / 4) |
SGL_OFFSET_5, &msg->u.head[0]);
rc = i2o_msg_post_wait_mem(c, m, 10, &res);
/* This only looks like a memory leak - don't "fix" it. */
if (rc == -ETIMEDOUT)
return rc;
memcpy_fromio(reslist, res.virt, res.len);
i2o_dma_free(dev, &res);
/* Query failed */
if (rc)
return rc;
/*
* Calculate number of bytes of Result LIST
* We need to loop through each Result BLOCK and grab the length
*/
restmp = res32 + 1;
len = 1;
for (i = 0; i < (res32[0] & 0X0000FFFF); i++) {
if (restmp[0] & 0x00FF0000) { /* BlockStatus != SUCCESS */
printk(KERN_WARNING
"%s - Error:\n ErrorInfoSize = 0x%02x, "
"BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
(cmd ==
I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" :
"PARAMS_GET", res32[1] >> 24,
(res32[1] >> 16) & 0xFF, res32[1] & 0xFFFF);
/*
* If this is the only request,than we return an error
*/
if ((res32[0] & 0x0000FFFF) == 1) {
return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */
}
}
len += restmp[0] & 0x0000FFFF; /* Length of res BLOCK */
restmp += restmp[0] & 0x0000FFFF; /* Skip to next BLOCK */
}
return (len << 2); /* bytes used by result list */
}
/*
* Query one field group value or a whole scalar group.
*/
int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field,
void *buf, int buflen)
{
u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
u8 resblk[8 + buflen]; /* 8 bytes for header */
int size;
if (field == -1) /* whole group */
opblk[4] = -1;
size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
sizeof(opblk), resblk, sizeof(resblk));
memcpy(buf, resblk + 8, buflen); /* cut off header */
if (size > buflen)
return buflen;
return size;
}
/*
* if oper == I2O_PARAMS_TABLE_GET, get from all rows
* if fieldcount == -1 return all fields
* ibuf and ibuflen are unused (use NULL, 0)
* else return specific fields
* ibuf contains fieldindexes
*
* if oper == I2O_PARAMS_LIST_GET, get from specific rows
* if fieldcount == -1 return all fields
* ibuf contains rowcount, keyvalues
* else return specific fields
* fieldcount is # of fieldindexes
* ibuf contains fieldindexes, rowcount, keyvalues
*
* You could also use directly function i2o_issue_params().
*/
int i2o_parm_table_get(struct i2o_device *dev, int oper, int group,
int fieldcount, void *ibuf, int ibuflen, void *resblk,
int reslen)
{
u16 *opblk;
int size;
size = 10 + ibuflen;
if (size % 4)
size += 4 - size % 4;
opblk = kmalloc(size, GFP_KERNEL);
if (opblk == NULL) {
printk(KERN_ERR "i2o: no memory for query buffer.\n");
return -ENOMEM;
}
opblk[0] = 1; /* operation count */
opblk[1] = 0; /* pad */
opblk[2] = oper;
opblk[3] = group;
opblk[4] = fieldcount;
memcpy(opblk + 5, ibuf, ibuflen); /* other params */
size = i2o_parm_issue(dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
size, resblk, reslen);
kfree(opblk);
if (size > reslen)
return reslen;
return size;
}
/**
* i2o_device_init - Initialize I2O devices
*
* Registers the I2O device class.
*
* Returns 0 on success or negative error code on failure.
*/
int i2o_device_init(void)
{
int rc;
rc = class_register(&i2o_device_class);
if (rc)
return rc;
return class_interface_register(&i2o_device_class_interface);
};
/**
* i2o_device_exit - I2O devices exit function
*
* Unregisters the I2O device class.
*/
void i2o_device_exit(void)
{
class_interface_register(&i2o_device_class_interface);
class_unregister(&i2o_device_class);
};
EXPORT_SYMBOL(i2o_device_claim);
EXPORT_SYMBOL(i2o_device_claim_release);
EXPORT_SYMBOL(i2o_parm_field_get);
EXPORT_SYMBOL(i2o_parm_table_get);
EXPORT_SYMBOL(i2o_parm_issue);

View File

@@ -0,0 +1,374 @@
/*
* Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs
*
* Copyright (C) 2004 Markus Lidel <Markus.Lidel@shadowconnect.com>
*
* 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.
*
* Fixes/additions:
* Markus Lidel <Markus.Lidel@shadowconnect.com>
* initial version.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/rwsem.h>
#include <linux/i2o.h>
/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */
unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
module_param_named(max_drivers, i2o_max_drivers, uint, 0);
MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support");
/* I2O drivers lock and array */
static spinlock_t i2o_drivers_lock;
static struct i2o_driver **i2o_drivers;
/**
* i2o_bus_match - Tell if a I2O device class id match the class ids of
* the I2O driver (OSM)
*
* @dev: device which should be verified
* @drv: the driver to match against
*
* Used by the bus to check if the driver wants to handle the device.
*
* Returns 1 if the class ids of the driver match the class id of the
* device, otherwise 0.
*/
static int i2o_bus_match(struct device *dev, struct device_driver *drv)
{
struct i2o_device *i2o_dev = to_i2o_device(dev);
struct i2o_driver *i2o_drv = to_i2o_driver(drv);
struct i2o_class_id *ids = i2o_drv->classes;
if (ids)
while (ids->class_id != I2O_CLASS_END) {
if (ids->class_id == i2o_dev->lct_data.class_id)
return 1;
ids++;
}
return 0;
};
/* I2O bus type */
struct bus_type i2o_bus_type = {
.name = "i2o",
.match = i2o_bus_match,
};
/**
* i2o_driver_register - Register a I2O driver (OSM) in the I2O core
* @drv: I2O driver which should be registered
*
* Registers the OSM drv in the I2O core and creates an event queues if
* necessary.
*
* Returns 0 on success or negative error code on failure.
*/
int i2o_driver_register(struct i2o_driver *drv)
{
struct i2o_controller *c;
int i;
int rc = 0;
unsigned long flags;
pr_debug("i2o: Register driver %s\n", drv->name);
if (drv->event) {
drv->event_queue = create_workqueue(drv->name);
if (!drv->event_queue) {
printk(KERN_ERR "i2o: Could not initialize event queue "
"for driver %s\n", drv->name);
return -EFAULT;
}
pr_debug("i2o: Event queue initialized for driver %s\n",
drv->name);
} else
drv->event_queue = NULL;
drv->driver.name = drv->name;
drv->driver.bus = &i2o_bus_type;
spin_lock_irqsave(&i2o_drivers_lock, flags);
for (i = 0; i2o_drivers[i]; i++)
if (i >= i2o_max_drivers) {
printk(KERN_ERR "i2o: too many drivers registered, "
"increase max_drivers\n");
spin_unlock_irqrestore(&i2o_drivers_lock, flags);
return -EFAULT;
}
drv->context = i;
i2o_drivers[i] = drv;
spin_unlock_irqrestore(&i2o_drivers_lock, flags);
pr_debug("i2o: driver %s gets context id %d\n", drv->name,
drv->context);
list_for_each_entry(c, &i2o_controllers, list) {
struct i2o_device *i2o_dev;
i2o_driver_notify_controller_add(drv, c);
list_for_each_entry(i2o_dev, &c->devices, list)
i2o_driver_notify_device_add(drv, i2o_dev);
}
rc = driver_register(&drv->driver);
if (rc)
destroy_workqueue(drv->event_queue);
return rc;
};
/**
* i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core
* @drv: I2O driver which should be unregistered
*
* Unregisters the OSM drv from the I2O core and cleanup event queues if
* necessary.
*/
void i2o_driver_unregister(struct i2o_driver *drv)
{
struct i2o_controller *c;
unsigned long flags;
pr_debug("i2o: unregister driver %s\n", drv->name);
driver_unregister(&drv->driver);
list_for_each_entry(c, &i2o_controllers, list) {
struct i2o_device *i2o_dev;
list_for_each_entry(i2o_dev, &c->devices, list)
i2o_driver_notify_device_remove(drv, i2o_dev);
i2o_driver_notify_controller_remove(drv, c);
}
spin_lock_irqsave(&i2o_drivers_lock, flags);
i2o_drivers[drv->context] = NULL;
spin_unlock_irqrestore(&i2o_drivers_lock, flags);
if (drv->event_queue) {
destroy_workqueue(drv->event_queue);
drv->event_queue = NULL;
pr_debug("i2o: event queue removed for %s\n", drv->name);
}
};
/**
* i2o_driver_dispatch - dispatch an I2O reply message
* @c: I2O controller of the message
* @m: I2O message number
* @msg: I2O message to be delivered
*
* The reply is delivered to the driver from which the original message
* was. This function is only called from interrupt context.
*
* Returns 0 on success and the message should not be flushed. Returns > 0
* on success and if the message should be flushed afterwords. Returns
* negative error code on failure (the message will be flushed too).
*/
int i2o_driver_dispatch(struct i2o_controller *c, u32 m,
struct i2o_message __iomem *msg)
{
struct i2o_driver *drv;
u32 context = readl(&msg->u.s.icntxt);
if (likely(context < i2o_max_drivers)) {
spin_lock(&i2o_drivers_lock);
drv = i2o_drivers[context];
spin_unlock(&i2o_drivers_lock);
if (unlikely(!drv)) {
printk(KERN_WARNING "%s: Spurious reply to unknown "
"driver %d\n", c->name, context);
return -EIO;
}
if ((readl(&msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
struct i2o_device *dev, *tmp;
struct i2o_event *evt;
u16 size;
u16 tid;
tid = readl(&msg->u.head[1]) & 0x1fff;
pr_debug("%s: event received from device %d\n", c->name,
tid);
/* cut of header from message size (in 32-bit words) */
size = (readl(&msg->u.head[0]) >> 16) - 5;
evt = kmalloc(size * 4 + sizeof(*evt), GFP_ATOMIC);
if (!evt)
return -ENOMEM;
memset(evt, 0, size * 4 + sizeof(*evt));
evt->size = size;
memcpy_fromio(&evt->tcntxt, &msg->u.s.tcntxt,
(size + 2) * 4);
list_for_each_entry_safe(dev, tmp, &c->devices, list)
if (dev->lct_data.tid == tid) {
evt->i2o_dev = dev;
break;
}
INIT_WORK(&evt->work, (void (*)(void *))drv->event,
evt);
queue_work(drv->event_queue, &evt->work);
return 1;
}
if (likely(drv->reply))
return drv->reply(c, m, msg);
else
pr_debug("%s: Reply to driver %s, but no reply function"
" defined!\n", c->name, drv->name);
return -EIO;
} else
printk(KERN_WARNING "%s: Spurious reply to unknown driver "
"%d\n", c->name, readl(&msg->u.s.icntxt));
return -EIO;
}
/**
* i2o_driver_notify_controller_add_all - Send notify of added controller
* to all I2O drivers
*
* Send notifications to all registered drivers that a new controller was
* added.
*/
void i2o_driver_notify_controller_add_all(struct i2o_controller *c)
{
int i;
struct i2o_driver *drv;
for (i = 0; i < I2O_MAX_DRIVERS; i++) {
drv = i2o_drivers[i];
if (drv)
i2o_driver_notify_controller_add(drv, c);
}
}
/**
* i2o_driver_notify_controller_remove_all - Send notify of removed
* controller to all I2O drivers
*
* Send notifications to all registered drivers that a controller was
* removed.
*/
void i2o_driver_notify_controller_remove_all(struct i2o_controller *c)
{
int i;
struct i2o_driver *drv;
for (i = 0; i < I2O_MAX_DRIVERS; i++) {
drv = i2o_drivers[i];
if (drv)
i2o_driver_notify_controller_remove(drv, c);
}
}
/**
* i2o_driver_notify_device_add_all - Send notify of added device to all
* I2O drivers
*
* Send notifications to all registered drivers that a device was added.
*/
void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev)
{
int i;
struct i2o_driver *drv;
for (i = 0; i < I2O_MAX_DRIVERS; i++) {
drv = i2o_drivers[i];
if (drv)
i2o_driver_notify_device_add(drv, i2o_dev);
}
}
/**
* i2o_driver_notify_device_remove_all - Send notify of removed device to
* all I2O drivers
*
* Send notifications to all registered drivers that a device was removed.
*/
void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev)
{
int i;
struct i2o_driver *drv;
for (i = 0; i < I2O_MAX_DRIVERS; i++) {
drv = i2o_drivers[i];
if (drv)
i2o_driver_notify_device_remove(drv, i2o_dev);
}
}
/**
* i2o_driver_init - initialize I2O drivers (OSMs)
*
* Registers the I2O bus and allocate memory for the array of OSMs.
*
* Returns 0 on success or negative error code on failure.
*/
int __init i2o_driver_init(void)
{
int rc = 0;
spin_lock_init(&i2o_drivers_lock);
if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64) ||
((i2o_max_drivers ^ (i2o_max_drivers - 1)) !=
(2 * i2o_max_drivers - 1))) {
printk(KERN_WARNING "i2o: max_drivers set to %d, but must be "
">=2 and <= 64 and a power of 2\n", i2o_max_drivers);
i2o_max_drivers = I2O_MAX_DRIVERS;
}
printk(KERN_INFO "i2o: max drivers = %d\n", i2o_max_drivers);
i2o_drivers =
kmalloc(i2o_max_drivers * sizeof(*i2o_drivers), GFP_KERNEL);
if (!i2o_drivers)
return -ENOMEM;
memset(i2o_drivers, 0, i2o_max_drivers * sizeof(*i2o_drivers));
rc = bus_register(&i2o_bus_type);
if (rc < 0)
kfree(i2o_drivers);
return rc;
};
/**
* i2o_driver_exit - clean up I2O drivers (OSMs)
*
* Unregisters the I2O bus and free driver array.
*/
void __exit i2o_driver_exit(void)
{
bus_unregister(&i2o_bus_type);
kfree(i2o_drivers);
};
EXPORT_SYMBOL(i2o_driver_register);
EXPORT_SYMBOL(i2o_driver_unregister);
EXPORT_SYMBOL(i2o_driver_notify_controller_add_all);
EXPORT_SYMBOL(i2o_driver_notify_controller_remove_all);
EXPORT_SYMBOL(i2o_driver_notify_device_add_all);
EXPORT_SYMBOL(i2o_driver_notify_device_remove_all);

View File

@@ -0,0 +1,507 @@
/*
* Executive OSM
*
* Copyright (C) 1999-2002 Red Hat Software
*
* Written by Alan Cox, Building Number Three Ltd
*
* 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.
*
* A lot of the I2O message side code from this is taken from the Red
* Creek RCPCI45 adapter driver by Red Creek Communications
*
* Fixes/additions:
* Philipp Rumpf
* Juha Siev<65>nen <Juha.Sievanen@cs.Helsinki.FI>
* Auvo H<>kkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Deepak Saxena <deepak@plexity.net>
* Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
* Alan Cox <alan@redhat.com>:
* Ported to Linux 2.5.
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Minor fixes for 2.6.
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Support for sysfs included.
*/
#include <linux/module.h>
#include <linux/i2o.h>
#include <linux/delay.h>
#define OSM_NAME "exec-osm"
struct i2o_driver i2o_exec_driver;
static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind);
/* Module internal functions from other sources */
extern int i2o_device_parse_lct(struct i2o_controller *);
/* global wait list for POST WAIT */
static LIST_HEAD(i2o_exec_wait_list);
/* Wait struct needed for POST WAIT */
struct i2o_exec_wait {
wait_queue_head_t *wq; /* Pointer to Wait queue */
struct i2o_dma dma; /* DMA buffers to free on failure */
u32 tcntxt; /* transaction context from reply */
int complete; /* 1 if reply received otherwise 0 */
u32 m; /* message id */
struct i2o_message __iomem *msg; /* pointer to the reply message */
struct list_head list; /* node in global wait list */
};
/* Exec OSM class handling definition */
static struct i2o_class_id i2o_exec_class_id[] = {
{I2O_CLASS_EXECUTIVE},
{I2O_CLASS_END}
};
/**
* i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it
*
* Allocate the i2o_exec_wait struct and initialize the wait.
*
* Returns i2o_exec_wait pointer on success or negative error code on
* failure.
*/
static struct i2o_exec_wait *i2o_exec_wait_alloc(void)
{
struct i2o_exec_wait *wait;
wait = kmalloc(sizeof(*wait), GFP_KERNEL);
if (!wait)
return ERR_PTR(-ENOMEM);
memset(wait, 0, sizeof(*wait));
INIT_LIST_HEAD(&wait->list);
return wait;
};
/**
* i2o_exec_wait_free - Free a i2o_exec_wait struct
* @i2o_exec_wait: I2O wait data which should be cleaned up
*/
static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
{
kfree(wait);
};
/**
* i2o_msg_post_wait_mem - Post and wait a message with DMA buffers
* @c: controller
* @m: message to post
* @timeout: time in seconds to wait
* @dma: i2o_dma struct of the DMA buffer to free on failure
*
* This API allows an OSM to post a message and then be told whether or
* not the system received a successful reply. If the message times out
* then the value '-ETIMEDOUT' is returned. This is a special case. In
* this situation the message may (should) complete at an indefinite time
* in the future. When it completes it will use the memory buffer
* attached to the request. If -ETIMEDOUT is returned then the memory
* buffer must not be freed. Instead the event completion will free them
* for you. In all other cases the buffer are your problem.
*
* Returns 0 on success or negative error code on failure.
*/
int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
timeout, struct i2o_dma *dma)
{
DECLARE_WAIT_QUEUE_HEAD(wq);
struct i2o_exec_wait *wait;
static u32 tcntxt = 0x80000000;
struct i2o_message __iomem *msg = c->in_queue.virt + m;
int rc = 0;
wait = i2o_exec_wait_alloc();
if (!wait)
return -ENOMEM;
if (tcntxt == 0xffffffff)
tcntxt = 0x80000000;
if (dma)
wait->dma = *dma;
/*
* Fill in the message initiator context and transaction context.
* We will only use transaction contexts >= 0x80000000 for POST WAIT,
* so we could find a POST WAIT reply easier in the reply handler.
*/
writel(i2o_exec_driver.context, &msg->u.s.icntxt);
wait->tcntxt = tcntxt++;
writel(wait->tcntxt, &msg->u.s.tcntxt);
/*
* Post the message to the controller. At some point later it will
* return. If we time out before it returns then complete will be zero.
*/
i2o_msg_post(c, m);
if (!wait->complete) {
wait->wq = &wq;
/*
* we add elements add the head, because if a entry in the list
* will never be removed, we have to iterate over it every time
*/
list_add(&wait->list, &i2o_exec_wait_list);
wait_event_interruptible_timeout(wq, wait->complete,
timeout * HZ);
wait->wq = NULL;
}
barrier();
if (wait->complete) {
if (readl(&wait->msg->body[0]) >> 24)
rc = readl(&wait->msg->body[0]) & 0xff;
i2o_flush_reply(c, wait->m);
i2o_exec_wait_free(wait);
} else {
/*
* We cannot remove it now. This is important. When it does
* terminate (which it must do if the controller has not
* died...) then it will otherwise scribble on stuff.
*
* FIXME: try abort message
*/
if (dma)
dma->virt = NULL;
rc = -ETIMEDOUT;
}
return rc;
};
/**
* i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP
* @c: I2O controller which answers
* @m: message id
* @msg: pointer to the I2O reply message
*
* This function is called in interrupt context only. If the reply reached
* before the timeout, the i2o_exec_wait struct is filled with the message
* and the task will be waked up. The task is now responsible for returning
* the message m back to the controller! If the message reaches us after
* the timeout clean up the i2o_exec_wait struct (including allocated
* DMA buffer).
*
* Return 0 on success and if the message m should not be given back to the
* I2O controller, or >0 on success and if the message should be given back
* afterwords. Returns negative error code on failure. In this case the
* message must also be given back to the controller.
*/
static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
struct i2o_message __iomem *msg)
{
struct i2o_exec_wait *wait, *tmp;
static spinlock_t lock;
int rc = 1;
u32 context;
spin_lock_init(&lock);
context = readl(&msg->u.s.tcntxt);
/*
* We need to search through the i2o_exec_wait_list to see if the given
* message is still outstanding. If not, it means that the IOP took
* longer to respond to the message than we had allowed and timer has
* already expired. Not much we can do about that except log it for
* debug purposes, increase timeout, and recompile.
*/
spin_lock(&lock);
list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
if (wait->tcntxt == context) {
list_del(&wait->list);
wait->m = m;
wait->msg = msg;
wait->complete = 1;
barrier();
if (wait->wq) {
wake_up_interruptible(wait->wq);
rc = 0;
} else {
struct device *dev;
dev = &c->pdev->dev;
pr_debug("%s: timedout reply received!\n",
c->name);
i2o_dma_free(dev, &wait->dma);
i2o_exec_wait_free(wait);
rc = -1;
}
spin_unlock(&lock);
return rc;
}
}
spin_unlock(&lock);
pr_debug("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
context);
return -1;
};
/**
* i2o_exec_probe - Called if a new I2O device (executive class) appears
* @dev: I2O device which should be probed
*
* Registers event notification for every event from Executive device. The
* return is always 0, because we want all devices of class Executive.
*
* Returns 0 on success.
*/
static int i2o_exec_probe(struct device *dev)
{
struct i2o_device *i2o_dev = to_i2o_device(dev);
i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
i2o_dev->iop->exec = i2o_dev;
return 0;
};
/**
* i2o_exec_remove - Called on I2O device removal
* @dev: I2O device which was removed
*
* Unregisters event notification from Executive I2O device.
*
* Returns 0 on success.
*/
static int i2o_exec_remove(struct device *dev)
{
i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
return 0;
};
/**
* i2o_exec_lct_modified - Called on LCT NOTIFY reply
* @c: I2O controller on which the LCT has modified
*
* This function handles asynchronus LCT NOTIFY replies. It parses the
* new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY
* again.
*/
static void i2o_exec_lct_modified(struct i2o_controller *c)
{
if (i2o_device_parse_lct(c) == -EAGAIN)
i2o_exec_lct_notify(c, 0);
};
/**
* i2o_exec_reply - I2O Executive reply handler
* @c: I2O controller from which the reply comes
* @m: message id
* @msg: pointer to the I2O reply message
*
* This function is always called from interrupt context. If a POST WAIT
* reply was received, pass it to the complete function. If a LCT NOTIFY
* reply was received, a new event is created to handle the update.
*
* Returns 0 on success and if the reply should not be flushed or > 0
* on success and if the reply should be flushed. Returns negative error
* code on failure and if the reply should be flushed.
*/
static int i2o_exec_reply(struct i2o_controller *c, u32 m,
struct i2o_message *msg)
{
if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) { // Fail bit is set
struct i2o_message __iomem *pmsg; /* preserved message */
u32 pm;
pm = le32_to_cpu(msg->body[3]);
pmsg = i2o_msg_in_to_virt(c, pm);
i2o_report_status(KERN_INFO, "i2o_core", msg);
/* Release the preserved msg by resubmitting it as a NOP */
i2o_msg_nop(c, pm);
/* If reply to i2o_post_wait failed, return causes a timeout */
return -1;
}
if (le32_to_cpu(msg->u.s.tcntxt) & 0x80000000)
return i2o_msg_post_wait_complete(c, m, msg);
if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
struct work_struct *work;
pr_debug("%s: LCT notify received\n", c->name);
work = kmalloc(sizeof(*work), GFP_ATOMIC);
if (!work)
return -ENOMEM;
INIT_WORK(work, (void (*)(void *))i2o_exec_lct_modified, c);
queue_work(i2o_exec_driver.event_queue, work);
return 1;
}
/*
* If this happens, we want to dump the message to the syslog so
* it can be sent back to the card manufacturer by the end user
* to aid in debugging.
*
*/
printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
"Message dumped to syslog\n", c->name);
i2o_dump_message(msg);
return -EFAULT;
}
/**
* i2o_exec_event - Event handling function
* @evt: Event which occurs
*
* Handles events send by the Executive device. At the moment does not do
* anything useful.
*/
static void i2o_exec_event(struct i2o_event *evt)
{
osm_info("Event received from device: %d\n",
evt->i2o_dev->lct_data.tid);
kfree(evt);
};
/**
* i2o_exec_lct_get - Get the IOP's Logical Configuration Table
* @c: I2O controller from which the LCT should be fetched
*
* Send a LCT NOTIFY request to the controller, and wait
* I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is
* to large, retry it.
*
* Returns 0 on success or negative error code on failure.
*/
int i2o_exec_lct_get(struct i2o_controller *c)
{
struct i2o_message __iomem *msg;
u32 m;
int i = 0;
int rc = -EAGAIN;
for (i = 1; i <= I2O_LCT_GET_TRIES; i++) {
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
return -ETIMEDOUT;
writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]);
writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID,
&msg->u.head[1]);
writel(0xffffffff, &msg->body[0]);
writel(0x00000000, &msg->body[1]);
writel(0xd0000000 | c->dlct.len, &msg->body[2]);
writel(c->dlct.phys, &msg->body[3]);
rc = i2o_msg_post_wait(c, m, I2O_TIMEOUT_LCT_GET);
if (rc < 0)
break;
rc = i2o_device_parse_lct(c);
if (rc != -EAGAIN)
break;
}
return rc;
}
/**
* i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request
* @c: I2O controller to which the request should be send
* @change_ind: change indicator
*
* This function sends a LCT NOTIFY request to the I2O controller with
* the change indicator change_ind. If the change_ind == 0 the controller
* replies immediately after the request. If change_ind > 0 the reply is
* send after change indicator of the LCT is > change_ind.
*/
static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
{
i2o_status_block *sb = c->status_block.virt;
struct device *dev;
struct i2o_message __iomem *msg;
u32 m;
dev = &c->pdev->dev;
if (i2o_dma_realloc(dev, &c->dlct, sb->expected_lct_size, GFP_KERNEL))
return -ENOMEM;
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
return -ETIMEDOUT;
writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]);
writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID,
&msg->u.head[1]);
writel(i2o_exec_driver.context, &msg->u.s.icntxt);
writel(0, &msg->u.s.tcntxt); /* FIXME */
writel(0xffffffff, &msg->body[0]);
writel(change_ind, &msg->body[1]);
writel(0xd0000000 | c->dlct.len, &msg->body[2]);
writel(c->dlct.phys, &msg->body[3]);
i2o_msg_post(c, m);
return 0;
};
/* Exec OSM driver struct */
struct i2o_driver i2o_exec_driver = {
.name = OSM_NAME,
.reply = i2o_exec_reply,
.event = i2o_exec_event,
.classes = i2o_exec_class_id,
.driver = {
.probe = i2o_exec_probe,
.remove = i2o_exec_remove,
},
};
/**
* i2o_exec_init - Registers the Exec OSM
*
* Registers the Exec OSM in the I2O core.
*
* Returns 0 on success or negative error code on failure.
*/
int __init i2o_exec_init(void)
{
return i2o_driver_register(&i2o_exec_driver);
};
/**
* i2o_exec_exit - Removes the Exec OSM
*
* Unregisters the Exec OSM from the I2O core.
*/
void __exit i2o_exec_exit(void)
{
i2o_driver_unregister(&i2o_exec_driver);
};
EXPORT_SYMBOL(i2o_msg_post_wait_mem);
EXPORT_SYMBOL(i2o_exec_lct_get);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,99 @@
/*
* Block OSM structures/API
*
* Copyright (C) 1999-2002 Red Hat Software
*
* Written by Alan Cox, Building Number Three Ltd
*
* 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 program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* For the purpose of avoiding doubt the preferred form of the work
* for making modifications shall be a standards compliant form such
* gzipped tar and not one requiring a proprietary or patent encumbered
* tool to unpack.
*
* Fixes/additions:
* Steve Ralston:
* Multiple device handling error fixes,
* Added a queue depth.
* Alan Cox:
* FC920 has an rmw bug. Dont or in the end marker.
* Removed queue walk, fixed for 64bitness.
* Rewrote much of the code over time
* Added indirect block lists
* Handle 64K limits on many controllers
* Don't use indirects on the Promise (breaks)
* Heavily chop down the queue depths
* Deepak Saxena:
* Independent queues per IOP
* Support for dynamic device creation/deletion
* Code cleanup
* Support for larger I/Os through merge* functions
* (taken from DAC960 driver)
* Boji T Kannanthanam:
* Set the I2O Block devices to be detected in increasing
* order of TIDs during boot.
* Search and set the I2O block device that we boot off
* from as the first device to be claimed (as /dev/i2o/hda)
* Properly attach/detach I2O gendisk structure from the
* system gendisk list. The I2O block devices now appear in
* /proc/partitions.
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Minor bugfixes for 2.6.
*/
#ifndef I2O_BLOCK_OSM_H
#define I2O_BLOCK_OSM_H
#define I2O_BLOCK_RETRY_TIME HZ/4
#define I2O_BLOCK_MAX_OPEN_REQUESTS 50
/* I2O Block OSM mempool struct */
struct i2o_block_mempool {
kmem_cache_t *slab;
mempool_t *pool;
};
/* I2O Block device descriptor */
struct i2o_block_device {
struct i2o_device *i2o_dev; /* pointer to I2O device */
struct gendisk *gd;
spinlock_t lock; /* queue lock */
struct list_head open_queue; /* list of transfered, but unfinished
requests */
unsigned int open_queue_depth; /* number of requests in the queue */
int rcache; /* read cache flags */
int wcache; /* write cache flags */
int flags;
int power; /* power state */
int media_change_flag; /* media changed flag */
};
/* I2O Block device request */
struct i2o_block_request
{
struct list_head queue;
struct request *req; /* corresponding request */
struct i2o_block_device *i2o_blk_dev; /* I2O block device */
int sg_dma_direction; /* direction of DMA buffer read/write */
int sg_nents; /* number of SG elements */
struct scatterlist sg_table[I2O_MAX_SEGMENTS]; /* SG table */
};
/* I2O Block device delayed request */
struct i2o_block_delayed_request
{
struct work_struct work;
struct request_queue *queue;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,159 @@
/*
* i2o_lan.h I2O LAN Class definitions
*
* I2O LAN CLASS OSM May 26th 2000
*
* (C) Copyright 1999, 2000 University of Helsinki,
* Department of Computer Science
*
* This code is still under development / test.
*
* Author: Auvo H<>kkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Juha Siev<65>nen <Juha.Sievanen@cs.Helsinki.FI>
* Taneli V<>h<EFBFBD>kangas <Taneli.Vahakangas@cs.Helsinki.FI>
*/
#ifndef _I2O_LAN_H
#define _I2O_LAN_H
/* Default values for tunable parameters first */
#define I2O_LAN_MAX_BUCKETS_OUT 96
#define I2O_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */
#define I2O_LAN_RX_COPYBREAK 200
#define I2O_LAN_TX_TIMEOUT (1*HZ)
#define I2O_LAN_TX_BATCH_MODE 2 /* 2=automatic, 1=on, 0=off */
#define I2O_LAN_EVENT_MASK 0 /* 0=None, 0xFFC00002=All */
/* LAN types */
#define I2O_LAN_ETHERNET 0x0030
#define I2O_LAN_100VG 0x0040
#define I2O_LAN_TR 0x0050
#define I2O_LAN_FDDI 0x0060
#define I2O_LAN_FIBRE_CHANNEL 0x0070
#define I2O_LAN_UNKNOWN 0x00000000
/* Connector types */
/* Ethernet */
#define I2O_LAN_AUI (I2O_LAN_ETHERNET << 4) + 0x00000001
#define I2O_LAN_10BASE5 (I2O_LAN_ETHERNET << 4) + 0x00000002
#define I2O_LAN_FIORL (I2O_LAN_ETHERNET << 4) + 0x00000003
#define I2O_LAN_10BASE2 (I2O_LAN_ETHERNET << 4) + 0x00000004
#define I2O_LAN_10BROAD36 (I2O_LAN_ETHERNET << 4) + 0x00000005
#define I2O_LAN_10BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000006
#define I2O_LAN_10BASE_FP (I2O_LAN_ETHERNET << 4) + 0x00000007
#define I2O_LAN_10BASE_FB (I2O_LAN_ETHERNET << 4) + 0x00000008
#define I2O_LAN_10BASE_FL (I2O_LAN_ETHERNET << 4) + 0x00000009
#define I2O_LAN_100BASE_TX (I2O_LAN_ETHERNET << 4) + 0x0000000A
#define I2O_LAN_100BASE_FX (I2O_LAN_ETHERNET << 4) + 0x0000000B
#define I2O_LAN_100BASE_T4 (I2O_LAN_ETHERNET << 4) + 0x0000000C
#define I2O_LAN_1000BASE_SX (I2O_LAN_ETHERNET << 4) + 0x0000000D
#define I2O_LAN_1000BASE_LX (I2O_LAN_ETHERNET << 4) + 0x0000000E
#define I2O_LAN_1000BASE_CX (I2O_LAN_ETHERNET << 4) + 0x0000000F
#define I2O_LAN_1000BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000010
/* AnyLAN */
#define I2O_LAN_100VG_ETHERNET (I2O_LAN_100VG << 4) + 0x00000001
#define I2O_LAN_100VG_TR (I2O_LAN_100VG << 4) + 0x00000002
/* Token Ring */
#define I2O_LAN_4MBIT (I2O_LAN_TR << 4) + 0x00000001
#define I2O_LAN_16MBIT (I2O_LAN_TR << 4) + 0x00000002
/* FDDI */
#define I2O_LAN_125MBAUD (I2O_LAN_FDDI << 4) + 0x00000001
/* Fibre Channel */
#define I2O_LAN_POINT_POINT (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000001
#define I2O_LAN_ARB_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000002
#define I2O_LAN_PUBLIC_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000003
#define I2O_LAN_FABRIC (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000004
#define I2O_LAN_EMULATION 0x00000F00
#define I2O_LAN_OTHER 0x00000F01
#define I2O_LAN_DEFAULT 0xFFFFFFFF
/* LAN class functions */
#define LAN_PACKET_SEND 0x3B
#define LAN_SDU_SEND 0x3D
#define LAN_RECEIVE_POST 0x3E
#define LAN_RESET 0x35
#define LAN_SUSPEND 0x37
/* LAN DetailedStatusCode defines */
#define I2O_LAN_DSC_SUCCESS 0x00
#define I2O_LAN_DSC_DEVICE_FAILURE 0x01
#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x02
#define I2O_LAN_DSC_TRANSMIT_ERROR 0x03
#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x04
#define I2O_LAN_DSC_RECEIVE_ERROR 0x05
#define I2O_LAN_DSC_RECEIVE_ABORTED 0x06
#define I2O_LAN_DSC_DMA_ERROR 0x07
#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x08
#define I2O_LAN_DSC_OUT_OF_MEMORY 0x09
#define I2O_LAN_DSC_BUCKET_OVERRUN 0x0A
#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x0B
#define I2O_LAN_DSC_CANCELED 0x0C
#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x0D
#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED 0x0E
#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED 0x0F
#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x10
#define I2O_LAN_DSC_SUSPENDED 0x11
struct i2o_packet_info {
u32 offset : 24;
u32 flags : 8;
u32 len : 24;
u32 status : 8;
};
struct i2o_bucket_descriptor {
u32 context; /* FIXME: 64bit support */
struct i2o_packet_info packet_info[1];
};
/* Event Indicator Mask Flags for LAN OSM */
#define I2O_LAN_EVT_LINK_DOWN 0x01
#define I2O_LAN_EVT_LINK_UP 0x02
#define I2O_LAN_EVT_MEDIA_CHANGE 0x04
#include <linux/netdevice.h>
#include <linux/fddidevice.h>
struct i2o_lan_local {
u8 unit;
struct i2o_device *i2o_dev;
struct fddi_statistics stats; /* see also struct net_device_stats */
unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
atomic_t buckets_out; /* nbr of unused buckets on DDM */
atomic_t tx_out; /* outstanding TXes */
u8 tx_count; /* packets in one TX message frame */
u16 tx_max_out; /* DDM's Tx queue len */
u8 sgl_max; /* max SGLs in one message frame */
u32 m; /* IOP address of the batch msg frame */
struct work_struct i2o_batch_send_task;
int send_active;
struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */
int i2o_fbl_tail;
spinlock_t fbl_lock;
spinlock_t tx_lock;
u32 max_size_mc_table; /* max number of multicast addresses */
/* LAN OSM configurable parameters are here: */
u16 max_buckets_out; /* max nbr of buckets to send to DDM */
u16 bucket_thresh; /* send more when this many used */
u16 rx_copybreak;
u8 tx_batch_mode; /* Set when using batch mode sends */
u32 i2o_event_mask; /* To turn on interesting event flags */
};
#endif /* _I2O_LAN_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,830 @@
/*
* 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, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* For the avoidance of doubt the "preferred form" of this code is one which
* is in an open non patent encumbered format. Where cryptographic key signing
* forms part of the process of creating an executable the information
* including keys needed to generate an equivalently functional executable
* are deemed to be part of the source code.
*
* Complications for I2O scsi
*
* o Each (bus,lun) is a logical device in I2O. We keep a map
* table. We spoof failed selection for unmapped units
* o Request sense buffers can come back for free.
* o Scatter gather is a bit dynamic. We have to investigate at
* setup time.
* o Some of our resources are dynamically shared. The i2o core
* needs a message reservation protocol to avoid swap v net
* deadlocking. We need to back off queue requests.
*
* In general the firmware wants to help. Where its help isn't performance
* useful we just ignore the aid. Its not worth the code in truth.
*
* Fixes/additions:
* Steve Ralston:
* Scatter gather now works
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Minor fixes for 2.6.
*
* To Do:
* 64bit cleanups
* Fix the resource management problems.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/prefetch.h>
#include <linux/pci.h>
#include <linux/blkdev.h>
#include <linux/i2o.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#define OSM_NAME "scsi-osm"
#define OSM_VERSION "$Rev$"
#define OSM_DESCRIPTION "I2O SCSI Peripheral OSM"
static struct i2o_driver i2o_scsi_driver;
static int i2o_scsi_max_id = 16;
static int i2o_scsi_max_lun = 8;
struct i2o_scsi_host {
struct Scsi_Host *scsi_host; /* pointer to the SCSI host */
struct i2o_controller *iop; /* pointer to the I2O controller */
struct i2o_device *channel[0]; /* channel->i2o_dev mapping table */
};
static struct scsi_host_template i2o_scsi_host_template;
#define I2O_SCSI_CAN_QUEUE 4
/* SCSI OSM class handling definition */
static struct i2o_class_id i2o_scsi_class_id[] = {
{I2O_CLASS_SCSI_PERIPHERAL},
{I2O_CLASS_END}
};
static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
{
struct i2o_scsi_host *i2o_shost;
struct i2o_device *i2o_dev;
struct Scsi_Host *scsi_host;
int max_channel = 0;
u8 type;
int i;
size_t size;
i2o_status_block *sb;
list_for_each_entry(i2o_dev, &c->devices, list)
if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) {
if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1)) /* SCSI bus */
max_channel++;
}
if (!max_channel) {
osm_warn("no channels found on %s\n", c->name);
return ERR_PTR(-EFAULT);
}
size = max_channel * sizeof(struct i2o_device *)
+ sizeof(struct i2o_scsi_host);
scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size);
if (!scsi_host) {
osm_warn("Could not allocate SCSI host\n");
return ERR_PTR(-ENOMEM);
}
scsi_host->max_channel = max_channel - 1;
scsi_host->max_id = i2o_scsi_max_id;
scsi_host->max_lun = i2o_scsi_max_lun;
scsi_host->this_id = c->unit;
sb = c->status_block.virt;
scsi_host->sg_tablesize = (sb->inbound_frame_size -
sizeof(struct i2o_message) / 4 - 6) / 2;
i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata;
i2o_shost->scsi_host = scsi_host;
i2o_shost->iop = c;
i = 0;
list_for_each_entry(i2o_dev, &c->devices, list)
if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) {
if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1)) /* only SCSI bus */
i2o_shost->channel[i++] = i2o_dev;
if (i >= max_channel)
break;
}
return i2o_shost;
};
/**
* i2o_scsi_get_host - Get an I2O SCSI host
* @c: I2O controller to for which to get the SCSI host
*
* If the I2O controller already exists as SCSI host, the SCSI host
* is returned, otherwise the I2O controller is added to the SCSI
* core.
*
* Returns pointer to the I2O SCSI host on success or NULL on failure.
*/
static struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c)
{
return c->driver_data[i2o_scsi_driver.context];
};
/**
* i2o_scsi_remove - Remove I2O device from SCSI core
* @dev: device which should be removed
*
* Removes the I2O device from the SCSI core again.
*
* Returns 0 on success.
*/
static int i2o_scsi_remove(struct device *dev)
{
struct i2o_device *i2o_dev = to_i2o_device(dev);
struct i2o_controller *c = i2o_dev->iop;
struct i2o_scsi_host *i2o_shost;
struct scsi_device *scsi_dev;
i2o_shost = i2o_scsi_get_host(c);
shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
if (scsi_dev->hostdata == i2o_dev) {
scsi_remove_device(scsi_dev);
scsi_device_put(scsi_dev);
break;
}
return 0;
};
/**
* i2o_scsi_probe - verify if dev is a I2O SCSI device and install it
* @dev: device to verify if it is a I2O SCSI device
*
* Retrieve channel, id and lun for I2O device. If everthing goes well
* register the I2O device as SCSI device on the I2O SCSI controller.
*
* Returns 0 on success or negative error code on failure.
*/
static int i2o_scsi_probe(struct device *dev)
{
struct i2o_device *i2o_dev = to_i2o_device(dev);
struct i2o_controller *c = i2o_dev->iop;
struct i2o_scsi_host *i2o_shost;
struct Scsi_Host *scsi_host;
struct i2o_device *parent;
struct scsi_device *scsi_dev;
u32 id;
u64 lun;
int channel = -1;
int i;
i2o_shost = i2o_scsi_get_host(c);
if (!i2o_shost)
return -EFAULT;
scsi_host = i2o_shost->scsi_host;
if (i2o_parm_field_get(i2o_dev, 0, 3, &id, 4) < 0)
return -EFAULT;
if (id >= scsi_host->max_id) {
osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)", id,
scsi_host->max_id);
return -EFAULT;
}
if (i2o_parm_field_get(i2o_dev, 0, 4, &lun, 8) < 0)
return -EFAULT;
if (lun >= scsi_host->max_lun) {
osm_warn("SCSI device id (%d) >= max_lun of I2O host (%d)",
(unsigned int)lun, scsi_host->max_lun);
return -EFAULT;
}
parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
if (!parent) {
osm_warn("can not find parent of device %03x\n",
i2o_dev->lct_data.tid);
return -EFAULT;
}
for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
if (i2o_shost->channel[i] == parent)
channel = i;
if (channel == -1) {
osm_warn("can not find channel of device %03x\n",
i2o_dev->lct_data.tid);
return -EFAULT;
}
scsi_dev =
__scsi_add_device(i2o_shost->scsi_host, channel, id, lun, i2o_dev);
if (!scsi_dev) {
osm_warn("can not add SCSI device %03x\n",
i2o_dev->lct_data.tid);
return -EFAULT;
}
osm_debug("added new SCSI device %03x (cannel: %d, id: %d, lun: %d)\n",
i2o_dev->lct_data.tid, channel, id, (unsigned int)lun);
return 0;
};
static const char *i2o_scsi_info(struct Scsi_Host *SChost)
{
struct i2o_scsi_host *hostdata;
hostdata = (struct i2o_scsi_host *)SChost->hostdata;
return hostdata->iop->name;
}
/**
* i2o_scsi_reply - SCSI OSM message reply handler
* @c: controller issuing the reply
* @m: message id for flushing
* @msg: the message from the controller
*
* Process reply messages (interrupts in normal scsi controller think).
* We can get a variety of messages to process. The normal path is
* scsi command completions. We must also deal with IOP failures,
* the reply to a bus reset and the reply to a LUN query.
*
* Returns 0 on success and if the reply should not be flushed or > 0
* on success and if the reply should be flushed. Returns negative error
* code on failure and if the reply should be flushed.
*/
static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
struct i2o_message *msg)
{
struct scsi_cmnd *cmd;
struct device *dev;
u8 as, ds, st;
cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
if (msg->u.head[0] & (1 << 13)) {
struct i2o_message __iomem *pmsg; /* preserved message */
u32 pm;
int err = DID_ERROR;
pm = le32_to_cpu(msg->body[3]);
pmsg = i2o_msg_in_to_virt(c, pm);
osm_err("IOP fail.\n");
osm_err("From %d To %d Cmd %d.\n",
(msg->u.head[1] >> 12) & 0xFFF,
msg->u.head[1] & 0xFFF, msg->u.head[1] >> 24);
osm_err("Failure Code %d.\n", msg->body[0] >> 24);
if (msg->body[0] & (1 << 16))
osm_err("Format error.\n");
if (msg->body[0] & (1 << 17))
osm_err("Path error.\n");
if (msg->body[0] & (1 << 18))
osm_err("Path State.\n");
if (msg->body[0] & (1 << 18))
{
osm_err("Congestion.\n");
err = DID_BUS_BUSY;
}
osm_debug("Failing message is %p.\n", pmsg);
cmd = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt));
if (!cmd)
return 1;
cmd->result = err << 16;
cmd->scsi_done(cmd);
/* Now flush the message by making it a NOP */
i2o_msg_nop(c, pm);
return 1;
}
/*
* Low byte is device status, next is adapter status,
* (then one byte reserved), then request status.
*/
ds = (u8) le32_to_cpu(msg->body[0]);
as = (u8) (le32_to_cpu(msg->body[0]) >> 8);
st = (u8) (le32_to_cpu(msg->body[0]) >> 24);
/*
* Is this a control request coming back - eg an abort ?
*/
if (!cmd) {
if (st)
osm_warn("SCSI abort: %08X", le32_to_cpu(msg->body[0]));
osm_info("SCSI abort completed.\n");
return -EFAULT;
}
osm_debug("Completed %ld\n", cmd->serial_number);
if (st) {
u32 count, error;
/* An error has occurred */
switch (st) {
case 0x06:
count = le32_to_cpu(msg->body[1]);
if (count < cmd->underflow) {
int i;
osm_err("SCSI underflow 0x%08X 0x%08X\n", count,
cmd->underflow);
osm_debug("Cmd: ");
for (i = 0; i < 15; i++)
pr_debug("%02X ", cmd->cmnd[i]);
pr_debug(".\n");
cmd->result = (DID_ERROR << 16);
}
break;
default:
error = le32_to_cpu(msg->body[0]);
osm_err("SCSI error %08x\n", error);
if ((error & 0xff) == 0x02 /*CHECK_CONDITION */ ) {
int i;
u32 len = sizeof(cmd->sense_buffer);
len = (len > 40) ? 40 : len;
// Copy over the sense data
memcpy(cmd->sense_buffer, (void *)&msg->body[3],
len);
for (i = 0; i <= len; i++)
osm_info("%02x\n",
cmd->sense_buffer[i]);
if (cmd->sense_buffer[0] == 0x70
&& cmd->sense_buffer[2] == DATA_PROTECT) {
/* This is to handle an array failed */
cmd->result = (DID_TIME_OUT << 16);
printk(KERN_WARNING "%s: SCSI Data "
"Protect-Device (%d,%d,%d) "
"hba_status=0x%x, dev_status="
"0x%x, cmd=0x%x\n", c->name,
(u32) cmd->device->channel,
(u32) cmd->device->id,
(u32) cmd->device->lun,
(error >> 8) & 0xff,
error & 0xff, cmd->cmnd[0]);
} else
cmd->result = (DID_ERROR << 16);
break;
}
switch (as) {
case 0x0E:
/* SCSI Reset */
cmd->result = DID_RESET << 16;
break;
case 0x0F:
cmd->result = DID_PARITY << 16;
break;
default:
cmd->result = DID_ERROR << 16;
break;
}
break;
}
cmd->scsi_done(cmd);
return 1;
}
cmd->result = DID_OK << 16 | ds;
cmd->scsi_done(cmd);
dev = &c->pdev->dev;
if (cmd->use_sg)
dma_unmap_sg(dev, (struct scatterlist *)cmd->buffer,
cmd->use_sg, cmd->sc_data_direction);
else if (cmd->request_bufflen)
dma_unmap_single(dev, (dma_addr_t) ((long)cmd->SCp.ptr),
cmd->request_bufflen, cmd->sc_data_direction);
return 1;
};
/**
* i2o_scsi_notify_controller_add - Retrieve notifications of added
* controllers
* @c: the controller which was added
*
* If a I2O controller is added, we catch the notification to add a
* corresponding Scsi_Host.
*/
static void i2o_scsi_notify_controller_add(struct i2o_controller *c)
{
struct i2o_scsi_host *i2o_shost;
int rc;
i2o_shost = i2o_scsi_host_alloc(c);
if (IS_ERR(i2o_shost)) {
osm_err("Could not initialize SCSI host\n");
return;
}
rc = scsi_add_host(i2o_shost->scsi_host, &c->device);
if (rc) {
osm_err("Could not add SCSI host\n");
scsi_host_put(i2o_shost->scsi_host);
return;
}
c->driver_data[i2o_scsi_driver.context] = i2o_shost;
osm_debug("new I2O SCSI host added\n");
};
/**
* i2o_scsi_notify_controller_remove - Retrieve notifications of removed
* controllers
* @c: the controller which was removed
*
* If a I2O controller is removed, we catch the notification to remove the
* corresponding Scsi_Host.
*/
static void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
{
struct i2o_scsi_host *i2o_shost;
i2o_shost = i2o_scsi_get_host(c);
if (!i2o_shost)
return;
c->driver_data[i2o_scsi_driver.context] = NULL;
scsi_remove_host(i2o_shost->scsi_host);
scsi_host_put(i2o_shost->scsi_host);
pr_info("I2O SCSI host removed\n");
};
/* SCSI OSM driver struct */
static struct i2o_driver i2o_scsi_driver = {
.name = OSM_NAME,
.reply = i2o_scsi_reply,
.classes = i2o_scsi_class_id,
.notify_controller_add = i2o_scsi_notify_controller_add,
.notify_controller_remove = i2o_scsi_notify_controller_remove,
.driver = {
.probe = i2o_scsi_probe,
.remove = i2o_scsi_remove,
},
};
/**
* i2o_scsi_queuecommand - queue a SCSI command
* @SCpnt: scsi command pointer
* @done: callback for completion
*
* Issue a scsi command asynchronously. Return 0 on success or 1 if
* we hit an error (normally message queue congestion). The only
* minor complication here is that I2O deals with the device addressing
* so we have to map the bus/dev/lun back to an I2O handle as well
* as faking absent devices ourself.
*
* Locks: takes the controller lock on error path only
*/
static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
void (*done) (struct scsi_cmnd *))
{
struct i2o_controller *c;
struct Scsi_Host *host;
struct i2o_device *i2o_dev;
struct device *dev;
int tid;
struct i2o_message __iomem *msg;
u32 m;
u32 scsi_flags, sg_flags;
u32 __iomem *mptr;
u32 __iomem *lenptr;
u32 len, reqlen;
int i;
/*
* Do the incoming paperwork
*/
i2o_dev = SCpnt->device->hostdata;
host = SCpnt->device->host;
c = i2o_dev->iop;
dev = &c->pdev->dev;
SCpnt->scsi_done = done;
if (unlikely(!i2o_dev)) {
osm_warn("no I2O device in request\n");
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
tid = i2o_dev->lct_data.tid;
osm_debug("qcmd: Tid = %03x\n", tid);
osm_debug("Real scsi messages.\n");
/*
* Obtain an I2O message. If there are none free then
* throw it back to the scsi layer
*/
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
return SCSI_MLQUEUE_HOST_BUSY;
/*
* Put together a scsi execscb message
*/
len = SCpnt->request_bufflen;
switch (SCpnt->sc_data_direction) {
case PCI_DMA_NONE:
scsi_flags = 0x00000000; // DATA NO XFER
sg_flags = 0x00000000;
break;
case PCI_DMA_TODEVICE:
scsi_flags = 0x80000000; // DATA OUT (iop-->dev)
sg_flags = 0x14000000;
break;
case PCI_DMA_FROMDEVICE:
scsi_flags = 0x40000000; // DATA IN (iop<--dev)
sg_flags = 0x10000000;
break;
default:
/* Unknown - kill the command */
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
writel(I2O_CMD_SCSI_EXEC << 24 | HOST_TID << 12 | tid, &msg->u.head[1]);
writel(i2o_scsi_driver.context, &msg->u.s.icntxt);
/* We want the SCSI control block back */
writel(i2o_cntxt_list_add(c, SCpnt), &msg->u.s.tcntxt);
/* LSI_920_PCI_QUIRK
*
* Intermittant observations of msg frame word data corruption
* observed on msg[4] after:
* WRITE, READ-MODIFY-WRITE
* operations. 19990606 -sralston
*
* (Hence we build this word via tag. Its good practice anyway
* we don't want fetches over PCI needlessly)
*/
/* Attach tags to the devices */
/*
if(SCpnt->device->tagged_supported) {
if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
scsi_flags |= 0x01000000;
else if(SCpnt->tag == ORDERED_QUEUE_TAG)
scsi_flags |= 0x01800000;
}
*/
/* Direction, disconnect ok, tag, CDBLen */
writel(scsi_flags | 0x20200000 | SCpnt->cmd_len, &msg->body[0]);
mptr = &msg->body[1];
/* Write SCSI command into the message - always 16 byte block */
memcpy_toio(mptr, SCpnt->cmnd, 16);
mptr += 4;
lenptr = mptr++; /* Remember me - fill in when we know */
reqlen = 12; // SINGLE SGE
/* Now fill in the SGList and command */
if (SCpnt->use_sg) {
struct scatterlist *sg;
int sg_count;
sg = SCpnt->request_buffer;
len = 0;
sg_count = dma_map_sg(dev, sg, SCpnt->use_sg,
SCpnt->sc_data_direction);
if (unlikely(sg_count <= 0))
return -ENOMEM;
for (i = SCpnt->use_sg; i > 0; i--) {
if (i == 1)
sg_flags |= 0xC0000000;
writel(sg_flags | sg_dma_len(sg), mptr++);
writel(sg_dma_address(sg), mptr++);
len += sg_dma_len(sg);
sg++;
}
reqlen = mptr - &msg->u.head[0];
writel(len, lenptr);
} else {
len = SCpnt->request_bufflen;
writel(len, lenptr);
if (len > 0) {
dma_addr_t dma_addr;
dma_addr = dma_map_single(dev, SCpnt->request_buffer,
SCpnt->request_bufflen,
SCpnt->sc_data_direction);
if (!dma_addr)
return -ENOMEM;
SCpnt->SCp.ptr = (void *)(unsigned long)dma_addr;
sg_flags |= 0xC0000000;
writel(sg_flags | SCpnt->request_bufflen, mptr++);
writel(dma_addr, mptr++);
} else
reqlen = 9;
}
/* Stick the headers on */
writel(reqlen << 16 | SGL_OFFSET_10, &msg->u.head[0]);
/* Queue the message */
i2o_msg_post(c, m);
osm_debug("Issued %ld\n", SCpnt->serial_number);
return 0;
};
/**
* i2o_scsi_abort - abort a running command
* @SCpnt: command to abort
*
* Ask the I2O controller to abort a command. This is an asynchrnous
* process and our callback handler will see the command complete with an
* aborted message if it succeeds.
*
* Returns 0 if the command is successfully aborted or negative error code
* on failure.
*/
static int i2o_scsi_abort(struct scsi_cmnd *SCpnt)
{
struct i2o_device *i2o_dev;
struct i2o_controller *c;
struct i2o_message __iomem *msg;
u32 m;
int tid;
int status = FAILED;
osm_warn("Aborting command block.\n");
i2o_dev = SCpnt->device->hostdata;
c = i2o_dev->iop;
tid = i2o_dev->lct_data.tid;
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
return SCSI_MLQUEUE_HOST_BUSY;
writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
writel(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid,
&msg->u.head[1]);
writel(i2o_cntxt_list_get_ptr(c, SCpnt), &msg->body[0]);
if (i2o_msg_post_wait(c, m, I2O_TIMEOUT_SCSI_SCB_ABORT))
status = SUCCESS;
return status;
}
/**
* i2o_scsi_bios_param - Invent disk geometry
* @sdev: scsi device
* @dev: block layer device
* @capacity: size in sectors
* @ip: geometry array
*
* This is anyones guess quite frankly. We use the same rules everyone
* else appears to and hope. It seems to work.
*/
static int i2o_scsi_bios_param(struct scsi_device *sdev,
struct block_device *dev, sector_t capacity,
int *ip)
{
int size;
size = capacity;
ip[0] = 64; /* heads */
ip[1] = 32; /* sectors */
if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */
ip[0] = 255; /* heads */
ip[1] = 63; /* sectors */
ip[2] = size / (255 * 63); /* cylinders */
}
return 0;
}
static struct scsi_host_template i2o_scsi_host_template = {
.proc_name = OSM_NAME,
.name = OSM_DESCRIPTION,
.info = i2o_scsi_info,
.queuecommand = i2o_scsi_queuecommand,
.eh_abort_handler = i2o_scsi_abort,
.bios_param = i2o_scsi_bios_param,
.can_queue = I2O_SCSI_CAN_QUEUE,
.sg_tablesize = 8,
.cmd_per_lun = 6,
.use_clustering = ENABLE_CLUSTERING,
};
/**
* i2o_scsi_init - SCSI OSM initialization function
*
* Register SCSI OSM into I2O core.
*
* Returns 0 on success or negative error code on failure.
*/
static int __init i2o_scsi_init(void)
{
int rc;
printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
/* Register SCSI OSM into I2O core */
rc = i2o_driver_register(&i2o_scsi_driver);
if (rc) {
osm_err("Could not register SCSI driver\n");
return rc;
}
return 0;
};
/**
* i2o_scsi_exit - SCSI OSM exit function
*
* Unregisters SCSI OSM from I2O core.
*/
static void __exit i2o_scsi_exit(void)
{
/* Unregister I2O SCSI OSM from I2O core */
i2o_driver_unregister(&i2o_scsi_driver);
};
MODULE_AUTHOR("Red Hat Software");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(OSM_DESCRIPTION);
MODULE_VERSION(OSM_VERSION);
module_init(i2o_scsi_init);
module_exit(i2o_scsi_exit);

1327
drivers/message/i2o/iop.c Normal file

File diff suppressed because it is too large Load Diff

528
drivers/message/i2o/pci.c Normal file
View File

@@ -0,0 +1,528 @@
/*
* PCI handling of I2O controller
*
* Copyright (C) 1999-2002 Red Hat Software
*
* Written by Alan Cox, Building Number Three Ltd
*
* 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.
*
* A lot of the I2O message side code from this is taken from the Red
* Creek RCPCI45 adapter driver by Red Creek Communications
*
* Fixes/additions:
* Philipp Rumpf
* Juha Siev<65>nen <Juha.Sievanen@cs.Helsinki.FI>
* Auvo H<>kkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Deepak Saxena <deepak@plexity.net>
* Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
* Alan Cox <alan@redhat.com>:
* Ported to Linux 2.5.
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Minor fixes for 2.6.
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Support for sysfs included.
*/
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/i2o.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif // CONFIG_MTRR
/* Module internal functions from other sources */
extern struct i2o_controller *i2o_iop_alloc(void);
extern void i2o_iop_free(struct i2o_controller *);
extern int i2o_iop_add(struct i2o_controller *);
extern void i2o_iop_remove(struct i2o_controller *);
extern int i2o_driver_dispatch(struct i2o_controller *, u32,
struct i2o_message *);
/* PCI device id table for all I2O controllers */
static struct pci_device_id __devinitdata i2o_pci_ids[] = {
{PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)},
{PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)},
{0}
};
/**
* i2o_dma_realloc - Realloc DMA memory
* @dev: struct device pointer to the PCI device of the I2O controller
* @addr: pointer to a i2o_dma struct DMA buffer
* @len: new length of memory
* @gfp_mask: GFP mask
*
* If there was something allocated in the addr, free it first. If len > 0
* than try to allocate it and write the addresses back to the addr
* structure. If len == 0 set the virtual address to NULL.
*
* Returns the 0 on success or negative error code on failure.
*/
int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len,
unsigned int gfp_mask)
{
i2o_dma_free(dev, addr);
if (len)
return i2o_dma_alloc(dev, addr, len, gfp_mask);
return 0;
};
/**
* i2o_pci_free - Frees the DMA memory for the I2O controller
* @c: I2O controller to free
*
* Remove all allocated DMA memory and unmap memory IO regions. If MTRR
* is enabled, also remove it again.
*/
static void i2o_pci_free(struct i2o_controller *c)
{
struct device *dev;
dev = &c->pdev->dev;
i2o_dma_free(dev, &c->out_queue);
i2o_dma_free(dev, &c->status_block);
if (c->lct)
kfree(c->lct);
i2o_dma_free(dev, &c->dlct);
i2o_dma_free(dev, &c->hrt);
i2o_dma_free(dev, &c->status);
#ifdef CONFIG_MTRR
if (c->mtrr_reg0 >= 0)
mtrr_del(c->mtrr_reg0, 0, 0);
if (c->mtrr_reg1 >= 0)
mtrr_del(c->mtrr_reg1, 0, 0);
#endif
if (c->raptor && c->in_queue.virt)
iounmap(c->in_queue.virt);
if (c->base.virt)
iounmap(c->base.virt);
}
/**
* i2o_pci_alloc - Allocate DMA memory, map IO memory for I2O controller
* @c: I2O controller
*
* Allocate DMA memory for a PCI (or in theory AGP) I2O controller. All
* IO mappings are also done here. If MTRR is enabled, also do add memory
* regions here.
*
* Returns 0 on success or negative error code on failure.
*/
static int __devinit i2o_pci_alloc(struct i2o_controller *c)
{
struct pci_dev *pdev = c->pdev;
struct device *dev = &pdev->dev;
int i;
for (i = 0; i < 6; i++) {
/* Skip I/O spaces */
if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
if (!c->base.phys) {
c->base.phys = pci_resource_start(pdev, i);
c->base.len = pci_resource_len(pdev, i);
/*
* If we know what card it is, set the size
* correctly. Code is taken from dpt_i2o.c
*/
if (pdev->device == 0xa501) {
if (pdev->subsystem_device >= 0xc032 &&
pdev->subsystem_device <= 0xc03b) {
if (c->base.len > 0x400000)
c->base.len = 0x400000;
} else {
if (c->base.len > 0x100000)
c->base.len = 0x100000;
}
}
if (!c->raptor)
break;
} else {
c->in_queue.phys = pci_resource_start(pdev, i);
c->in_queue.len = pci_resource_len(pdev, i);
break;
}
}
}
if (i == 6) {
printk(KERN_ERR "%s: I2O controller has no memory regions"
" defined.\n", c->name);
i2o_pci_free(c);
return -EINVAL;
}
/* Map the I2O controller */
if (c->raptor) {
printk(KERN_INFO "%s: PCI I2O controller\n", c->name);
printk(KERN_INFO " BAR0 at 0x%08lX size=%ld\n",
(unsigned long)c->base.phys, (unsigned long)c->base.len);
printk(KERN_INFO " BAR1 at 0x%08lX size=%ld\n",
(unsigned long)c->in_queue.phys,
(unsigned long)c->in_queue.len);
} else
printk(KERN_INFO "%s: PCI I2O controller at %08lX size=%ld\n",
c->name, (unsigned long)c->base.phys,
(unsigned long)c->base.len);
c->base.virt = ioremap(c->base.phys, c->base.len);
if (!c->base.virt) {
printk(KERN_ERR "%s: Unable to map controller.\n", c->name);
return -ENOMEM;
}
if (c->raptor) {
c->in_queue.virt = ioremap(c->in_queue.phys, c->in_queue.len);
if (!c->in_queue.virt) {
printk(KERN_ERR "%s: Unable to map controller.\n",
c->name);
i2o_pci_free(c);
return -ENOMEM;
}
} else
c->in_queue = c->base;
c->irq_mask = c->base.virt + 0x34;
c->post_port = c->base.virt + 0x40;
c->reply_port = c->base.virt + 0x44;
#ifdef CONFIG_MTRR
/* Enable Write Combining MTRR for IOP's memory region */
c->mtrr_reg0 = mtrr_add(c->in_queue.phys, c->in_queue.len,
MTRR_TYPE_WRCOMB, 1);
c->mtrr_reg1 = -1;
if (c->mtrr_reg0 < 0)
printk(KERN_WARNING "%s: could not enable write combining "
"MTRR\n", c->name);
else
printk(KERN_INFO "%s: using write combining MTRR\n", c->name);
/*
* If it is an INTEL i960 I/O processor then set the first 64K to
* Uncacheable since the region contains the messaging unit which
* shouldn't be cached.
*/
if ((pdev->vendor == PCI_VENDOR_ID_INTEL ||
pdev->vendor == PCI_VENDOR_ID_DPT) && !c->raptor) {
printk(KERN_INFO "%s: MTRR workaround for Intel i960 processor"
"\n", c->name);
c->mtrr_reg1 = mtrr_add(c->base.phys, 0x10000,
MTRR_TYPE_UNCACHABLE, 1);
if (c->mtrr_reg1 < 0) {
printk(KERN_WARNING "%s: Error in setting "
"MTRR_TYPE_UNCACHABLE\n", c->name);
mtrr_del(c->mtrr_reg0, c->in_queue.phys,
c->in_queue.len);
c->mtrr_reg0 = -1;
}
}
#endif
if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) {
i2o_pci_free(c);
return -ENOMEM;
}
if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt), GFP_KERNEL)) {
i2o_pci_free(c);
return -ENOMEM;
}
if (i2o_dma_alloc(dev, &c->dlct, 8192, GFP_KERNEL)) {
i2o_pci_free(c);
return -ENOMEM;
}
if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block),
GFP_KERNEL)) {
i2o_pci_free(c);
return -ENOMEM;
}
if (i2o_dma_alloc(dev, &c->out_queue, MSG_POOL_SIZE, GFP_KERNEL)) {
i2o_pci_free(c);
return -ENOMEM;
}
pci_set_drvdata(pdev, c);
return 0;
}
/**
* i2o_pci_interrupt - Interrupt handler for I2O controller
* @irq: interrupt line
* @dev_id: pointer to the I2O controller
* @r: pointer to registers
*
* Handle an interrupt from a PCI based I2O controller. This turns out
* to be rather simple. We keep the controller pointer in the cookie.
*/
static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
{
struct i2o_controller *c = dev_id;
struct device *dev = &c->pdev->dev;
struct i2o_message *m;
u32 mv;
/*
* Old 960 steppings had a bug in the I2O unit that caused
* the queue to appear empty when it wasn't.
*/
mv = I2O_REPLY_READ32(c);
if (mv == I2O_QUEUE_EMPTY) {
mv = I2O_REPLY_READ32(c);
if (unlikely(mv == I2O_QUEUE_EMPTY)) {
return IRQ_NONE;
} else
pr_debug("%s: 960 bug detected\n", c->name);
}
while (mv != I2O_QUEUE_EMPTY) {
/*
* Map the message from the page frame map to kernel virtual.
* Because bus_to_virt is deprecated, we have calculate the
* location by ourself!
*/
m = i2o_msg_out_to_virt(c, mv);
/*
* Ensure this message is seen coherently but cachably by
* the processor
*/
dma_sync_single_for_cpu(dev, mv, MSG_FRAME_SIZE * 4,
PCI_DMA_FROMDEVICE);
/* dispatch it */
if (i2o_driver_dispatch(c, mv, m))
/* flush it if result != 0 */
i2o_flush_reply(c, mv);
/*
* That 960 bug again...
*/
mv = I2O_REPLY_READ32(c);
if (mv == I2O_QUEUE_EMPTY)
mv = I2O_REPLY_READ32(c);
}
return IRQ_HANDLED;
}
/**
* i2o_pci_irq_enable - Allocate interrupt for I2O controller
*
* Allocate an interrupt for the I2O controller, and activate interrupts
* on the I2O controller.
*
* Returns 0 on success or negative error code on failure.
*/
static int i2o_pci_irq_enable(struct i2o_controller *c)
{
struct pci_dev *pdev = c->pdev;
int rc;
I2O_IRQ_WRITE32(c, 0xffffffff);
if (pdev->irq) {
rc = request_irq(pdev->irq, i2o_pci_interrupt, SA_SHIRQ,
c->name, c);
if (rc < 0) {
printk(KERN_ERR "%s: unable to allocate interrupt %d."
"\n", c->name, pdev->irq);
return rc;
}
}
I2O_IRQ_WRITE32(c, 0x00000000);
printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq);
return 0;
}
/**
* i2o_pci_irq_disable - Free interrupt for I2O controller
* @c: I2O controller
*
* Disable interrupts in I2O controller and then free interrupt.
*/
static void i2o_pci_irq_disable(struct i2o_controller *c)
{
I2O_IRQ_WRITE32(c, 0xffffffff);
if (c->pdev->irq > 0)
free_irq(c->pdev->irq, c);
}
/**
* i2o_pci_probe - Probe the PCI device for an I2O controller
* @dev: PCI device to test
* @id: id which matched with the PCI device id table
*
* Probe the PCI device for any device which is a memory of the
* Intelligent, I2O class or an Adaptec Zero Channel Controller. We
* attempt to set up each such device and register it with the core.
*
* Returns 0 on success or negative error code on failure.
*/
static int __devinit i2o_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct i2o_controller *c;
int rc;
printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
if ((pdev->class & 0xff) > 1) {
printk(KERN_WARNING "i2o: I2O controller found but does not "
"support I2O 1.5 (skipping).\n");
return -ENODEV;
}
if ((rc = pci_enable_device(pdev))) {
printk(KERN_WARNING "i2o: I2O controller found but could not be"
" enabled.\n");
return rc;
}
printk(KERN_INFO "i2o: I2O controller found on bus %d at %d.\n",
pdev->bus->number, pdev->devfn);
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "i2o: I2O controller on bus %d at %d: No "
"suitable DMA available!\n", pdev->bus->number,
pdev->devfn);
rc = -ENODEV;
goto disable;
}
pci_set_master(pdev);
c = i2o_iop_alloc();
if (IS_ERR(c)) {
printk(KERN_ERR "i2o: memory for I2O controller could not be "
"allocated\n");
rc = PTR_ERR(c);
goto disable;
}
c->pdev = pdev;
c->device = pdev->dev;
/* Cards that fall apart if you hit them with large I/O loads... */
if (pdev->vendor == PCI_VENDOR_ID_NCR && pdev->device == 0x0630) {
c->short_req = 1;
printk(KERN_INFO "%s: Symbios FC920 workarounds activated.\n",
c->name);
}
if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) {
c->promise = 1;
printk(KERN_INFO "%s: Promise workarounds activated.\n",
c->name);
}
/* Cards that go bananas if you quiesce them before you reset them. */
if (pdev->vendor == PCI_VENDOR_ID_DPT) {
c->no_quiesce = 1;
if (pdev->device == 0xa511)
c->raptor = 1;
}
if ((rc = i2o_pci_alloc(c))) {
printk(KERN_ERR "%s: DMA / IO allocation for I2O controller "
" failed\n", c->name);
goto free_controller;
}
if (i2o_pci_irq_enable(c)) {
printk(KERN_ERR "%s: unable to enable interrupts for I2O "
"controller\n", c->name);
goto free_pci;
}
if ((rc = i2o_iop_add(c)))
goto uninstall;
return 0;
uninstall:
i2o_pci_irq_disable(c);
free_pci:
i2o_pci_free(c);
free_controller:
i2o_iop_free(c);
disable:
pci_disable_device(pdev);
return rc;
}
/**
* i2o_pci_remove - Removes a I2O controller from the system
* pdev: I2O controller which should be removed
*
* Reset the I2O controller, disable interrupts and remove all allocated
* resources.
*/
static void __devexit i2o_pci_remove(struct pci_dev *pdev)
{
struct i2o_controller *c;
c = pci_get_drvdata(pdev);
i2o_iop_remove(c);
i2o_pci_irq_disable(c);
i2o_pci_free(c);
printk(KERN_INFO "%s: Controller removed.\n", c->name);
i2o_iop_free(c);
pci_disable_device(pdev);
};
/* PCI driver for I2O controller */
static struct pci_driver i2o_pci_driver = {
.name = "I2O controller",
.id_table = i2o_pci_ids,
.probe = i2o_pci_probe,
.remove = __devexit_p(i2o_pci_remove),
};
/**
* i2o_pci_init - registers I2O PCI driver in PCI subsystem
*
* Returns > 0 on success or negative error code on failure.
*/
int __init i2o_pci_init(void)
{
return pci_register_driver(&i2o_pci_driver);
};
/**
* i2o_pci_exit - unregisters I2O PCI driver from PCI subsystem
*/
void __exit i2o_pci_exit(void)
{
pci_unregister_driver(&i2o_pci_driver);
};
EXPORT_SYMBOL(i2o_dma_realloc);
MODULE_DEVICE_TABLE(pci, i2o_pci_ids);