Commit b46aedbc authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://ppc.bkbits.net/for-linus-ppc

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 20917119 f347cc1b
......@@ -27,8 +27,7 @@ refers to this file. With the appropriate DocBook toolset, this permits
users to generate html, ps and pdf renderings of information within this
file (e.g. the interface functions).
This version of the document was written in the period when lk 2.5.47
was current.
This version of the document roughly matches lk 2.5.50 .
Driver structure
================
......@@ -43,9 +42,9 @@ under the drivers/scsi directory.
When a new LLD is being added to Linux, the following files (found in the
drivers/scsi directory) will need some attention: Makefile, Config.help and
Config.in . SCSI documentation is in the process of being moved to the
Documentation/scsi directory in the kernel source tree. It is probably best
to study how existing LLDs are organized.
Config.in . SCSI documentation is found in the Documentation/scsi directory
of the kernel source tree. It is probably best to study how existing LLDs
are organized.
As the 2.5 series development kernels evolve, changes are being
introduced into this interface. An example of this is driver
......@@ -75,11 +74,10 @@ Those functions in group b) are listed in a section entitled "Interface
functions" below. The function pointers are placed in the members of
"struct SHT", an instance of which is passed to scsi_register() [or
scsi_register_host() in the passive initialization model]. Those interface
functions that are not mandatory and that the LLD does
not wish to supply should have NULL placed in the corresponding member
of struct SHT. [Defining an instance of struct SHT at file scope will
cause NULL to be placed in function pointer members not explicitly
initialized.]
functions that are not mandatory and that the LLD does not wish to supply
should have NULL placed in the corresponding member of struct SHT.
[Defining an instance of struct SHT at file scope will cause NULL to be
placed in function pointer members not explicitly initialized.]
Those instances in group c) are slowly being removed as they tend to be
"racy" especially in a hotplug environment.
......@@ -87,42 +85,53 @@ Those instances in group c) are slowly being removed as they tend to be
Hotplug initialization model
============================
In this model a LLD controls when SCSI hosts are introduced
and removed from the SCSI subsystem. Hosts can be introduced as early as
driver initialization and removed as late as driver shutdown. Typically
a driver will respond to a sysfs probe() callback that indicates a
HBA is present (e.g. a PCI device). After confirming it is a device that
it wants to control, it will initialize the HBA and then register a new
host with the SCSI mid level.
In this model a LLD controls when SCSI hosts are introduced and removed
from the SCSI subsystem. Hosts can be introduced as early as driver
initialization and removed as late as driver shutdown. Typically a driver
will respond to a sysfs probe() callback that indicates a HBA is present
(e.g. a PCI device). After confirming it is a device that it wants to
control, it will initialize the HBA and then register a new host with the
SCSI mid level.
Hot unplugging a HBA that controls a disk which is processing SCSI
commands on a mounted file system is an ugly situation. Issues with
this scenario are still being worked through. The primary concern in
this scenario are still being worked through. The primary concern is
the stability of the kernel (specifically the block and SCSI subsystems)
since the effected disk can be "cleaned up" the next time it is seen.
During LLD initialization the driver should register
itself with the appropriate IO bus that it expects to find HBA(s)
(e.g. the PCI bus). This can probably be done via sysfs (formerly known
as driverfs). Any driver parameters (especially those that are writeable
after the driver is loaded) could also be registered with sysfs at
this point. At the end of driver initialization the SCSI mid level is
typically not aware of its presence.
During LLD initialization the driver should register itself with the
appropriate IO bus that it expects to find HBA(s) (e.g. the PCI bus). This
can probably be done via sysfs (formerly known as driverfs). Any driver
parameters (especially those that are writeable after the driver is
loaded) could also be registered with sysfs at this point. At the end of
driver initialization the SCSI mid level is typically not aware of its
presence.
At some later time, the LLD becomes aware of a HBA and what follows
is a typical sequence of calls (for 3 discovered SCSI devices)
between the LLD and the mid level.
is a typical sequence of calls between the LLD and the mid level.
This example shows 3 devices being found and 1 device not being found:
LLD mid level LLD
--- --------- ---
scsi_register() -->
scsi_add_host() --------+
|
slave_attach() --> scsi_adjust_queue_depth()
slave_attach() --> scsi_adjust_queue_depth()
slave_attach() --> scsi_adjust_queue_depth()
The invocation of scsi_adjust_queue_depth() by the LLD is optional.
slave_alloc()
slave_configure() --> scsi_adjust_queue_depth()
|
slave_alloc()
slave_configure() --> scsi_adjust_queue_depth()
|
slave_alloc()
slave_configure() --> scsi_adjust_queue_depth()
|
slave_alloc() **
slave_destroy() **
The invocation of scsi_adjust_queue_depth() by the LLD is required
if slave_configure() is supplied.
** For scsi devices that the mid level tries to scan but do not
respond, a slave_alloc(), slave_destroy() pair is called.
Here is the corresponding sequence when a host (HBA) is being
removed:
......@@ -131,29 +140,29 @@ LLD mid level
--- ---------
scsi_remove_host() -----+
|
slave_detach()
slave_detach()
slave_detach()
slave_destroy()
slave_destroy()
slave_destroy()
scsi_unregister() -->
It is practical for a LLD to keep track of struct Scsi_Host instances
(a pointer is returned by scsi_register() ) and struct scsi_device
instances (a pointer is passed as the parameter to slave_attach() ).
Both classes of instances are "owned" by the mid-level. struct scsi_devices
instances are freed after slave_detach(). struct Scsi_Host instances
are freed after scsi_unregister().
instances (a pointer is passed as the parameter to slave_alloc() and
slave_configure() ). Both classes of instances are "owned" by the
mid-level. struct scsi_devices instances are freed after slave_destroy().
struct Scsi_Host instances are freed after scsi_unregister().
Passive initialization model
============================
LLD initialization (both built-in and module) and shutdown and "wired
LLD initialization (both built-in and module) and shutdown are "wired
up" by passing function pointers to the module_init() and module_exit()
macros respectively. In this model the function identified by "module_init"
must call scsi_register_host() and the function identified by "module_exit"
must call scsi_unregister_host().
Most LLDs inherited from the lk 2.4 series include a file called
"scsi_module.c" [yes the ".c" is a little surprising] in their
source code. For it to work a declaration like this is needed before
source code. For that file to work a declaration like this is needed before
it is included:
static struct SHT driver_template = DRIVER_TEMPLATE;
#include "scsi_module.c"
......@@ -164,7 +173,7 @@ pointers to supported interface functions and other values.
Here is an example of an initialization sequence when two hosts are
detected (so detect() returns 2) and the SCSI bus scan on each host
finds 3 SCSI devices.
finds 1 SCSI device (and a second device does not respond).
LLD mid level LLD
--- --------- ---
......@@ -175,17 +184,21 @@ scsi_register_host() -------+
| scsi_register()
| scsi_register()
|
slave_attach() --> scsi_adjust_queue_depth()
slave_attach() --> scsi_adjust_queue_depth()
slave_attach() --> scsi_adjust_queue_depth()
slave_alloc()
slave_configure() --> scsi_adjust_queue_depth()
slave_alloc() **
slave_destroy() **
|
slave_attach() --> scsi_adjust_queue_depth()
slave_attach() --> scsi_adjust_queue_depth()
slave_attach() --> scsi_adjust_queue_depth()
slave_alloc()
slave_configure() --> scsi_adjust_queue_depth()
slave_alloc() **
slave_destroy() **
If the LLD does not supply a slave_attach() then the mid level invokes
If the LLD does not supply a slave_configure() then the mid level invokes
scsi_adjust_queue_depth() itself with tagged queuing off and "cmd_per_lun"
for that host as the third parameter.
for that host as the queue length.
** For scsi devices that the mid level tries to scan but do not
respond, a slave_alloc(), slave_destroy() pair is called.
Here is a LLD shutdown sequence:
......@@ -193,17 +206,13 @@ LLD mid level LLD
--- --------- ---
scsi_unregister_host() -----+
|
slave_detach()
slave_detach()
slave_detach()
slave_destroy()
release() --> scsi_unregister()
|
slave_detach()
slave_detach()
slave_detach()
slave_destroy()
release() --> scsi_unregister()
Both slave_detach() and release() are optional. If they are not supplied
Both slave_destroy() and release() are optional. If they are not supplied
the mid level supplies default actions.
The shortcoming of the "passive initialization model" is that host
......@@ -215,8 +224,7 @@ driver shutdown and re-initialization.
Conventions
===========
First there is Linus's thoughts on C coding found in file
Documentation/CodingStyle .
First Linus's thoughts on C coding found in file Documentation/CodingStyle .
Next there is a movement to "outlaw" typedefs introducing synonyms for
struct tags. Both can be still found in the SCSI subsystem, for example:
......@@ -264,9 +272,10 @@ int scsi_add_host(struct Scsi_Host *shost)
* Returns nothing
*
* Notes: Can be invoked any time on a SCSI device controlled by this
* LLD. [Specifically after slave_attach() and prior to slave_detach().]
* Can safely be invoked from interrupt code. Actual queue depth change
* may be delayed until the next command is being processed.
* LLD. [Specifically during and after slave_configure() and prior to
* slave_destroy().] Can safely be invoked from interrupt code. Actual
* queue depth change may be delayed until the next command is being
* processed.
* Defined in drivers/scsi/scsi.c [see source code for more notes]
*
**/
......@@ -471,11 +480,11 @@ Interface functions are supplied (defined) by LLDs and
their function pointers are placed in an instance of struct SHT which
is passed to scsi_register() [or scsi_register_host()]. Some
are mandatory. Interface functions should be declared static. The
accepted convention is that driver "xyz" will declare its slave_attach()
accepted convention is that driver "xyz" will declare its slave_configure()
function as:
static int xyz_slave_attach(struct scsi_device * sdev);
static int xyz_slave_configure(struct scsi_device * sdev);
A pointer to this function should be placed in the 'slave_attach' member
A pointer to this function should be placed in the 'slave_configure' member
of a "struct SHT" instance. A pointer to such an instance should
passed to the mid level's scsi_register() [or scsi_register_host()].
......@@ -787,13 +796,37 @@ int proc_info(char * buffer, char ** start, off_t offset,
/**
* slave_attach - driver fine tuning for give device just after it
* has been first scan (i.e. it responded to an
* slave_alloc - prior to any commands being sent to a new device
* (i.e. just prior to scan) this call is made
* @sdp: pointer to new device (about to be scanned)
*
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*
* Required: no
*
* Locks: none
*
* Notes: Allows the driver to allocate any resources for a device
* prior to its initial scan. The corresponding scsi device may not
* exist but the mid level is just about to scan for it (i.e. send
* and INQUIRY command plus ...). If a device is found then
* slave_configure() will be called while if a device is not found
* slave_destroy() is called.
* For more details see the hosts.h file.
**/
int slave_alloc(struct scsi_device *sdp);
/**
* slave_configure - driver fine tuning for give device just after it
* has been first scanned (i.e. it responded to an
* INQUIRY)
* @sdp: device that has just been attached
*
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is taken offline.
* the device is taken offline. [offline devices will _not_ have
* slave_destroy() called on them so clean up resources.]
*
* Required: no
*
......@@ -805,16 +838,16 @@ int proc_info(char * buffer, char ** start, off_t offset,
* If this function is not supplied, the mid level will call
* scsi_adjust_queue_depth() with the struct Scsi_Host::cmd_per_lun
* value on behalf of the given device. If this function is
* supplied then its implementation is expected to call
* supplied then its implementation must call
* scsi_adjust_queue_depth().
**/
int slave_attach(struct scsi_device *sdp);
int slave_configure(struct scsi_device *sdp);
/**
* slave_detach - given device is about to be shut down. No further
* commands will be sent.
* @sdp: device that is about to be detached
* slave_destroy - given device is about to be shut down. All
* activity has ceased on this device.
* @sdp: device that is about to be shut down
*
* Returns nothing
*
......@@ -827,10 +860,10 @@ int proc_info(char * buffer, char ** start, off_t offset,
* by this driver for given device should be freed now. No further
* commands will be sent for this sdp instance. [However the device
* could be re-attached in the future in which case a new instance
* of struct scsi_device would be supplied by a future slave_attach()
* call.]
* of struct scsi_device would be supplied by future slave_alloc()
* and slave_configure() calls.]
**/
void slave_detach(struct scsi_device *sdp);
void slave_destroy(struct scsi_device *sdp);
......@@ -958,7 +991,7 @@ subsystems in the Documentation/Configure.help file. In the 2.5 series,
the SCSI subsystem now has its own (much smaller) drivers/scsi/Config.help
file.
Addition of slave_attach() and slave_detach().
Addition of slave_alloc(), slave_configure() and slave_destroy().
Addition of the "hotplug initialization model".
......@@ -970,8 +1003,9 @@ The following people have contributed to this document:
James Bottomley <James.Bottomley@steeleye.com>
Patrick Mansfield <patmans@us.ibm.com>
Christoph Hellwig <hch@infradead.org>
Doug Ledford <dledford@redhat.com>
Douglas Gilbert
dgilbert@interlog.com
17th November 2002
29th November 2002
......@@ -1108,6 +1108,8 @@ config MCA
<file:Documentation/mca.txt> (and especially the web page given
there) before attempting to build an MCA bus kernel.
source "drivers/mca/Kconfig"
config HOTPLUG
bool "Support for hot-pluggable devices"
---help---
......
......@@ -54,54 +54,7 @@
#include <linux/init.h>
#include <asm/arch_hooks.h>
/* This structure holds MCA information. Each (plug-in) adapter has
* eight POS registers. Then the machine may have integrated video and
* SCSI subsystems, which also have eight POS registers.
* Finally, the motherboard (planar) has got POS-registers.
* Other miscellaneous information follows.
*/
typedef enum {
MCA_ADAPTER_NORMAL = 0,
MCA_ADAPTER_NONE = 1,
MCA_ADAPTER_DISABLED = 2,
MCA_ADAPTER_ERROR = 3
} MCA_AdapterStatus;
struct MCA_adapter {
MCA_AdapterStatus status; /* is there a valid adapter? */
int id; /* adapter id value */
unsigned char pos[8]; /* POS registers */
int driver_loaded; /* is there a driver installed? */
/* 0 - No, 1 - Yes */
char name[48]; /* adapter-name provided by driver */
char procname[8]; /* name of /proc/mca file */
MCA_ProcFn procfn; /* /proc info callback */
void* dev; /* device/context info for callback */
};
struct MCA_info {
/* one for each of the 8 possible slots, plus one for integrated SCSI
* and one for integrated video.
*/
struct MCA_adapter slot[MCA_NUMADAPTERS];
/* two potential addresses for integrated SCSI adapter - this will
* track which one we think it is.
*/
unsigned char which_scsi;
};
/* The mca_info structure pointer. If MCA bus is present, the function
* mca_probe() is invoked. The function puts motherboard, then all
* adapters into setup mode, allocates and fills an MCA_info structure,
* and points this pointer to the structure. Otherwise the pointer
* is set to zero.
*/
static struct MCA_info* mca_info = NULL;
static unsigned char which_scsi = 0;
/*
* Motherboard register spinlock. Untested on SMP at the moment, but
......@@ -109,33 +62,17 @@ static struct MCA_info* mca_info = NULL;
*
* Yes - Alan
*/
static spinlock_t mca_lock = SPIN_LOCK_UNLOCKED;
/* MCA registers */
#define MCA_MOTHERBOARD_SETUP_REG 0x94
#define MCA_ADAPTER_SETUP_REG 0x96
#define MCA_POS_REG(n) (0x100+(n))
#define MCA_ENABLED 0x01 /* POS 2, set if adapter enabled */
/*--------------------------------------------------------------------*/
#ifdef CONFIG_PROC_FS
static void mca_do_proc_init(void);
#endif
/*--------------------------------------------------------------------*/
spinlock_t mca_lock = SPIN_LOCK_UNLOCKED;
/* Build the status info for the adapter */
static void mca_configure_adapter_status(int slot) {
mca_info->slot[slot].status = MCA_ADAPTER_NONE;
static void mca_configure_adapter_status(struct mca_device *mca_dev) {
mca_dev->status = MCA_ADAPTER_NONE;
mca_info->slot[slot].id = mca_info->slot[slot].pos[0]
+ (mca_info->slot[slot].pos[1] << 8);
mca_dev->pos_id = mca_dev->pos[0]
+ (mca_dev->pos[1] << 8);
if(!mca_info->slot[slot].id && slot < MCA_MAX_SLOT_NR) {
if(!mca_dev->pos_id && mca_dev->slot < MCA_MAX_SLOT_NR) {
/* id = 0x0000 usually indicates hardware failure,
* however, ZP Gu (zpg@castle.net> reports that his 9556
......@@ -145,10 +82,10 @@ static void mca_configure_adapter_status(int slot) {
* however, this code will stay.
*/
mca_info->slot[slot].status = MCA_ADAPTER_ERROR;
mca_dev->status = MCA_ADAPTER_ERROR;
return;
} else if(mca_info->slot[slot].id != 0xffff) {
} else if(mca_dev->pos_id != 0xffff) {
/* 0xffff usually indicates that there's no adapter,
* however, some integrated adapters may have 0xffff as
......@@ -157,26 +94,26 @@ static void mca_configure_adapter_status(int slot) {
* and possibly also the 95 ULTIMEDIA.
*/
mca_info->slot[slot].status = MCA_ADAPTER_NORMAL;
mca_dev->status = MCA_ADAPTER_NORMAL;
}
if((mca_info->slot[slot].id == 0xffff ||
mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR) {
if((mca_dev->pos_id == 0xffff ||
mca_dev->pos_id == 0x0000) && mca_dev->slot >= MCA_MAX_SLOT_NR) {
int j;
for(j = 2; j < 8; j++) {
if(mca_info->slot[slot].pos[j] != 0xff) {
mca_info->slot[slot].status = MCA_ADAPTER_NORMAL;
if(mca_dev->pos[j] != 0xff) {
mca_dev->status = MCA_ADAPTER_NORMAL;
break;
}
}
}
if(!(mca_info->slot[slot].pos[2] & MCA_ENABLED)) {
if(!(mca_dev->pos[2] & MCA_ENABLED)) {
/* enabled bit is in POS 2 */
mca_info->slot[slot].status = MCA_ADAPTER_DISABLED;
mca_dev->status = MCA_ADAPTER_DISABLED;
}
} /* mca_configure_adapter_status */
......@@ -194,366 +131,51 @@ struct resource mca_standard_resources[] = {
#define MCA_STANDARD_RESOURCES (sizeof(mca_standard_resources)/sizeof(struct resource))
int __init mca_init(void)
{
unsigned int i, j;
/* WARNING: Be careful when making changes here. Putting an adapter
* and the motherboard simultaneously into setup mode may result in
* damage to chips (according to The Indispensible PC Hardware Book
* by Hans-Peter Messmer). Also, we disable system interrupts (so
* that we are not disturbed in the middle of this).
*/
/* Make sure the MCA bus is present */
if(!MCA_bus)
return -ENODEV;
printk(KERN_INFO "Micro Channel bus detected.\n");
/* Allocate MCA_info structure (at address divisible by 8) */
mca_info = (struct MCA_info *)kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
if(mca_info == NULL) {
printk(KERN_ERR "Failed to allocate memory for mca_info!");
return -ENOMEM;
}
memset(mca_info, 0, sizeof(struct MCA_info));
/*
* We do not expect many MCA interrupts during initialization,
* but let us be safe:
*/
spin_lock_irq(&mca_lock);
/* Make sure adapter setup is off */
outb_p(0, MCA_ADAPTER_SETUP_REG);
/* Read motherboard POS registers */
outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG);
mca_info->slot[MCA_MOTHERBOARD].name[0] = 0;
for(j=0; j<8; j++) {
mca_info->slot[MCA_MOTHERBOARD].pos[j] = inb_p(MCA_POS_REG(j));
}
mca_configure_adapter_status(MCA_MOTHERBOARD);
/* Put motherboard into video setup mode, read integrated video
* POS registers, and turn motherboard setup off.
*/
outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG);
mca_info->slot[MCA_INTEGVIDEO].name[0] = 0;
for(j=0; j<8; j++) {
mca_info->slot[MCA_INTEGVIDEO].pos[j] = inb_p(MCA_POS_REG(j));
}
mca_configure_adapter_status(MCA_INTEGVIDEO);
/* Put motherboard into scsi setup mode, read integrated scsi
* POS registers, and turn motherboard setup off.
*
* It seems there are two possible SCSI registers. Martin says that
* for the 56,57, 0xf7 is the one, but fails on the 76.
* Alfredo (apena@vnet.ibm.com) says
* 0xfd works on his machine. We'll try both of them. I figure it's
* a good bet that only one could be valid at a time. This could
* screw up though if one is used for something else on the other
* machine.
*/
outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG);
mca_info->slot[MCA_INTEGSCSI].name[0] = 0;
for(j=0; j<8; j++) {
if((mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff)
{
/* 0xff all across means no device. 0x00 means
* something's broken, but a device is probably there.
* However, if you get 0x00 from a motherboard
* register it won't matter what we find. For the
* record, on the 57SLC, the integrated SCSI
* adapter has 0xffff for the adapter ID, but
* nonzero for other registers.
*/
mca_info->which_scsi = 0xf7;
}
}
if(!mca_info->which_scsi) {
/* Didn't find it at 0xf7, try somewhere else... */
mca_info->which_scsi = 0xfd;
outb_p(0xfd, MCA_MOTHERBOARD_SETUP_REG);
for(j=0; j<8; j++)
mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j));
}
mca_configure_adapter_status(MCA_INTEGSCSI);
/* Turn off motherboard setup */
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
/* Now loop over MCA slots: put each adapter into setup mode, and
* read its POS registers. Then put adapter setup off.
*/
for(i=0; i<MCA_MAX_SLOT_NR; i++) {
outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG);
for(j=0; j<8; j++) {
mca_info->slot[i].pos[j]=inb_p(MCA_POS_REG(j));
}
mca_info->slot[i].name[0] = 0;
mca_info->slot[i].driver_loaded = 0;
mca_configure_adapter_status(i);
}
outb_p(0, MCA_ADAPTER_SETUP_REG);
/* Enable interrupts and return memory start */
spin_unlock_irq(&mca_lock);
for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
request_resource(&ioport_resource, mca_standard_resources + i);
#ifdef CONFIG_PROC_FS
mca_do_proc_init();
#endif
return 0;
}
subsys_initcall(mca_init);
/*--------------------------------------------------------------------*/
static void mca_handle_nmi_slot(int slot, int check_flag)
{
if(slot < MCA_MAX_SLOT_NR) {
printk(KERN_CRIT "NMI: caused by MCA adapter in slot %d (%s)\n", slot+1,
mca_info->slot[slot].name);
} else if(slot == MCA_INTEGSCSI) {
printk(KERN_CRIT "NMI: caused by MCA integrated SCSI adapter (%s)\n",
mca_info->slot[slot].name);
} else if(slot == MCA_INTEGVIDEO) {
printk(KERN_CRIT "NMI: caused by MCA integrated video adapter (%s)\n",
mca_info->slot[slot].name);
} else if(slot == MCA_MOTHERBOARD) {
printk(KERN_CRIT "NMI: caused by motherboard (%s)\n",
mca_info->slot[slot].name);
}
/* More info available in POS 6 and 7? */
if(check_flag) {
unsigned char pos6, pos7;
pos6 = mca_read_pos(slot, 6);
pos7 = mca_read_pos(slot, 7);
printk(KERN_CRIT "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7);
}
} /* mca_handle_nmi_slot */
/*--------------------------------------------------------------------*/
void mca_handle_nmi(void)
{
int i;
unsigned char pos5;
/* First try - scan the various adapters and see if a specific
* adapter was responsible for the error.
*/
for(i = 0; i < MCA_NUMADAPTERS; i++)
{
/* Bit 7 of POS 5 is reset when this adapter has a hardware
* error. Bit 7 it reset if there's error information
* available in POS 6 and 7.
*/
pos5 = mca_read_pos(i, 5);
if(!(pos5 & 0x80)) {
mca_handle_nmi_slot(i, !(pos5 & 0x40));
return;
}
}
mca_nmi_hook();
} /* mca_handle_nmi */
/*--------------------------------------------------------------------*/
/**
* mca_find_adapter - scan for adapters
* @id: MCA identification to search for
* @start: starting slot
* mca_read_pos - read the POS registers into a memory buffer
*
* Search the MCA configuration for adapters matching the 16bit
* ID given. The first time it should be called with start as zero
* and then further calls made passing the return value of the
* previous call until %MCA_NOTFOUND is returned.
*
* Disabled adapters are not reported.
*/
int mca_find_adapter(int id, int start)
{
if(mca_info == NULL || id == 0xffff) {
return MCA_NOTFOUND;
}
for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
/* Not sure about this. There's no point in returning
* adapters that aren't enabled, since they can't actually
* be used. However, they might be needed for statistical
* purposes or something... But if that is the case, the
* user is free to write a routine that manually iterates
* through the adapters.
*/
if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED) {
continue;
}
if(id == mca_info->slot[start].id) {
return start;
}
}
return MCA_NOTFOUND;
} /* mca_find_adapter() */
EXPORT_SYMBOL(mca_find_adapter);
/*--------------------------------------------------------------------*/
/**
* mca_find_unused_adapter - scan for unused adapters
* @id: MCA identification to search for
* @start: starting slot
*
* Search the MCA configuration for adapters matching the 16bit
* ID given. The first time it should be called with start as zero
* and then further calls made passing the return value of the
* previous call until %MCA_NOTFOUND is returned.
*
* Adapters that have been claimed by drivers and those that
* are disabled are not reported. This function thus allows a driver
* to scan for further cards when some may already be driven.
* Returns 1 if a card actually exists (i.e. the pos isn't
* all 0xff) or 0 otherwise
*/
static int mca_read_and_store_pos(unsigned char *pos) {
int j;
int found = 0;
int mca_find_unused_adapter(int id, int start)
{
if(mca_info == NULL || id == 0xffff) {
return MCA_NOTFOUND;
}
for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
/* not sure about this. There's no point in returning
* adapters that aren't enabled, since they can't actually
* be used. However, they might be needed for statistical
* purposes or something... But if that is the case, the
* user is free to write a routine that manually iterates
* through the adapters.
*/
if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED ||
mca_info->slot[start].driver_loaded) {
continue;
}
if(id == mca_info->slot[start].id) {
return start;
for(j=0; j<8; j++) {
if((pos[j] = inb_p(MCA_POS_REG(j))) != 0xff) {
/* 0xff all across means no device. 0x00 means
* something's broken, but a device is
* probably there. However, if you get 0x00
* from a motherboard register it won't matter
* what we find. For the record, on the
* 57SLC, the integrated SCSI adapter has
* 0xffff for the adapter ID, but nonzero for
* other registers. */
found = 1;
}
}
return found;
}
return MCA_NOTFOUND;
} /* mca_find_unused_adapter() */
EXPORT_SYMBOL(mca_find_unused_adapter);
/*--------------------------------------------------------------------*/
/**
* mca_read_stored_pos - read POS register from boot data
* @slot: slot number to read from
* @reg: register to read from
*
* Fetch a POS value that was stored at boot time by the kernel
* when it scanned the MCA space. The register value is returned.
* Missing or invalid registers report 0.
*/
unsigned char mca_read_stored_pos(int slot, int reg)
{
if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
if(reg < 0 || reg >= 8) return 0;
return mca_info->slot[slot].pos[reg];
} /* mca_read_stored_pos() */
EXPORT_SYMBOL(mca_read_stored_pos);
/*--------------------------------------------------------------------*/
/**
* mca_read_pos - read POS register from card
* @slot: slot number to read from
* @reg: register to read from
*
* Fetch a POS value directly from the hardware to obtain the
* current value. This is much slower than mca_read_stored_pos and
* may not be invoked from interrupt context. It handles the
* deep magic required for onboard devices transparently.
*/
unsigned char mca_read_pos(int slot, int reg)
static unsigned char mca_pc_read_pos(struct mca_device *mca_dev, int reg)
{
unsigned int byte = 0;
unsigned char byte;
unsigned long flags;
if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
if(reg < 0 || reg >= 8) return 0;
if(reg < 0 || reg >= 8)
return 0;
spin_lock_irqsave(&mca_lock, flags);
/* Make sure motherboard setup is off */
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
/* Read in the appropriate register */
if(slot == MCA_INTEGSCSI && mca_info->which_scsi) {
/* Disable adapter setup, enable motherboard setup */
outb_p(0, MCA_ADAPTER_SETUP_REG);
outb_p(mca_info->which_scsi, MCA_MOTHERBOARD_SETUP_REG);
byte = inb_p(MCA_POS_REG(reg));
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
} else if(slot == MCA_INTEGVIDEO) {
if(mca_dev->pos_register) {
/* Disable adapter setup, enable motherboard setup */
outb_p(0, MCA_ADAPTER_SETUP_REG);
outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG);
outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
byte = inb_p(MCA_POS_REG(reg));
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
} else if(slot == MCA_MOTHERBOARD) {
/* Disable adapter setup, enable motherboard setup */
outb_p(0, MCA_ADAPTER_SETUP_REG);
outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG);
byte = inb_p(MCA_POS_REG(reg));
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
} else if(slot < MCA_MAX_SLOT_NR) {
} else {
/* Make sure motherboard setup is off */
......@@ -561,58 +183,24 @@ unsigned char mca_read_pos(int slot, int reg)
/* Read the appropriate register */
outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG);
outb_p(0x8|(mca_dev->slot & 0xf), MCA_ADAPTER_SETUP_REG);
byte = inb_p(MCA_POS_REG(reg));
outb_p(0, MCA_ADAPTER_SETUP_REG);
}
/* Make sure the stored values are consistent, while we're here */
mca_info->slot[slot].pos[reg] = byte;
spin_unlock_irqrestore(&mca_lock, flags);
return byte;
} /* mca_read_pos() */
EXPORT_SYMBOL(mca_read_pos);
mca_dev->pos[reg] = byte;
/*--------------------------------------------------------------------*/
/**
* mca_write_pos - read POS register from card
* @slot: slot number to read from
* @reg: register to read from
* @byte: byte to write to the POS registers
*
* Store a POS value directly from the hardware. You should not
* normally need to use this function and should have a very good
* knowledge of MCA bus before you do so. Doing this wrongly can
* damage the hardware.
*
* This function may not be used from interrupt context.
*
* Note that this a technically a Bad Thing, as IBM tech stuff says
* you should only set POS values through their utilities.
* However, some devices such as the 3c523 recommend that you write
* back some data to make sure the configuration is consistent.
* I'd say that IBM is right, but I like my drivers to work.
*
* This function can't do checks to see if multiple devices end up
* with the same resources, so you might see magic smoke if someone
* screws up.
*/
return byte;
}
void mca_write_pos(int slot, int reg, unsigned char byte)
static void mca_pc_write_pos(struct mca_device *mca_dev, int reg,
unsigned char byte)
{
unsigned long flags;
if(slot < 0 || slot >= MCA_MAX_SLOT_NR)
return;
if(reg < 0 || reg >= 8)
return;
if(mca_info == NULL)
return;
spin_lock_irqsave(&mca_lock, flags);
......@@ -622,7 +210,7 @@ void mca_write_pos(int slot, int reg, unsigned char byte)
/* Read in the appropriate register */
outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG);
outb_p(0x8|(mca_dev->slot&0xf), MCA_ADAPTER_SETUP_REG);
outb_p(byte, MCA_POS_REG(reg));
outb_p(0, MCA_ADAPTER_SETUP_REG);
......@@ -630,356 +218,250 @@ void mca_write_pos(int slot, int reg, unsigned char byte)
/* Update the global register list, while we have the byte */
mca_info->slot[slot].pos[reg] = byte;
} /* mca_write_pos() */
EXPORT_SYMBOL(mca_write_pos);
mca_dev->pos[reg] = byte;
/*--------------------------------------------------------------------*/
/**
* mca_set_adapter_name - Set the description of the card
* @slot: slot to name
* @name: text string for the namen
*
* This function sets the name reported via /proc for this
* adapter slot. This is for user information only. Setting a
* name deletes any previous name.
*/
void mca_set_adapter_name(int slot, char* name)
{
if(mca_info == NULL) return;
if(slot >= 0 && slot < MCA_NUMADAPTERS) {
if(name != NULL) {
strncpy(mca_info->slot[slot].name, name,
sizeof(mca_info->slot[slot].name)-1);
mca_info->slot[slot].name[
sizeof(mca_info->slot[slot].name)-1] = 0;
} else {
mca_info->slot[slot].name[0] = 0;
}
}
}
EXPORT_SYMBOL(mca_set_adapter_name);
/**
* mca_set_adapter_procfn - Set the /proc callback
* @slot: slot to configure
* @procfn: callback function to call for /proc
* @dev: device information passed to the callback
*
* This sets up an information callback for /proc/mca/slot?. The
* function is called with the buffer, slot, and device pointer (or
* some equally informative context information, or nothing, if you
* prefer), and is expected to put useful information into the
* buffer. The adapter name, ID, and POS registers get printed
* before this is called though, so don't do it again.
*
* This should be called with a %NULL @procfn when a module
* unregisters, thus preventing kernel crashes and other such
* nastiness.
*/
void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* dev)
/* for the primary MCA bus, we have identity transforms */
static int mca_dummy_transform_irq(struct mca_device * mca_dev, int irq)
{
if(mca_info == NULL) return;
if(slot >= 0 && slot < MCA_NUMADAPTERS) {
mca_info->slot[slot].procfn = procfn;
mca_info->slot[slot].dev = dev;
}
return irq;
}
EXPORT_SYMBOL(mca_set_adapter_procfn);
/**
* mca_is_adapter_used - check if claimed by driver
* @slot: slot to check
*
* Returns 1 if the slot has been claimed by a driver
*/
int mca_is_adapter_used(int slot)
static int mca_dummy_transform_ioport(struct mca_device * mca_dev, int port)
{
return mca_info->slot[slot].driver_loaded;
return port;
}
EXPORT_SYMBOL(mca_is_adapter_used);
/**
* mca_mark_as_used - claim an MCA device
* @slot: slot to claim
* FIXME: should we make this threadsafe
*
* Claim an MCA slot for a device driver. If the
* slot is already taken the function returns 1,
* if it is not taken it is claimed and 0 is
* returned.
*/
int mca_mark_as_used(int slot)
static void *mca_dummy_transform_memory(struct mca_device * mca_dev, void *mem)
{
if(mca_info->slot[slot].driver_loaded) return 1;
mca_info->slot[slot].driver_loaded = 1;
return 0;
return mem;
}
EXPORT_SYMBOL(mca_mark_as_used);
/**
* mca_mark_as_unused - release an MCA device
* @slot: slot to claim
*
* Release the slot for other drives to use.
*/
void mca_mark_as_unused(int slot)
static int __init mca_init(void)
{
mca_info->slot[slot].driver_loaded = 0;
}
EXPORT_SYMBOL(mca_mark_as_unused);
unsigned int i, j;
struct mca_device *mca_dev;
unsigned char pos[8];
short mca_builtin_scsi_ports[] = {0xf7, 0xfd, 0x00};
struct mca_bus *bus;
/**
* mca_get_adapter_name - get the adapter description
* @slot: slot to query
*
* Return the adapter description if set. If it has not been
* set or the slot is out range then return NULL.
*/
/* WARNING: Be careful when making changes here. Putting an adapter
* and the motherboard simultaneously into setup mode may result in
* damage to chips (according to The Indispensible PC Hardware Book
* by Hans-Peter Messmer). Also, we disable system interrupts (so
* that we are not disturbed in the middle of this).
*/
char *mca_get_adapter_name(int slot)
{
if(mca_info == NULL) return 0;
/* Make sure the MCA bus is present */
if(slot >= 0 && slot < MCA_NUMADAPTERS) {
return mca_info->slot[slot].name;
}
if(!MCA_bus)
return -ENODEV;
return 0;
}
printk(KERN_INFO "Micro Channel bus detected.\n");
EXPORT_SYMBOL(mca_get_adapter_name);
if(mca_system_init()) {
printk(KERN_ERR "MCA bus system initialisation failed\n");
return -ENODEV;
}
/**
* mca_isadapter - check if the slot holds an adapter
* @slot: slot to query
*
* Returns zero if the slot does not hold an adapter, non zero if
* it does.
*/
/* All MCA systems have at least a primary bus */
bus = mca_attach_bus(MCA_PRIMARY_BUS);
bus->default_dma_mask = 0xffffffffLL;
bus->f.mca_write_pos = mca_pc_write_pos;
bus->f.mca_read_pos = mca_pc_read_pos;
bus->f.mca_transform_irq = mca_dummy_transform_irq;
bus->f.mca_transform_ioport = mca_dummy_transform_ioport;
bus->f.mca_transform_memory = mca_dummy_transform_memory;
/* get the motherboard device */
mca_dev = kmalloc(sizeof(struct mca_device), GFP_KERNEL);
if(unlikely(!mca_dev))
goto out_nomem;
memset(mca_dev, 0, sizeof(struct mca_device));
int mca_isadapter(int slot)
{
if(mca_info == NULL) return 0;
/*
* We do not expect many MCA interrupts during initialization,
* but let us be safe:
*/
spin_lock_irq(&mca_lock);
if(slot >= 0 && slot < MCA_NUMADAPTERS) {
return ((mca_info->slot[slot].status == MCA_ADAPTER_NORMAL)
|| (mca_info->slot[slot].status == MCA_ADAPTER_DISABLED));
}
/* Make sure adapter setup is off */
return 0;
}
outb_p(0, MCA_ADAPTER_SETUP_REG);
EXPORT_SYMBOL(mca_isadapter);
/* Read motherboard POS registers */
mca_dev->pos_register = 0x7f;
outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
mca_dev->dev.name[0] = 0;
mca_read_and_store_pos(mca_dev->pos);
mca_configure_adapter_status(mca_dev);
/* fake POS and slot for a motherboard */
mca_dev->pos_id = MCA_MOTHERBOARD_POS;
mca_dev->slot = MCA_MOTHERBOARD;
mca_register_device(MCA_PRIMARY_BUS, mca_dev);
/**
* mca_isadapter - check if the slot holds an adapter
* @slot: slot to query
*
* Returns a non zero value if the slot holds an enabled adapter
* and zero for any other case.
*/
mca_dev = kmalloc(sizeof(struct mca_device), GFP_ATOMIC);
if(unlikely(!mca_dev))
goto out_unlock_nomem;
memset(mca_dev, 0, sizeof(struct mca_device));
int mca_isenabled(int slot)
{
if(mca_info == NULL) return 0;
if(slot >= 0 && slot < MCA_NUMADAPTERS) {
return (mca_info->slot[slot].status == MCA_ADAPTER_NORMAL);
}
/* Put motherboard into video setup mode, read integrated video
* POS registers, and turn motherboard setup off.
*/
return 0;
}
mca_dev->pos_register = 0xdf;
outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
mca_dev->dev.name[0] = 0;
mca_read_and_store_pos(mca_dev->pos);
mca_configure_adapter_status(mca_dev);
/* fake POS and slot for the integrated video */
mca_dev->pos_id = MCA_INTEGVIDEO_POS;
mca_dev->slot = MCA_INTEGVIDEO;
mca_register_device(MCA_PRIMARY_BUS, mca_dev);
EXPORT_SYMBOL(mca_isenabled);
/* Put motherboard into scsi setup mode, read integrated scsi
* POS registers, and turn motherboard setup off.
*
* It seems there are two possible SCSI registers. Martin says that
* for the 56,57, 0xf7 is the one, but fails on the 76.
* Alfredo (apena@vnet.ibm.com) says
* 0xfd works on his machine. We'll try both of them. I figure it's
* a good bet that only one could be valid at a time. This could
* screw up though if one is used for something else on the other
* machine.
*/
/*--------------------------------------------------------------------*/
for(i = 0; (which_scsi = mca_builtin_scsi_ports[i]) != 0; i++) {
outb_p(which_scsi, MCA_MOTHERBOARD_SETUP_REG);
if(mca_read_and_store_pos(pos))
break;
}
if(which_scsi) {
/* found a scsi card */
mca_dev = kmalloc(sizeof(struct mca_device), GFP_ATOMIC);
if(unlikely(!mca_dev))
goto out_unlock_nomem;
memset(mca_dev, 0, sizeof(struct mca_device));
for(j = 0; j < 8; j++)
mca_dev->pos[j] = pos[j];
mca_configure_adapter_status(mca_dev);
/* fake POS and slot for integrated SCSI controller */
mca_dev->pos_id = MCA_INTEGSCSI_POS;
mca_dev->slot = MCA_INTEGSCSI;
mca_dev->pos_register = which_scsi;
mca_register_device(MCA_PRIMARY_BUS, mca_dev);
}
#ifdef CONFIG_PROC_FS
/* Turn off motherboard setup */
int get_mca_info(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int i, j, len = 0;
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
if(MCA_bus && mca_info != NULL) {
/* Format POS registers of eight MCA slots */
/* Now loop over MCA slots: put each adapter into setup mode, and
* read its POS registers. Then put adapter setup off.
*/
for(i=0; i<MCA_MAX_SLOT_NR; i++) {
len += sprintf(page+len, "Slot %d: ", i+1);
for(j=0; j<8; j++)
len += sprintf(page+len, "%02x ", mca_info->slot[i].pos[j]);
len += sprintf(page+len, " %s\n", mca_info->slot[i].name);
}
for(i=0; i<MCA_MAX_SLOT_NR; i++) {
outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG);
if(!mca_read_and_store_pos(pos))
continue;
/* Format POS registers of integrated video subsystem */
mca_dev = kmalloc(sizeof(struct mca_device), GFP_ATOMIC);
if(unlikely(!mca_dev))
goto out_unlock_nomem;
memset(mca_dev, 0, sizeof(struct mca_device));
len += sprintf(page+len, "Video : ");
for(j=0; j<8; j++)
len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGVIDEO].pos[j]);
len += sprintf(page+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name);
mca_dev->pos[j]=pos[j];
/* Format POS registers of integrated SCSI subsystem */
mca_dev->driver_loaded = 0;
mca_dev->slot = i;
mca_dev->pos_register = 0;
mca_configure_adapter_status(mca_dev);
mca_register_device(MCA_PRIMARY_BUS, mca_dev);
}
outb_p(0, MCA_ADAPTER_SETUP_REG);
len += sprintf(page+len, "SCSI : ");
for(j=0; j<8; j++)
len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGSCSI].pos[j]);
len += sprintf(page+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name);
/* Enable interrupts and return memory start */
spin_unlock_irq(&mca_lock);
/* Format POS registers of motherboard */
for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
request_resource(&ioport_resource, mca_standard_resources + i);
len += sprintf(page+len, "Planar: ");
for(j=0; j<8; j++)
len += sprintf(page+len, "%02x ", mca_info->slot[MCA_MOTHERBOARD].pos[j]);
len += sprintf(page+len, " %s\n", mca_info->slot[MCA_MOTHERBOARD].name);
} else {
/* Leave it empty if MCA not detected - this should *never*
* happen!
*/
}
mca_do_proc_init();
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
return len;
return 0;
out_unlock_nomem:
spin_unlock_irq(&mca_lock);
out_nomem:
printk(KERN_EMERG "Failed memory allocation in MCA setup!\n");
return -ENOMEM;
}
subsys_initcall(mca_init);
/*--------------------------------------------------------------------*/
static int mca_default_procfn(char* buf, struct MCA_adapter *p)
static void mca_handle_nmi_device(struct mca_device *mca_dev, int check_flag)
{
int len = 0, i;
int slot = p - mca_info->slot;
/* Print out the basic information */
int slot = mca_dev->slot;
if(slot < MCA_MAX_SLOT_NR) {
len += sprintf(buf+len, "Slot: %d\n", slot+1);
} else if(slot == MCA_INTEGSCSI) {
len += sprintf(buf+len, "Integrated SCSI Adapter\n");
if(slot == MCA_INTEGSCSI) {
printk(KERN_CRIT "NMI: caused by MCA integrated SCSI adapter (%s)\n",
mca_dev->dev.name);
} else if(slot == MCA_INTEGVIDEO) {
len += sprintf(buf+len, "Integrated Video Adapter\n");
printk(KERN_CRIT "NMI: caused by MCA integrated video adapter (%s)\n",
mca_dev->dev.name);
} else if(slot == MCA_MOTHERBOARD) {
len += sprintf(buf+len, "Motherboard\n");
}
if(p->name[0]) {
/* Drivers might register a name without /proc handler... */
len += sprintf(buf+len, "Adapter Name: %s\n",
p->name);
} else {
len += sprintf(buf+len, "Adapter Name: Unknown\n");
}
len += sprintf(buf+len, "Id: %02x%02x\n",
p->pos[1], p->pos[0]);
len += sprintf(buf+len, "Enabled: %s\nPOS: ",
mca_isenabled(slot) ? "Yes" : "No");
for(i=0; i<8; i++) {
len += sprintf(buf+len, "%02x ", p->pos[i]);
printk(KERN_CRIT "NMI: caused by motherboard (%s)\n",
mca_dev->dev.name);
}
len += sprintf(buf+len, "\nDriver Installed: %s",
mca_is_adapter_used(slot) ? "Yes" : "No");
buf[len++] = '\n';
buf[len] = 0;
return len;
} /* mca_default_procfn() */
static int get_mca_machine_info(char* page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
len += sprintf(page+len, "Model Id: 0x%x\n", machine_id);
len += sprintf(page+len, "Submodel Id: 0x%x\n", machine_submodel_id);
len += sprintf(page+len, "BIOS Revision: 0x%x\n", BIOS_revision);
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
return len;
}
static int mca_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
struct MCA_adapter *p = (struct MCA_adapter *)data;
int len = 0;
/* Get the standard info */
/* More info available in POS 6 and 7? */
len = mca_default_procfn(page, p);
if(check_flag) {
unsigned char pos6, pos7;
/* Do any device-specific processing, if there is any */
pos6 = mca_device_read_pos(mca_dev, 6);
pos7 = mca_device_read_pos(mca_dev, 7);
if(p->procfn) {
len += p->procfn(page+len, p-mca_info->slot, p->dev);
printk(KERN_CRIT "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7);
}
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
return len;
} /* mca_read_proc() */
} /* mca_handle_nmi_slot */
/*--------------------------------------------------------------------*/
void __init mca_do_proc_init(void)
static int mca_handle_nmi_callback(struct device *dev, void *data)
{
int i;
struct proc_dir_entry *proc_mca;
struct proc_dir_entry* node = NULL;
struct MCA_adapter *p;
if(mca_info == NULL) return; /* Should never happen */
proc_mca = proc_mkdir("mca", &proc_root);
create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
/* Initialize /proc/mca entries for existing adapters */
for(i = 0; i < MCA_NUMADAPTERS; i++) {
p = &mca_info->slot[i];
p->procfn = 0;
if(i < MCA_MAX_SLOT_NR) sprintf(p->procname,"slot%d", i+1);
else if(i == MCA_INTEGVIDEO) sprintf(p->procname,"video");
else if(i == MCA_INTEGSCSI) sprintf(p->procname,"scsi");
else if(i == MCA_MOTHERBOARD) sprintf(p->procname,"planar");
if(!mca_isadapter(i)) continue;
struct mca_device *mca_dev = to_mca_device(dev);
unsigned char pos5;
node = create_proc_read_entry(p->procname, 0, proc_mca,
mca_read_proc, (void *)p);
pos5 = mca_device_read_pos(mca_dev, 5);
if(node == NULL) {
printk("Failed to allocate memory for MCA proc-entries!");
return;
}
if(!(pos5 & 0x80)) {
/* Bit 7 of POS 5 is reset when this adapter has a hardware
* error. Bit 7 it reset if there's error information
* available in POS 6 and 7.
*/
mca_handle_nmi_device(mca_dev, !(pos5 & 0x40));
return 1;
}
return 0;
}
} /* mca_do_proc_init() */
void mca_handle_nmi(void)
{
/* First try - scan the various adapters and see if a specific
* adapter was responsible for the error.
*/
bus_for_each_dev(&mca_bus_type, NULL, NULL, mca_handle_nmi_callback);
#endif
mca_nmi_hook();
} /* mca_handle_nmi */
......@@ -44,5 +44,6 @@ obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
obj-$(CONFIG_ISDN_BOOL) += isdn/
obj-$(CONFIG_MCA) += mca/
include $(TOPDIR)/Rules.make
......@@ -795,7 +795,6 @@ static inline void drain_rx_pool (amb_dev * dev, unsigned char pool) {
return;
}
#ifdef MODULE
static void drain_rx_pools (amb_dev * dev) {
unsigned char pool;
......@@ -803,10 +802,7 @@ static void drain_rx_pools (amb_dev * dev) {
for (pool = 0; pool < NUM_RX_POOLS; ++pool)
drain_rx_pool (dev, pool);
return;
}
#endif
static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority) {
rx_in rx;
......
......@@ -627,7 +627,7 @@ typedef struct {
struct amb_dev {
u8 irq;
u8 flags;
long flags;
u32 iobase;
u32 * membase;
......
......@@ -603,8 +603,7 @@ static int make_rate (const hrz_dev * dev, u32 c, rounding r,
// note: rounding the rate down means rounding 'p' up
const unsigned long br = test_bit (ultra, (hrz_flags *) &dev->flags) ?
BR_ULT : BR_HRZ;
const unsigned long br = test_bit(ultra, &dev->flags) ? BR_ULT : BR_HRZ;
u32 div = CR_MIND;
u32 pre;
......@@ -1106,9 +1105,9 @@ static inline void rx_bus_master_complete_handler (hrz_dev * dev) {
static inline int tx_hold (hrz_dev * dev) {
while (test_and_set_bit (tx_busy, &dev->flags)) {
PRINTD (DBG_TX, "sleeping at tx lock %p %u", dev, dev->flags);
PRINTD (DBG_TX, "sleeping at tx lock %p %lu", dev, dev->flags);
interruptible_sleep_on (&dev->tx_queue);
PRINTD (DBG_TX, "woken at tx lock %p %u", dev, dev->flags);
PRINTD (DBG_TX, "woken at tx lock %p %lu", dev, dev->flags);
if (signal_pending (current))
return -1;
}
......
......@@ -429,7 +429,7 @@ struct hrz_dev {
#endif
u8 irq;
u8 flags;
long flags;
u8 tx_last;
u8 tx_idle;
......
......@@ -328,13 +328,7 @@ struct mxser_hwconf mxsercfg[MXSER_BOARDS];
* static functions:
*/
#ifdef MODULE
int init_module(void);
void cleanup_module(void);
#endif
static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
int mxser_init(void);
static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
static int mxser_get_PCI_conf(struct pci_dev *, int, struct mxser_hwconf *);
static void mxser_do_softint(void *);
......@@ -373,21 +367,7 @@ static int mxser_set_modem_info(struct mxser_struct *, unsigned int, unsigned in
* The MOXA C168/C104 serial driver boot-time initialization code!
*/
#ifdef MODULE
int init_module(void)
{
int ret;
if (verbose)
printk("Loading module mxser ...\n");
ret = mxser_init();
if (verbose)
printk("Done.\n");
return (ret);
}
void cleanup_module(void)
static void __exit mxser_module_exit(void)
{
int i, err = 0;
......@@ -411,8 +391,6 @@ void cleanup_module(void)
printk("Done.\n");
}
#endif
int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
{
......@@ -510,7 +488,7 @@ static int mxser_get_PCI_conf(struct pci_dev *pdev, int board_type, struct mxser
return (0);
}
int mxser_init(void)
static int __init mxser_module_init(void)
{
int i, m, retval, b;
int n, index;
......@@ -2493,3 +2471,6 @@ static void mxser_normal_mode(int port)
}
outb(0x00, port + 4);
}
module_init(mxser_module_init);
module_exit(mxser_module_exit);
......@@ -44,7 +44,7 @@ struct sx_board {
int poll;
int ta_type;
struct timer_list timer;
int locks;
long locks;
};
struct vpd_prom {
......
......@@ -3,8 +3,9 @@
*
* ADB HID driver for Power Macintosh computers.
*
* Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl
* (see that file for its authors and contributors).
* Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl.
* drivers/macintosh/mac_keyb.c was Copyright (C) 1996 Paul Mackerras
* with considerable contributions from Ben Herrenschmidt and others.
*
* Copyright (C) 2000 Franz Sirl.
*
......@@ -433,22 +434,17 @@ static void leds_done(struct adb_request *req)
static int
adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
{
unsigned long flags;
switch (code) {
case ADB_MSG_PRE_RESET:
case ADB_MSG_POWERDOWN:
/* Stop the repeat timer. Autopoll is already off at this point */
save_flags(flags);
cli();
{
int i;
for (i = 1; i < 16; i++) {
if (adbhid[i])
del_timer(&adbhid[i]->input.timer);
del_timer_sync(&adbhid[i]->input.timer);
}
}
restore_flags(flags);
/* Stop pending led requests */
while(!led_request.complete)
......@@ -479,7 +475,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
memset(adbhid[id], 0, sizeof(struct adbhid));
sprintf(adbhid[id]->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id);
init_input_dev(&adbhid[id]);
init_input_dev(&adbhid[id]->input);
adbhid[id]->id = default_id;
adbhid[id]->original_handler_id = original_handler_id;
......@@ -508,21 +504,21 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
switch (original_handler_id) {
default:
printk("<unknown>.\n");
adbhid[id]->input.idversion = ADB_KEYBOARD_UNKNOWN;
adbhid[id]->input.id.version = ADB_KEYBOARD_UNKNOWN;
break;
case 0x01: case 0x02: case 0x03: case 0x06: case 0x08:
case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C:
case 0xC0: case 0xC3: case 0xC6:
printk("ANSI.\n");
adbhid[id]->input.idversion = ADB_KEYBOARD_ANSI;
adbhid[id]->input.id.version = ADB_KEYBOARD_ANSI;
break;
case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
case 0xC4: case 0xC7:
printk("ISO, swapping keys.\n");
adbhid[id]->input.idversion = ADB_KEYBOARD_ISO;
adbhid[id]->input.id.version = ADB_KEYBOARD_ISO;
i = adbhid[id]->keycode[10];
adbhid[id]->keycode[10] = adbhid[id]->keycode[50];
adbhid[id]->keycode[50] = i;
......@@ -531,7 +527,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A:
case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9:
printk("JIS.\n");
adbhid[id]->input.idversion = ADB_KEYBOARD_JIS;
adbhid[id]->input.id.version = ADB_KEYBOARD_JIS;
break;
}
......
comment "Micro Channel Architecture Bus support"
depends on MCA
config MCA_LEGACY
bool "Legacy MCA API Support"
depends on MCA
help
This compiles in support for the old slot based MCA API. If you
have an unconverted MCA driver, you will need to say Y here. It
is safe to say Y anyway.
config MCA_PROC_FS
bool "Support for the mca entry in /proc"
depends on MCA_LEGACY && PROC_FS
help
If you want the old style /proc/mca directory in addition to the
new style sysfs say Y here.
# Makefile for the Linux MCA bus support
obj-y := mca-bus.o mca-device.o mca-driver.o
obj-$(CONFIG_MCA_PROC_FS) += mca-proc.o
obj-$(CONFIG_MCA_LEGACY) += mca-legacy.o
export-objs := mca-bus.o mca-legacy.o mca-proc.o mca-driver.o
include $(TOPDIR)/Rules.make
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
* MCA bus support functions for sysfs.
*
* (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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.
**
** 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.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/mca.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
/* Very few machines have more than one MCA bus. However, there are
* those that do (Voyager 35xx/5xxx), so we do it this way for future
* expansion. None that I know have more than 2 */
struct mca_bus *mca_root_busses[MAX_MCA_BUSSES];
#define MCA_DEVINFO(i,s) { .pos = i, .name = s }
struct mca_device_info {
short pos_id; /* the 2 byte pos id for this card */
char name[DEVICE_NAME_SIZE];
};
static int mca_bus_match (struct device *dev, struct device_driver *drv)
{
struct mca_device *mca_dev = to_mca_device (dev);
struct mca_driver *mca_drv = to_mca_driver (drv);
const short *mca_ids = mca_drv->id_table;
int i;
if (!mca_ids)
return 0;
for(i = 0; mca_ids[i]; i++) {
if (mca_ids[i] == mca_dev->pos_id) {
mca_dev->index = i;
return 1;
}
}
return 0;
}
struct bus_type mca_bus_type = {
.name = "MCA",
.match = mca_bus_match,
};
EXPORT_SYMBOL (mca_bus_type);
static ssize_t mca_show_pos_id(struct device *dev, char *buf, size_t count,
loff_t off)
{
/* four digits, \n and trailing \0 */
char mybuf[6];
struct mca_device *mca_dev = to_mca_device(dev);
int len;
if(mca_dev->pos_id < MCA_DUMMY_POS_START)
len = sprintf(mybuf, "%04x\n", mca_dev->pos_id);
else
len = sprintf(mybuf, "none\n");
len++;
if(len > off) {
len = min((size_t)(len - off), count);
memcpy(buf + off, mybuf + off, len);
} else {
len = 0;
}
return len;
}
static ssize_t mca_show_pos(struct device *dev, char *buf, size_t count,
loff_t off)
{
/* enough for 8 two byte hex chars plus space and new line */
char mybuf[26];
int j, len=0;
struct mca_device *mca_dev = to_mca_device(dev);
for(j=0; j<8; j++)
len += sprintf(mybuf+len, "%02x ", mca_dev->pos[j]);
/* change last trailing space to new line */
mybuf[len-1] = '\n';
len++;
if(len > off) {
len = min((size_t)(len - off), count);
memcpy(buf + off, mybuf + off, len);
} else {
len = 0;
}
return len;
}
static DEVICE_ATTR(id, S_IRUGO, mca_show_pos_id, NULL);
static DEVICE_ATTR(pos, S_IRUGO, mca_show_pos, NULL);
int __init mca_register_device(int bus, struct mca_device *mca_dev)
{
struct mca_bus *mca_bus = mca_root_busses[bus];
mca_dev->dev.parent = &mca_bus->dev;
mca_dev->dev.bus = &mca_bus_type;
sprintf (mca_dev->dev.bus_id, "%02d:%02X", bus, mca_dev->slot);
mca_dev->dma_mask = mca_bus->default_dma_mask;
mca_dev->dev.dma_mask = &mca_dev->dma_mask;
if (device_register(&mca_dev->dev))
return 0;
device_create_file(&mca_dev->dev, &dev_attr_id);
device_create_file(&mca_dev->dev, &dev_attr_pos);
return 1;
}
/* */
struct mca_bus * __devinit mca_attach_bus(int bus)
{
struct mca_bus *mca_bus;
if (unlikely(mca_root_busses[bus] != NULL)) {
/* This should never happen, but just in case */
printk(KERN_EMERG "MCA tried to add already existing bus %d\n",
bus);
dump_stack();
return NULL;
}
mca_bus = kmalloc(sizeof(struct mca_bus), GFP_KERNEL);
if (!mca_bus)
return NULL;
memset(mca_bus, 0, sizeof(struct mca_bus));
sprintf(mca_bus->dev.bus_id,"mca%d",bus);
sprintf(mca_bus->dev.name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary");
device_register(&mca_bus->dev);
mca_root_busses[bus] = mca_bus;
return mca_bus;
}
int __init mca_system_init (void)
{
return bus_register(&mca_bus_type);
}
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
* MCA device support functions
*
* These functions support the ongoing device access API.
*
* (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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.
**
** 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.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/mca.h>
/**
* mca_device_read_stored_pos - read POS register from stored data
* @mca_dev: device to read from
* @reg: register to read from
*
* Fetch a POS value that was stored at boot time by the kernel
* when it scanned the MCA space. The register value is returned.
* Missing or invalid registers report 0.
*/
unsigned char mca_device_read_stored_pos(struct mca_device *mca_dev, int reg)
{
if(reg < 0 || reg >= 8)
return 0;
return mca_dev->pos[reg];
}
EXPORT_SYMBOL(mca_device_read_stored_pos);
/**
* mca_device_read_pos - read POS register from card
* @mca_dev: device to read from
* @reg: register to read from
*
* Fetch a POS value directly from the hardware to obtain the
* current value. This is much slower than
* mca_device_read_stored_pos and may not be invoked from
* interrupt context. It handles the deep magic required for
* onboard devices transparently.
*/
unsigned char mca_device_read_pos(struct mca_device *mca_dev, int reg)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
return mca_bus->f.mca_read_pos(mca_dev, reg);
return mca_dev->pos[reg];
}
EXPORT_SYMBOL(mca_device_read_pos);
/**
* mca_device_write_pos - read POS register from card
* @mca_dev: device to write pos register to
* @reg: register to write to
* @byte: byte to write to the POS registers
*
* Store a POS value directly to the hardware. You should not
* normally need to use this function and should have a very good
* knowledge of MCA bus before you do so. Doing this wrongly can
* damage the hardware.
*
* This function may not be used from interrupt context.
*
*/
void mca_device_write_pos(struct mca_device *mca_dev, int reg,
unsigned char byte)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
mca_bus->f.mca_write_pos(mca_dev, reg, byte);
}
EXPORT_SYMBOL(mca_device_write_pos);
/**
* mca_device_transform_irq - transform the ADF obtained IRQ
* @mca_device: device whose irq needs transforming
* @irq: input irq from ADF
*
* MCA Adapter Definition Files (ADF) contain irq, ioport, memory
* etc. definitions. In systems with more than one bus, these need
* to be transformed through bus mapping functions to get the real
* system global quantities.
*
* This function transforms the interrupt number and returns the
* transformed system global interrupt
*/
int mca_device_transform_irq(struct mca_device *mca_dev, int irq)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
return mca_bus->f.mca_transform_irq(mca_dev, irq);
}
EXPORT_SYMBOL(mca_device_transform_irq);
/**
* mca_device_transform_ioport - transform the ADF obtained I/O port
* @mca_device: device whose port needs transforming
* @ioport: input I/O port from ADF
*
* MCA Adapter Definition Files (ADF) contain irq, ioport, memory
* etc. definitions. In systems with more than one bus, these need
* to be transformed through bus mapping functions to get the real
* system global quantities.
*
* This function transforms the I/O port number and returns the
* transformed system global port number.
*
* This transformation can be assumed to be linear for port ranges.
*/
int mca_device_transform_ioport(struct mca_device *mca_dev, int port)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
return mca_bus->f.mca_transform_ioport(mca_dev, port);
}
EXPORT_SYMBOL(mca_device_transform_ioport);
/**
* mca_device_transform_memory - transform the ADF obtained memory
* @mca_device: device whose memory region needs transforming
* @mem: memory region start from ADF
*
* MCA Adapter Definition Files (ADF) contain irq, ioport, memory
* etc. definitions. In systems with more than one bus, these need
* to be transformed through bus mapping functions to get the real
* system global quantities.
*
* This function transforms the memory region start and returns the
* transformed system global memory region (physical).
*
* This transformation can be assumed to be linear for region ranges.
*/
void *mca_device_transform_memory(struct mca_device *mca_dev, void *mem)
{
struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
return mca_bus->f.mca_transform_memory(mca_dev, mem);
}
EXPORT_SYMBOL(mca_device_transform_memory);
/**
* mca_device_claimed - check if claimed by driver
* @mca_dev: device to check
*
* Returns 1 if the slot has been claimed by a driver
*/
int mca_device_claimed(struct mca_device *mca_dev)
{
return mca_dev->driver_loaded;
}
EXPORT_SYMBOL(mca_device_claimed);
/**
* mca_device_set_claim - set the claim value of the driver
* @mca_dev: device to set value for
* @val: claim value to set (1 claimed, 0 unclaimed)
*/
void mca_device_set_claim(struct mca_device *mca_dev, int val)
{
mca_dev->driver_loaded = val;
}
EXPORT_SYMBOL(mca_device_set_claim);
/**
* mca_device_status - get the status of the device
* @mca_device: device to get
*
* returns an enumeration of the device status:
*
* MCA_ADAPTER_NORMAL adapter is OK.
* MCA_ADAPTER_NONE no adapter at device (should never happen).
* MCA_ADAPTER_DISABLED adapter is disabled.
* MCA_ADAPTER_ERROR adapter cannot be initialised.
*/
enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev)
{
return mca_dev->status;
}
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
* MCA driver support functions for sysfs.
*
* (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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.
**
** 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.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
*/
#include <linux/device.h>
#include <linux/mca.h>
#include <linux/module.h>
int mca_register_driver(struct mca_driver *mca_drv)
{
int r;
mca_drv->driver.bus = &mca_bus_type;
if ((r = driver_register(&mca_drv->driver)) < 0)
return r;
return 0;
}
EXPORT_SYMBOL(mca_register_driver);
void mca_unregister_driver(struct mca_driver *mca_drv)
{
driver_unregister(&mca_drv->driver);
}
EXPORT_SYMBOL(mca_unregister_driver);
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
* MCA bus support functions for legacy (2.4) API.
*
* Legacy API means the API that operates in terms of MCA slot number
*
* (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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.
**
** 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.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/mca.h>
#include <asm/io.h>
/* NOTE: This structure is stack allocated */
struct mca_find_adapter_info {
int id;
int slot;
struct mca_device *mca_dev;
};
/* The purpose of this iterator is to loop over all the devices and
* find the one with the smallest slot number that's just greater than
* or equal to the required slot with a matching id */
static int mca_find_adapter_callback(struct device *dev, void *data)
{
struct mca_find_adapter_info *info = data;
struct mca_device *mca_dev = to_mca_device(dev);
if(mca_dev->pos_id != info->id)
return 0;
if(mca_dev->slot < info->slot)
return 0;
if(!info->mca_dev || info->mca_dev->slot >= mca_dev->slot)
info->mca_dev = mca_dev;
return 0;
}
/**
* mca_find_adapter - scan for adapters
* @id: MCA identification to search for
* @start: starting slot
*
* Search the MCA configuration for adapters matching the 16bit
* ID given. The first time it should be called with start as zero
* and then further calls made passing the return value of the
* previous call until %MCA_NOTFOUND is returned.
*
* Disabled adapters are not reported.
*/
int mca_find_adapter(int id, int start)
{
struct mca_find_adapter_info info;
if(id == 0xffff)
return MCA_NOTFOUND;
info.slot = start;
info.id = id;
info.mca_dev = NULL;
for(;;) {
bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
if(info.mca_dev == NULL)
return MCA_NOTFOUND;
if(info.mca_dev->status != MCA_ADAPTER_DISABLED)
break;
/* OK, found adapter but it was disabled. Go around
* again, excluding the slot we just found */
info.slot = info.mca_dev->slot + 1;
info.mca_dev = NULL;
}
return info.mca_dev->slot;
}
EXPORT_SYMBOL(mca_find_adapter);
/*--------------------------------------------------------------------*/
/**
* mca_find_unused_adapter - scan for unused adapters
* @id: MCA identification to search for
* @start: starting slot
*
* Search the MCA configuration for adapters matching the 16bit
* ID given. The first time it should be called with start as zero
* and then further calls made passing the return value of the
* previous call until %MCA_NOTFOUND is returned.
*
* Adapters that have been claimed by drivers and those that
* are disabled are not reported. This function thus allows a driver
* to scan for further cards when some may already be driven.
*/
int mca_find_unused_adapter(int id, int start)
{
struct mca_find_adapter_info info = { 0 };
if(id == 0xffff)
return MCA_NOTFOUND;
info.slot = start;
info.id = id;
info.mca_dev = NULL;
for(;;) {
bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
if(info.mca_dev == NULL)
return MCA_NOTFOUND;
if(info.mca_dev->status != MCA_ADAPTER_DISABLED
&& !info.mca_dev->driver_loaded)
break;
/* OK, found adapter but it was disabled or already in
* use. Go around again, excluding the slot we just
* found */
info.slot = info.mca_dev->slot + 1;
info.mca_dev = NULL;
}
return info.mca_dev->slot;
}
EXPORT_SYMBOL(mca_find_unused_adapter);
/* NOTE: stack allocated structure */
struct mca_find_device_by_slot_info {
int slot;
struct mca_device *mca_dev;
};
static int mca_find_device_by_slot_callback(struct device *dev, void *data)
{
struct mca_find_device_by_slot_info *info = data;
struct mca_device *mca_dev = to_mca_device(dev);
if(mca_dev->slot == info->slot)
info->mca_dev = mca_dev;
return 0;
}
struct mca_device *mca_find_device_by_slot(int slot)
{
struct mca_find_device_by_slot_info info;
info.slot = slot;
info.mca_dev = NULL;
bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_device_by_slot_callback);
return info.mca_dev;
}
EXPORT_SYMBOL(mca_find_device_by_slot);
/**
* mca_read_stored_pos - read POS register from boot data
* @slot: slot number to read from
* @reg: register to read from
*
* Fetch a POS value that was stored at boot time by the kernel
* when it scanned the MCA space. The register value is returned.
* Missing or invalid registers report 0.
*/
unsigned char mca_read_stored_pos(int slot, int reg)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return 0;
return mca_device_read_stored_pos(mca_dev, reg);
}
EXPORT_SYMBOL(mca_read_stored_pos);
/**
* mca_read_pos - read POS register from card
* @slot: slot number to read from
* @reg: register to read from
*
* Fetch a POS value directly from the hardware to obtain the
* current value. This is much slower than mca_read_stored_pos and
* may not be invoked from interrupt context. It handles the
* deep magic required for onboard devices transparently.
*/
unsigned char mca_read_pos(int slot, int reg)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return 0;
return mca_device_read_pos(mca_dev, reg);
}
EXPORT_SYMBOL(mca_read_pos);
/**
* mca_write_pos - read POS register from card
* @slot: slot number to read from
* @reg: register to read from
* @byte: byte to write to the POS registers
*
* Store a POS value directly from the hardware. You should not
* normally need to use this function and should have a very good
* knowledge of MCA bus before you do so. Doing this wrongly can
* damage the hardware.
*
* This function may not be used from interrupt context.
*
* Note that this a technically a Bad Thing, as IBM tech stuff says
* you should only set POS values through their utilities.
* However, some devices such as the 3c523 recommend that you write
* back some data to make sure the configuration is consistent.
* I'd say that IBM is right, but I like my drivers to work.
*
* This function can't do checks to see if multiple devices end up
* with the same resources, so you might see magic smoke if someone
* screws up.
*/
void mca_write_pos(int slot, int reg, unsigned char byte)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return;
mca_device_write_pos(mca_dev, reg, byte);
}
EXPORT_SYMBOL(mca_write_pos);
/**
* mca_set_adapter_name - Set the description of the card
* @slot: slot to name
* @name: text string for the namen
*
* This function sets the name reported via /proc for this
* adapter slot. This is for user information only. Setting a
* name deletes any previous name.
*/
void mca_set_adapter_name(int slot, char* name)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return;
strncpy(mca_dev->dev.name, name, sizeof(mca_dev->dev.name));
mca_dev->dev.name[sizeof(mca_dev->dev.name) - 1] = '\0';
}
EXPORT_SYMBOL(mca_set_adapter_name);
/**
* mca_get_adapter_name - get the adapter description
* @slot: slot to query
*
* Return the adapter description if set. If it has not been
* set or the slot is out range then return NULL.
*/
char *mca_get_adapter_name(int slot)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return NULL;
return mca_dev->dev.name;
}
EXPORT_SYMBOL(mca_get_adapter_name);
/**
* mca_is_adapter_used - check if claimed by driver
* @slot: slot to check
*
* Returns 1 if the slot has been claimed by a driver
*/
int mca_is_adapter_used(int slot)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return 0;
return mca_device_claimed(mca_dev);
}
EXPORT_SYMBOL(mca_is_adapter_used);
/**
* mca_mark_as_used - claim an MCA device
* @slot: slot to claim
* FIXME: should we make this threadsafe
*
* Claim an MCA slot for a device driver. If the
* slot is already taken the function returns 1,
* if it is not taken it is claimed and 0 is
* returned.
*/
int mca_mark_as_used(int slot)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
/* FIXME: this is actually a severe error */
return 1;
if(mca_device_claimed(mca_dev))
return 1;
mca_device_set_claim(mca_dev, 1);
return 0;
}
EXPORT_SYMBOL(mca_mark_as_used);
/**
* mca_mark_as_unused - release an MCA device
* @slot: slot to claim
*
* Release the slot for other drives to use.
*/
void mca_mark_as_unused(int slot)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return;
mca_device_set_claim(mca_dev, 0);
}
EXPORT_SYMBOL(mca_mark_as_unused);
/**
* mca_isadapter - check if the slot holds an adapter
* @slot: slot to query
*
* Returns zero if the slot does not hold an adapter, non zero if
* it does.
*/
int mca_isadapter(int slot)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
enum MCA_AdapterStatus status;
if(!mca_dev)
return 0;
status = mca_device_status(mca_dev);
return status == MCA_ADAPTER_NORMAL
|| status == MCA_ADAPTER_DISABLED;
}
EXPORT_SYMBOL(mca_isadapter);
/**
* mca_isenabled - check if the slot holds an enabled adapter
* @slot: slot to query
*
* Returns a non zero value if the slot holds an enabled adapter
* and zero for any other case.
*/
int mca_isenabled(int slot)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return 0;
return mca_device_status(mca_dev) == MCA_ADAPTER_NORMAL;
}
/* -*- mode: c; c-basic-offset: 8 -*- */
/*
* MCA bus support functions for the proc fs.
*
* NOTE: this code *requires* the legacy MCA api.
*
* Legacy API means the API that operates in terms of MCA slot number
*
* (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.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.
**
** 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.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/mca.h>
static int get_mca_info_helper(struct mca_device *mca_dev, char *page, int len)
{
int j;
for(j=0; j<8; j++)
len += sprintf(page+len, "%02x ",
mca_dev ? mca_dev->pos[j] : 0xff);
len += sprintf(page+len, " %s\n", mca_dev ? mca_dev->dev.name : "");
return len;
}
int get_mca_info(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int i, len = 0;
if(MCA_bus) {
struct mca_device *mca_dev;
/* Format POS registers of eight MCA slots */
for(i=0; i<MCA_MAX_SLOT_NR; i++) {
mca_dev = mca_find_device_by_slot(i);
len += sprintf(page+len, "Slot %d: ", i+1);
len = get_mca_info_helper(mca_dev, page, len);
}
/* Format POS registers of integrated video subsystem */
mca_dev = mca_find_device_by_slot(MCA_INTEGVIDEO);
len += sprintf(page+len, "Video : ");
len = get_mca_info_helper(mca_dev, page, len);
/* Format POS registers of integrated SCSI subsystem */
mca_dev = mca_find_device_by_slot(MCA_INTEGSCSI);
len += sprintf(page+len, "SCSI : ");
len = get_mca_info_helper(mca_dev, page, len);
/* Format POS registers of motherboard */
mca_dev = mca_find_device_by_slot(MCA_MOTHERBOARD);
len += sprintf(page+len, "Planar: ");
len = get_mca_info_helper(mca_dev, page, len);
} else {
/* Leave it empty if MCA not detected - this should *never*
* happen!
*/
}
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
return len;
}
/*--------------------------------------------------------------------*/
static int mca_default_procfn(char* buf, struct mca_device *mca_dev)
{
int len = 0, i;
int slot = mca_dev->slot;
/* Print out the basic information */
if(slot < MCA_MAX_SLOT_NR) {
len += sprintf(buf+len, "Slot: %d\n", slot+1);
} else if(slot == MCA_INTEGSCSI) {
len += sprintf(buf+len, "Integrated SCSI Adapter\n");
} else if(slot == MCA_INTEGVIDEO) {
len += sprintf(buf+len, "Integrated Video Adapter\n");
} else if(slot == MCA_MOTHERBOARD) {
len += sprintf(buf+len, "Motherboard\n");
}
if(mca_dev->dev.name[0]) {
/* Drivers might register a name without /proc handler... */
len += sprintf(buf+len, "Adapter Name: %s\n",
mca_dev->dev.name);
} else {
len += sprintf(buf+len, "Adapter Name: Unknown\n");
}
len += sprintf(buf+len, "Id: %02x%02x\n",
mca_dev->pos[1], mca_dev->pos[0]);
len += sprintf(buf+len, "Enabled: %s\nPOS: ",
mca_isenabled(slot) ? "Yes" : "No");
for(i=0; i<8; i++) {
len += sprintf(buf+len, "%02x ", mca_dev->pos[i]);
}
len += sprintf(buf+len, "\nDriver Installed: %s",
mca_is_adapter_used(slot) ? "Yes" : "No");
buf[len++] = '\n';
buf[len] = 0;
return len;
} /* mca_default_procfn() */
static int get_mca_machine_info(char* page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = 0;
len += sprintf(page+len, "Model Id: 0x%x\n", machine_id);
len += sprintf(page+len, "Submodel Id: 0x%x\n", machine_submodel_id);
len += sprintf(page+len, "BIOS Revision: 0x%x\n", BIOS_revision);
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
return len;
}
static int mca_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
struct mca_device *mca_dev = (struct mca_device *)data;
int len = 0;
/* Get the standard info */
len = mca_default_procfn(page, mca_dev);
/* Do any device-specific processing, if there is any */
if(mca_dev->procfn) {
len += mca_dev->procfn(page+len, mca_dev->slot,
mca_dev->proc_dev);
}
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
return len;
} /* mca_read_proc() */
/*--------------------------------------------------------------------*/
void __init mca_do_proc_init(void)
{
int i;
struct proc_dir_entry *proc_mca;
struct proc_dir_entry* node = NULL;
struct mca_device *mca_dev;
proc_mca = proc_mkdir("mca", &proc_root);
create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
/* Initialize /proc/mca entries for existing adapters */
for(i = 0; i < MCA_NUMADAPTERS; i++) {
mca_dev = mca_find_device_by_slot(i);
if(!mca_dev)
continue;
mca_dev->procfn = NULL;
if(i < MCA_MAX_SLOT_NR) sprintf(mca_dev->procname,"slot%d", i+1);
else if(i == MCA_INTEGVIDEO) sprintf(mca_dev->procname,"video");
else if(i == MCA_INTEGSCSI) sprintf(mca_dev->procname,"scsi");
else if(i == MCA_MOTHERBOARD) sprintf(mca_dev->procname,"planar");
if(!mca_isadapter(i)) continue;
node = create_proc_read_entry(mca_dev->procname, 0, proc_mca,
mca_read_proc, (void *)mca_dev);
if(node == NULL) {
printk("Failed to allocate memory for MCA proc-entries!");
return;
}
}
} /* mca_do_proc_init() */
/**
* mca_set_adapter_procfn - Set the /proc callback
* @slot: slot to configure
* @procfn: callback function to call for /proc
* @dev: device information passed to the callback
*
* This sets up an information callback for /proc/mca/slot?. The
* function is called with the buffer, slot, and device pointer (or
* some equally informative context information, or nothing, if you
* prefer), and is expected to put useful information into the
* buffer. The adapter name, ID, and POS registers get printed
* before this is called though, so don't do it again.
*
* This should be called with a %NULL @procfn when a module
* unregisters, thus preventing kernel crashes and other such
* nastiness.
*/
void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* proc_dev)
{
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
if(!mca_dev)
return;
mca_dev->procfn = procfn;
mca_dev->proc_dev = proc_dev;
}
EXPORT_SYMBOL(mca_set_adapter_procfn);
......@@ -48,7 +48,6 @@ extern int ne2_probe(struct net_device *dev);
extern int hp100_probe(struct net_device *dev);
extern int ultra_probe(struct net_device *dev);
extern int ultra32_probe(struct net_device *dev);
extern int ultramca_probe(struct net_device *dev);
extern int wd_probe(struct net_device *dev);
extern int el2_probe(struct net_device *dev);
extern int ne_probe(struct net_device *dev);
......@@ -191,9 +190,6 @@ static struct devprobe eisa_probes[] __initdata = {
static struct devprobe mca_probes[] __initdata = {
#ifdef CONFIG_ULTRAMCA
{ultramca_probe, 0},
#endif
#ifdef CONFIG_NE2_MCA
{ne2_probe, 0},
#endif
......
......@@ -1155,8 +1155,8 @@ static void netdev_timer(unsigned long data)
unsigned int old_linkok = np->linkok;
if (debug)
printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8lx "
"config %8.8lx.\n", dev->name, readl(ioaddr + ISR),
printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x "
"config %8.8x.\n", dev->name, readl(ioaddr + ISR),
readl(ioaddr + TCRRCR));
if (np->flags == HAS_MII_XCVR) {
......@@ -1184,7 +1184,7 @@ static void tx_timeout(struct net_device *dev)
long ioaddr = dev->base_addr;
int i;
printk(KERN_WARNING "%s: Transmit timed out, status %8.8lx,"
printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
" resetting...\n", dev->name, readl(ioaddr + ISR));
{
......@@ -1554,7 +1554,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
np->stats.rx_crc_errors += (readl(ioaddr + TALLY) & 0x7fff0000) >> 16;
if (debug)
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4lx.\n",
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
dev->name, readl(ioaddr + ISR));
writel(np->imrvalue, ioaddr + IMR);
......
......@@ -390,7 +390,7 @@ int __init lance_probe(struct net_device *dev)
static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options)
{
struct lance_private *lp;
short dma_channels; /* Mark spuriously-busy DMA channels */
long dma_channels; /* Mark spuriously-busy DMA channels */
int i, reset_val, lance_version;
const char *chipname;
/* Flags for specific chips or boards. */
......
......@@ -184,11 +184,41 @@ static struct card {
short addr_offset;
unsigned char *vendor_id;
char *cardname;
unsigned char config;
long config;
} cards[] = {
{ NI65_ID0,NI65_ID1,0x0e,0x10,0x0,0x8,ni_vendor,"ni6510", 0x1 } ,
{ NI65_EB_ID0,NI65_EB_ID1,0x0e,0x18,0x10,0x0,ni_vendor,"ni6510 EtherBlaster", 0x2 } ,
{ NE2100_ID0,NE2100_ID1,0x0e,0x18,0x10,0x0,NULL,"generic NE2100", 0x0 }
{
.id0 = NI65_ID0,
.id1 = NI65_ID1,
.id_offset = 0x0e,
.total_size = 0x10,
.cmd_offset = 0x0,
.addr_offset = 0x8,
.vendor_id = ni_vendor,
.cardname = "ni6510",
.config = 0x1,
},
{
.id0 = NI65_EB_ID0,
.id1 = NI65_EB_ID1,
.id_offset = 0x0e,
.total_size = 0x18,
.cmd_offset = 0x10,
.addr_offset = 0x0,
.vendor_id = ni_vendor,
.cardname = "ni6510 EtherBlaster",
.config = 0x2,
},
{
.id0 = NE2100_ID0,
.id1 = NE2100_ID1,
.id_offset = 0x0e,
.total_size = 0x18,
.cmd_offset = 0x10,
.addr_offset = 0x0,
.vendor_id = NULL,
.cardname = "generic NE2100",
.config = 0x0,
},
};
#define NUM_CARDS 3
......@@ -415,7 +445,8 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
else {
if(dev->dma == 0) {
/* 'stuck test' from lance.c */
int dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0);
long dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) |
(inb(DMA2_STAT_REG) & 0xf0);
for(i=1;i<5;i++) {
int dma = dmatab[i];
if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))
......
......@@ -142,14 +142,13 @@ static void __init network_ldisc_init(void)
static void __init special_device_init(void)
{
#ifdef CONFIG_NET_SB1000
{
extern int sb1000_probe(struct net_device *dev);
static struct net_device sb1000_dev =
{
"cm0" __PAD3, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, sb1000_probe
};
register_netdev(&sb1000_dev);
}
extern int sb1000_probe(struct net_device *dev);
static struct net_device sb1000_dev = {
.name = "cm0" __PAD3,
.init = sb1000_probe,
};
register_netdev(&sb1000_dev);
#endif
}
......
......@@ -51,8 +51,6 @@
#include "8390.h"
#include "smc-mca.h"
int ultramca_probe(struct net_device *dev);
static int ultramca_open(struct net_device *dev);
static void ultramca_reset_8390(struct net_device *dev);
static void ultramca_get_8390_hdr(struct net_device *dev,
......@@ -89,37 +87,57 @@ struct smc_mca_adapters_t {
char *name;
};
static struct smc_mca_adapters_t smc_mca_adapters[] __initdata = {
{ 0x61c8, "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)" },
{ 0x61c9, "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)" },
{ 0x6fc0, "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)" },
{ 0x6fc1, "WD Starcard PLUS/A (WD8003ST/A)" },
{ 0x6fc2, "WD Ethercard PLUS 10T/A (WD8003W/A)" },
{ 0xefd4, "IBM PS/2 Adapter/A for Ethernet UTP/AUI (WD8013WP/A)" },
{ 0xefd5, "IBM PS/2 Adapter/A for Ethernet BNC/AUI (WD8013EP/A)" },
{ 0xefe5, "IBM PS/2 Adapter/A for Ethernet" },
{ 0x0000, NULL }
#define MAX_ULTRAMCA_CARDS 4 /* Max number of Ultra cards per module */
static int ultra_io[MAX_ULTRAMCA_CARDS];
static int ultra_irq[MAX_ULTRAMCA_CARDS];
MODULE_LICENSE("GPL");
MODULE_PARM(ultra_io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
MODULE_PARM(ultra_irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
MODULE_PARM_DESC(ultra_io, "SMC Ultra/EtherEZ MCA I/O base address(es)");
MODULE_PARM_DESC(ultra_irq, "SMC Ultra/EtherEZ MCA IRQ number(s)");
static short smc_mca_adapter_ids[] __initdata = {
0x61c8,
0x61c9,
0x6fc0,
0x6fc1,
0x6fc2,
0xefd4,
0xefd5,
0xefe5,
0x0000
};
static char *smc_mca_adapter_names[] __initdata = {
"SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)",
"SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)",
"WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)",
"WD Starcard PLUS/A (WD8003ST/A)",
"WD Ethercard PLUS 10T/A (WD8003W/A)",
"IBM PS/2 Adapter/A for Ethernet UTP/AUI (WD8013WP/A)",
"IBM PS/2 Adapter/A for Ethernet BNC/AUI (WD8013EP/A)",
"IBM PS/2 Adapter/A for Ethernet",
NULL
};
int __init ultramca_probe(struct net_device *dev)
static int ultra_found = 0;
int __init ultramca_probe(struct device *gen_dev)
{
unsigned short ioaddr;
struct net_device *dev;
unsigned char reg4, num_pages;
char slot = -1;
struct mca_device *mca_dev = to_mca_device(gen_dev);
char slot = mca_dev->slot;
unsigned char pos2 = 0xff, pos3 = 0xff, pos4 = 0xff, pos5 = 0xff;
int i, j;
int adapter_found = 0;
int adapter = 0;
int i;
int adapter = mca_dev->index;
int tbase = 0;
int tirq = 0;
int base_addr = dev->base_addr;
int irq = dev->irq;
if (!MCA_bus) {
return -ENODEV;
}
SET_MODULE_OWNER(dev);
int base_addr = ultra_io[ultra_found];
int irq = ultra_irq[ultra_found];
if (base_addr || irq) {
printk(KERN_INFO "Probing for SMC MCA adapter");
......@@ -132,82 +150,76 @@ int __init ultramca_probe(struct net_device *dev)
}
}
/* proper multicard detection by ZP Gu (zpg@castle.net) */
for (j = 0; (smc_mca_adapters[j].name != NULL) && !adapter_found; j++) {
slot = mca_find_unused_adapter(smc_mca_adapters[j].id, 0);
while((slot != MCA_NOTFOUND) && !adapter_found) {
tirq = 0;
tbase = 0;
/* If we're trying to match a specificied irq or
* io address, we'll reject the adapter
* found unless it's the one we're looking for
*/
pos2 = mca_read_stored_pos(slot, 2); /* io_addr */
pos3 = mca_read_stored_pos(slot, 3); /* shared mem */
pos4 = mca_read_stored_pos(slot, 4); /* ROM bios addr
* range */
pos5 = mca_read_stored_pos(slot, 5); /* irq, media
* and RIPL */
/* Test the following conditions:
* - If an irq parameter is supplied, compare it
* with the irq of the adapter we found
* - If a base_addr paramater is given, compare it
* with the base_addr of the adapter we found
* - Check that the irq and the base_addr of the
* adapter we found is not already in use by
* this driver
*/
switch (j) { /* j = card-idx (card array above) [hs] */
case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A:
case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A:
case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A:
case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A:
{
tbase = addr_table[(pos2 & 0xf0) >> 4].base_addr;
tirq = irq_table[(pos5 & 0xc) >> 2].new_irq;
break;
}
case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A:
case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A:
case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A:
case _efe5_IBM_PS2_Adapter_A_for_Ethernet:
{
tbase = ((pos2 & 0x0fe) * 0x10);
tirq = irq_table[(pos5 & 3)].old_irq;
break;
}
}
tirq = 0;
tbase = 0;
/* If we're trying to match a specificied irq or io address,
* we'll reject the adapter found unless it's the one we're
* looking for */
pos2 = mca_device_read_stored_pos(mca_dev, 2); /* io_addr */
pos3 = mca_device_read_stored_pos(mca_dev, 3); /* shared mem */
pos4 = mca_device_read_stored_pos(mca_dev, 4); /* ROM bios addr range */
pos5 = mca_device_read_stored_pos(mca_dev, 5); /* irq, media and RIPL */
/* Test the following conditions:
* - If an irq parameter is supplied, compare it
* with the irq of the adapter we found
* - If a base_addr paramater is given, compare it
* with the base_addr of the adapter we found
* - Check that the irq and the base_addr of the
* adapter we found is not already in use by
* this driver
*/
if(!tirq || !tbase || (irq && irq != tirq) || (base_addr && tbase != base_addr)) {
slot = mca_find_unused_adapter(smc_mca_adapters[j].id, slot + 1);
} else {
adapter_found = 1;
adapter = j;
}
switch (mca_dev->index) {
case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A:
case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A:
case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A:
case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A:
{
tbase = addr_table[(pos2 & 0xf0) >> 4].base_addr;
tirq = irq_table[(pos5 & 0xc) >> 2].new_irq;
break;
}
case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A:
case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A:
case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A:
case _efe5_IBM_PS2_Adapter_A_for_Ethernet:
{
tbase = ((pos2 & 0x0fe) * 0x10);
tirq = irq_table[(pos5 & 3)].old_irq;
break;
}
}
if(!adapter_found) {
return ((base_addr || irq) ? -ENXIO : -ENODEV);
}
if(!tirq || !tbase
|| (irq && irq != tirq)
|| (base_addr && tbase != base_addr))
/* FIXME: we're trying to force the ordering of the
* devices here, there should be a way of getting this
* to happen */
return -ENXIO;
/* Adapter found. */
dev = alloc_etherdev(0);
if(!dev)
return -ENODEV;
printk(KERN_INFO "%s: %s found in slot %d\n",
dev->name, smc_mca_adapters[adapter].name, slot + 1);
SET_MODULE_OWNER(dev);
if((i = register_netdev(dev)) != 0)
return i;
mca_set_adapter_name(slot, smc_mca_adapters[adapter].name);
mca_mark_as_used(slot);
printk(KERN_INFO "%s: %s found in slot %d\n",
dev->name, smc_mca_adapter_names[adapter], slot + 1);
strncpy(gen_dev->name, smc_mca_adapter_names[adapter], sizeof(gen_dev->name));
mca_device_set_claim(mca_dev, 1);
ultra_found++;
dev->base_addr = ioaddr = tbase;
dev->irq = tirq;
dev->base_addr = ioaddr = mca_device_transform_ioport(mca_dev, tbase);
dev->irq = mca_device_transform_irq(mca_dev, tirq);
dev->mem_start = 0;
num_pages = 40;
......@@ -218,7 +230,8 @@ int __init ultramca_probe(struct net_device *dev)
for (i = 0; i < 16; i++) { /* taking 16 counts
* up to 15 [hs] */
if (mem_table[i].mem_index == (pos3 & ~MEM_MASK)) {
dev->mem_start = mem_table[i].mem_start;
dev->mem_start = (unsigned long)
mca_device_transform_memory(mca_dev, (void *)mem_table[i].mem_start);
num_pages = mem_table[i].num_pages;
}
}
......@@ -229,7 +242,8 @@ int __init ultramca_probe(struct net_device *dev)
case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A:
case _efe5_IBM_PS2_Adapter_A_for_Ethernet:
{
dev->mem_start = ((pos3 & 0xfc) * 0x1000);
dev->mem_start = (unsigned long)
mca_device_transform_memory(mca_dev, (void *)((pos3 & 0xfc) * 0x1000));
num_pages = 0x40;
break;
}
......@@ -240,7 +254,8 @@ int __init ultramca_probe(struct net_device *dev)
* the index of the 0x2000 step.
* beware different number of pages [hs]
*/
dev->mem_start = 0xc0000 + (0x2000 * (pos3 & 0xf));
dev->mem_start = (unsigned long)
mca_device_transform_memory(mca_dev, (void *)(0xc0000 + (0x2000 * (pos3 & 0xf))));
num_pages = 0x20 + (2 * (pos3 & 0x10));
break;
}
......@@ -258,7 +273,7 @@ int __init ultramca_probe(struct net_device *dev)
printk(KERN_INFO "%s: Parameters: %#3x,", dev->name, ioaddr);
for (i = 0; i < 6; i++)
printk(KERN_INFO " %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
/* Switch from the station address to the alternate register set
* and read the useful registers there.
......@@ -281,10 +296,11 @@ int __init ultramca_probe(struct net_device *dev)
*/
if (ethdev_init(dev)) {
printk (KERN_INFO ", no memory for dev->priv.\n");
printk (", no memory for dev->priv.\n");
release_region(ioaddr, ULTRA_IO_EXTENT);
return -ENOMEM;
}
gen_dev->driver_data = dev;
/* The 8390 isn't at the base address, so fake the offset
*/
......@@ -301,7 +317,7 @@ int __init ultramca_probe(struct net_device *dev)
dev->mem_end = ei_status.rmem_end =
dev->mem_start + (ei_status.stop_page - START_PG) * 256;
printk(KERN_INFO ", IRQ %d memory %#lx-%#lx.\n",
printk(", IRQ %d memory %#lx-%#lx.\n",
dev->irq, dev->mem_start, dev->mem_end - 1);
ei_status.reset_8390 = &ultramca_reset_8390;
......@@ -313,6 +329,7 @@ int __init ultramca_probe(struct net_device *dev)
dev->open = &ultramca_open;
dev->stop = &ultramca_close_card;
NS8390_init(dev, 0);
return 0;
......@@ -426,69 +443,48 @@ static int ultramca_close_card(struct net_device *dev)
return 0;
}
static int ultramca_remove(struct device *gen_dev)
{
struct mca_device *mca_dev = to_mca_device(gen_dev);
struct net_device *dev = (struct net_device *)gen_dev->driver_data;
#ifdef MODULE
#undef MODULE /* don't want to bother now! */
if(dev && dev->priv) {
/* NB: ultra_close_card() does free_irq */
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
#define MAX_ULTRAMCA_CARDS 4 /* Max number of Ultra cards per module */
mca_device_set_claim(mca_dev, 0);
release_region(ioaddr, ULTRA_IO_EXTENT);
unregister_netdev(dev);
kfree(dev->priv);
}
return 0;
}
static struct net_device dev_ultra[MAX_ULTRAMCA_CARDS];
static int io[MAX_ULTRAMCA_CARDS];
static int irq[MAX_ULTRAMCA_CARDS];
MODULE_LICENSE("GPL");
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
MODULE_PARM_DESC(io, "SMC Ultra/EtherEZ MCA I/O base address(es)");
MODULE_PARM_DESC(irq, "SMC Ultra/EtherEZ MCA IRQ number(s)");
static struct mca_driver ultra_driver = {
.id_table = smc_mca_adapter_ids,
.driver = {
.name = "smc-mca",
.bus = &mca_bus_type,
.probe = ultramca_probe,
.remove = ultramca_remove,
}
};
int init_module(void)
static int __init ultramca_init_module(void)
{
int this_dev, found = 0;
if(!MCA_bus)
return -ENXIO;
for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
struct net_device *dev = &dev_ultra[this_dev];
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
dev->init = ultramca_probe;
mca_register_driver(&ultra_driver);
if (register_netdev(dev) != 0) {
if (found != 0) { /* Got at least one. */
return 0;
}
printk(KERN_NOTICE "smc-mca.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
return -ENXIO;
}
found++;
}
return 0;
return ultra_found ? 0 : -ENXIO;
}
void cleanup_module(void)
static void __exit ultramca_cleanup_module(void)
{
int this_dev;
for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
struct net_device *dev = &dev_ultra[this_dev];
if (dev->priv != NULL) {
void *priv = dev->priv;
/* NB: ultra_close_card() does free_irq */
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
mca_mark_as_unused(ei_status.priv);
release_region(ioaddr, ULTRA_IO_EXTENT);
unregister_netdev(dev);
kfree(priv);
}
}
mca_unregister_driver(&ultra_driver);
}
#endif /* MODULE */
module_init(ultramca_init_module);
module_exit(ultramca_cleanup_module);
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/inet -c smc-mca.c"
* version-control: t
* kept-new-versions: 5
* c-indent-level: 8
* tab-width: 8
* End:
*/
......@@ -105,6 +105,7 @@
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/mca.h>
#include <asm/dma.h>
......@@ -182,131 +183,140 @@ param_setup(char *string)
__setup("NCR_D700=", param_setup);
#endif
/* private stack allocated structure for passing device information from
* detect to probe */
struct NCR_700_info {
Scsi_Host_Template *tpnt;
int found;
};
/* Detect a D700 card. Note, because of the set up---the chips are
* essentially connectecd to the MCA bus independently, it is easier
* to set them up as two separate host adapters, rather than one
* adapter with two channels */
STATIC int __init
D700_detect(Scsi_Host_Template *tpnt)
static int
NCR_D700_probe(struct device *dev)
{
int slot = 0;
int found = 0;
int differential;
int banner = 1;
if(!MCA_bus)
return 0;
#ifdef MODULE
if(NCR_D700)
param_setup(NCR_D700);
#endif
static int banner = 1;
struct mca_device *mca_dev = to_mca_device(dev);
int slot = mca_dev->slot;
struct NCR_700_info *info = to_mca_driver(dev->driver)->driver_data;
int found = 0;
int irq, i;
int pos3j, pos3k, pos3a, pos3b, pos4;
__u32 base_addr, offset_addr;
struct Scsi_Host *host = NULL;
/* enable board interrupt */
pos4 = mca_device_read_pos(mca_dev, 4);
pos4 |= 0x4;
mca_device_write_pos(mca_dev, 4, pos4);
mca_device_write_pos(mca_dev, 6, 9);
pos3j = mca_device_read_pos(mca_dev, 3);
mca_device_write_pos(mca_dev, 6, 10);
pos3k = mca_device_read_pos(mca_dev, 3);
mca_device_write_pos(mca_dev, 6, 0);
pos3a = mca_device_read_pos(mca_dev, 3);
mca_device_write_pos(mca_dev, 6, 1);
pos3b = mca_device_read_pos(mca_dev, 3);
base_addr = ((pos3j << 8) | pos3k) & 0xfffffff0;
offset_addr = ((pos3a << 8) | pos3b) & 0xffffff70;
irq = (pos4 & 0x3) + 11;
if(irq >= 13)
irq++;
if(banner) {
printk(KERN_NOTICE "NCR D700: Driver Version " NCR_D700_VERSION "\n"
"NCR D700: Copyright (c) 2001 by James.Bottomley@HansenPartnership.com\n"
"NCR D700:\n");
banner = 0;
}
/* now do the bus related transforms */
irq = mca_device_transform_irq(mca_dev, irq);
base_addr = mca_device_transform_ioport(mca_dev, base_addr);
offset_addr = mca_device_transform_ioport(mca_dev, offset_addr);
printk(KERN_NOTICE "NCR D700: found in slot %d irq = %d I/O base = 0x%x\n", slot, irq, offset_addr);
info->tpnt->proc_name = "NCR_D700";
/*outb(BOARD_RESET, base_addr);*/
/* clear any pending interrupts */
(void)inb(base_addr + 0x08);
/* get modctl, used later for setting diff bits */
switch(differential = (inb(base_addr + 0x08) >> 6)) {
case 0x00:
/* only SIOP1 differential */
differential = 0x02;
break;
case 0x01:
/* Both SIOPs differential */
differential = 0x03;
break;
case 0x03:
/* No SIOPs differential */
differential = 0x00;
break;
default:
printk(KERN_ERR "D700: UNEXPECTED DIFFERENTIAL RESULT 0x%02x\n",
differential);
differential = 0x00;
break;
}
for(slot = 0; (slot = mca_find_adapter(NCR_D700_MCA_ID, slot)) != MCA_NOTFOUND; slot++) {
int irq, i;
int pos3j, pos3k, pos3a, pos3b, pos4;
__u32 base_addr, offset_addr;
struct Scsi_Host *host = NULL;
/* enable board interrupt */
pos4 = mca_read_pos(slot, 4);
pos4 |= 0x4;
mca_write_pos(slot, 4, pos4);
mca_write_pos(slot, 6, 9);
pos3j = mca_read_pos(slot, 3);
mca_write_pos(slot, 6, 10);
pos3k = mca_read_pos(slot, 3);
mca_write_pos(slot, 6, 0);
pos3a = mca_read_pos(slot, 3);
mca_write_pos(slot, 6, 1);
pos3b = mca_read_pos(slot, 3);
base_addr = ((pos3j << 8) | pos3k) & 0xfffffff0;
offset_addr = ((pos3a << 8) | pos3b) & 0xffffff70;
irq = (pos4 & 0x3) + 11;
if(irq >= 13)
irq++;
if(banner) {
printk(KERN_NOTICE "NCR D700: Driver Version " NCR_D700_VERSION "\n"
"NCR D700: Copyright (c) 2001 by James.Bottomley@HansenPartnership.com\n"
"NCR D700:\n");
banner = 0;
/* plumb in both 700 chips */
for(i=0; i<2; i++) {
__u32 region = offset_addr | (0x80 * i);
struct NCR_700_Host_Parameters *hostdata =
kmalloc(sizeof(struct NCR_700_Host_Parameters),
GFP_KERNEL);
if(hostdata == NULL) {
printk(KERN_ERR "NCR D700: Failed to allocate host data for channel %d, detatching\n", i);
continue;
}
printk(KERN_NOTICE "NCR D700: found in slot %d irq = %d I/O base = 0x%x\n", slot, irq, offset_addr);
tpnt->proc_name = "NCR_D700";
/*outb(BOARD_RESET, base_addr);*/
/* clear any pending interrupts */
(void)inb(base_addr + 0x08);
/* get modctl, used later for setting diff bits */
switch(differential = (inb(base_addr + 0x08) >> 6)) {
case 0x00:
/* only SIOP1 differential */
differential = 0x02;
break;
case 0x01:
/* Both SIOPs differential */
differential = 0x03;
break;
case 0x03:
/* No SIOPs differential */
differential = 0x00;
break;
default:
printk(KERN_ERR "D700: UNEXPECTED DIFFERENTIAL RESULT 0x%02x\n",
differential);
differential = 0x00;
break;
memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
if(request_region(region, 64, "NCR_D700") == NULL) {
printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", region);
kfree(hostdata);
continue;
}
/* plumb in both 700 chips */
for(i=0; i<2; i++) {
__u32 region = offset_addr | (0x80 * i);
struct NCR_700_Host_Parameters *hostdata =
kmalloc(sizeof(struct NCR_700_Host_Parameters),
GFP_KERNEL);
if(hostdata == NULL) {
printk(KERN_ERR "NCR D700: Failed to allocate host data for channel %d, detatching\n", i);
continue;
}
memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
if(request_region(region, 64, "NCR_D700") == NULL) {
printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", region);
kfree(hostdata);
continue;
}
/* Fill in the three required pieces of hostdata */
hostdata->base = region;
hostdata->differential = (((1<<i) & differential) != 0);
hostdata->clock = NCR_D700_CLOCK_MHZ;
/* and register the chip */
if((host = NCR_700_detect(tpnt, hostdata)) == NULL) {
kfree(hostdata);
release_region(host->base, 64);
continue;
}
host->irq = irq;
/* FIXME: Read this from SUS */
host->this_id = id_array[slot * 2 + i];
printk(KERN_NOTICE "NCR D700: SIOP%d, SCSI id is %d\n",
i, host->this_id);
if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) {
printk(KERN_ERR "NCR D700, channel %d: irq problem, detatching\n", i);
scsi_unregister(host);
NCR_700_release(host);
continue;
}
found++;
mca_set_adapter_name(slot, "NCR D700 SCSI Adapter (version " NCR_D700_VERSION ")");
/* Fill in the three required pieces of hostdata */
hostdata->base = region;
hostdata->differential = (((1<<i) & differential) != 0);
hostdata->clock = NCR_D700_CLOCK_MHZ;
/* and register the chip */
if((host = NCR_700_detect(info->tpnt, hostdata)) == NULL) {
kfree(hostdata);
release_region(host->base, 64);
continue;
}
host->irq = irq;
/* FIXME: Read this from SUS */
host->this_id = id_array[slot * 2 + i];
printk(KERN_NOTICE "NCR D700: SIOP%d, SCSI id is %d\n",
i, host->this_id);
if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) {
printk(KERN_ERR "NCR D700, channel %d: irq problem, detatching\n", i);
scsi_unregister(host);
NCR_700_release(host);
continue;
}
scsi_set_device(host, dev);
found++;
}
info->found += found;
if(found) {
mca_device_set_claim(mca_dev, 1);
strncpy(dev->name, "NCR_D700", sizeof(dev->name));
}
return found;
return found? 0 : -ENODEV;
}
......@@ -323,7 +333,38 @@ D700_release(struct Scsi_Host *host)
return 1;
}
static short NCR_D700_id_table[] = { NCR_D700_MCA_ID, 0 };
struct mca_driver NCR_D700_driver = {
.id_table = NCR_D700_id_table,
.driver = {
.name = "NCR_D700",
.bus = &mca_bus_type,
.probe = NCR_D700_probe,
},
};
STATIC int __init
D700_detect(Scsi_Host_Template *tpnt)
{
struct NCR_700_info info;
if(!MCA_bus)
return 0;
#ifdef MODULE
if(NCR_D700)
param_setup(NCR_D700);
#endif
info.tpnt = tpnt;
info.found = 0;
NCR_D700_driver.driver_data = &info;
mca_register_driver(&NCR_D700_driver);
return info.found;
}
static Scsi_Host_Template driver_template = NCR_D700_SCSI;
#include "scsi_module.c"
......
......@@ -479,12 +479,6 @@ struct Scsi_Host
*/
unsigned int max_host_blocked;
/*
* For SCSI hosts which are PCI devices, set pci_dev so that
* we can do BIOS EDD 3.0 mappings
*/
struct pci_dev *pci_dev;
/*
* Support for driverfs filesystem
*/
......@@ -522,11 +516,21 @@ static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock)
shost->host_lock = lock;
}
static inline void scsi_set_device(struct Scsi_Host *shost,
struct device *dev)
{
shost->host_gendev = dev;
}
static inline struct device *scsi_get_device(struct Scsi_Host *shost)
{
return shost->host_gendev;
}
static inline void scsi_set_pci_device(struct Scsi_Host *shost,
struct pci_dev *pdev)
{
shost->pci_dev = pdev;
shost->host_gendev = &pdev->dev;
scsi_set_device(shost, &pdev->dev);
}
......
......@@ -764,7 +764,7 @@ static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
if (disk) {
struct Scsi_Device_Template **p = disk->private_data;
if (strcmp((*p)->tag, "sg") == 0)
if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0)
return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
}
return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
......
......@@ -46,6 +46,7 @@ const char * osst_version = "0.99.0p3";
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <linux/version.h>
#include <linux/blk.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
#include <asm/system.h>
......@@ -59,8 +60,6 @@ const char * osst_version = "0.99.0p3";
in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
#define OSST_DEB_MSG KERN_NOTICE
#define MAJOR_NR OSST_MAJOR
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
......@@ -5586,14 +5585,14 @@ static int osst_attach(Scsi_Device * SDp)
tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev;
tpnt->driverfs_dev_r[mode].bus = SDp->sdev_driverfs_dev.bus;
tpnt->driverfs_dev_r[mode].driver_data =
(void *)(long)__mkdev(MAJOR_NR, dev_num + (mode << 5));
(void *)(long)__mkdev(OSST_MAJOR, dev_num + (mode << 5));
device_register(&tpnt->driverfs_dev_r[mode]);
device_create_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_type);
device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
tpnt->de_r[mode] =
devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, dev_num + (mode << 5),
OSST_MAJOR, dev_num + (mode << 5),
S_IFCHR | S_IRUGO | S_IWUGO,
&osst_fops, NULL);
/* No-rewind entry */
......@@ -5605,7 +5604,7 @@ static int osst_attach(Scsi_Device * SDp)
tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev;
tpnt->driverfs_dev_n[mode].bus = SDp->sdev_driverfs_dev.bus;
tpnt->driverfs_dev_n[mode].driver_data =
(void *)(long)__mkdev(MAJOR_NR, dev_num + (mode << 5) + 128);
(void *)(long)__mkdev(OSST_MAJOR, dev_num + (mode << 5) + 128);
device_register(&tpnt->driverfs_dev_n[mode]);
device_create_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_type);
......@@ -5613,7 +5612,7 @@ static int osst_attach(Scsi_Device * SDp)
&dev_attr_kdev);
tpnt->de_n[mode] =
devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, dev_num + (mode << 5) + 128,
OSST_MAJOR, dev_num + (mode << 5) + 128,
S_IFCHR | S_IRUGO | S_IWUGO,
&osst_fops, NULL);
}
......@@ -5686,8 +5685,9 @@ static int __init init_osst(void)
printk(OSST_DEB_MSG "osst :D: %d s/g segments, write threshold %d bytes.\n",
max_sg_segs, osst_write_threshold);
#endif
if ((register_chrdev(MAJOR_NR,"osst",&osst_fops) < 0) || scsi_register_device(&osst_template)) {
printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n",MAJOR_NR);
if ((register_chrdev(OSST_MAJOR, "osst", &osst_fops) < 0) ||
scsi_register_device(&osst_template)) {
printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
return 1;
}
......@@ -5700,7 +5700,7 @@ static void __exit exit_osst (void)
OS_Scsi_Tape * STp;
scsi_unregister_device(&osst_template);
unregister_chrdev(MAJOR_NR, "osst");
unregister_chrdev(OSST_MAJOR, "osst");
if (os_scsi_tapes) {
for (i=0; i < osst_max_dev; ++i) {
......
......@@ -55,7 +55,6 @@
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/mempool.h>
#define __KERNEL_SYSCALLS__
......@@ -74,24 +73,6 @@
#include <linux/kmod.h>
#endif
#define SG_MEMPOOL_NR 5
#define SG_MEMPOOL_SIZE 32
struct scsi_host_sg_pool {
int size;
char *name;
kmem_cache_t *slab;
mempool_t *pool;
};
#define SP(x) { x, "sgpool-" #x }
struct scsi_host_sg_pool scsi_sg_pools[SG_MEMPOOL_NR] = {
SP(8), SP(16), SP(32), SP(64), SP(MAX_PHYS_SEGMENTS)
};
#undef SP
/*
static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
*/
/*
* Definitions and constants.
......@@ -668,10 +649,7 @@ int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
*/
void scsi_release_command(Scsi_Cmnd * SCpnt)
{
request_queue_t *q;
Scsi_Device * SDpnt;
SDpnt = SCpnt->device;
request_queue_t *q = &SCpnt->device->request_queue;
__scsi_release_command(SCpnt);
......@@ -681,7 +659,6 @@ void scsi_release_command(Scsi_Cmnd * SCpnt)
* This won't block - if the device cannot take any more, life
* will go on.
*/
q = &SDpnt->request_queue;
scsi_queue_next_request(q, NULL);
}
......@@ -2082,81 +2059,12 @@ static int __init setup_scsi_default_dev_flags(char *str)
__setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags);
#endif
static void *scsi_pool_alloc(int gfp_mask, void *data)
{
return kmem_cache_alloc(data, gfp_mask);
}
static void scsi_pool_free(void *ptr, void *data)
{
kmem_cache_free(data, ptr);
}
struct scatterlist *scsi_alloc_sgtable(Scsi_Cmnd *SCpnt, int gfp_mask)
{
struct scsi_host_sg_pool *sgp;
struct scatterlist *sgl;
int pf_flags;
BUG_ON(!SCpnt->use_sg);
switch (SCpnt->use_sg) {
case 1 ... 8 : SCpnt->sglist_len = 0; break;
case 9 ... 16 : SCpnt->sglist_len = 1; break;
case 17 ... 32 : SCpnt->sglist_len = 2; break;
case 33 ... 64 : SCpnt->sglist_len = 3; break;
case 65 ... MAX_PHYS_SEGMENTS : SCpnt->sglist_len = 4; break;
default: return NULL;
}
sgp = scsi_sg_pools + SCpnt->sglist_len;
pf_flags = current->flags;
current->flags |= PF_NOWARN;
sgl = mempool_alloc(sgp->pool, gfp_mask);
current->flags = pf_flags;
if (sgl) {
memset(sgl, 0, sgp->size);
return sgl;
}
return sgl;
}
void scsi_free_sgtable(struct scatterlist *sgl, int index)
{
struct scsi_host_sg_pool *sgp = scsi_sg_pools + index;
if (unlikely(index > SG_MEMPOOL_NR)) {
printk("scsi_free_sgtable: mempool %d\n", index);
BUG();
}
mempool_free(sgl, sgp->pool);
}
static int __init init_scsi(void)
{
int i;
printk(KERN_INFO "SCSI subsystem driver " REVISION "\n");
/*
* setup sg memory pools
*/
for (i = 0; i < SG_MEMPOOL_NR; i++) {
struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
int size = sgp->size * sizeof(struct scatterlist);
sgp->slab = kmem_cache_create(sgp->name, size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!sgp->slab)
printk(KERN_ERR "SCSI: can't init sg slab %s\n", sgp->name);
sgp->pool = mempool_create(SG_MEMPOOL_SIZE, scsi_pool_alloc, scsi_pool_free, sgp->slab);
if (!sgp->pool)
printk(KERN_ERR "SCSI: can't init sg mempool %s\n", sgp->name);
}
scsi_init_queue();
scsi_init_procfs();
devfs_mk_dir(NULL, "scsi", NULL);
scsi_host_init();
......@@ -2168,20 +2076,11 @@ static int __init init_scsi(void)
static void __exit exit_scsi(void)
{
int i;
scsi_sysfs_unregister();
scsi_dev_info_list_delete();
devfs_remove("scsi");
scsi_exit_procfs();
for (i = 0; i < SG_MEMPOOL_NR; i++) {
struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
mempool_destroy(sgp->pool);
kmem_cache_destroy(sgp->slab);
sgp->pool = NULL;
sgp->slab = NULL;
}
scsi_exit_queue();
}
subsys_initcall(init_scsi);
......
......@@ -420,12 +420,6 @@ extern int scsi_partsize(unsigned char *buf, unsigned long capacity,
unsigned int *cyls, unsigned int *hds,
unsigned int *secs);
/*
* sg list allocations
*/
struct scatterlist *scsi_alloc_sgtable(Scsi_Cmnd *SCpnt, int gfp_mask);
void scsi_free_sgtable(struct scatterlist *sgl, int index);
/*
* Prototypes for functions in scsi_lib.c
*/
......@@ -437,13 +431,13 @@ extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
extern void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt);
extern int scsi_prep_fn(struct request_queue *q, struct request *req);
extern void scsi_request_fn(request_queue_t * q);
extern int scsi_starvation_completion(Scsi_Device * SDpnt);
extern int scsi_init_queue(void);
extern void scsi_exit_queue(void);
/*
* Prototypes for functions in scsi.c
*/
extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt);
extern void scsi_bottom_half_handler(void);
extern void scsi_release_commandblocks(Scsi_Device * SDpnt);
extern void scsi_build_commandblocks(Scsi_Device * SDpnt);
extern void scsi_adjust_queue_depth(Scsi_Device *, int, int);
......@@ -462,7 +456,6 @@ extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd,
void *buffer, unsigned bufflen,
void (*done) (struct scsi_cmnd *),
int timeout, int retries);
extern int scsi_dev_init(void);
extern int scsi_mlqueue_insert(struct scsi_cmnd *, int);
extern int scsi_attach_device(struct scsi_device *);
extern void scsi_detach_device(struct scsi_device *);
......
......@@ -51,7 +51,7 @@
#include "scsi_debug.h"
static const char * scsi_debug_version_str = "Version: 1.65 (20021119)";
static const char * scsi_debug_version_str = "Version: 1.66 (20021205)";
#ifndef SCSI_CMD_READ_16
#define SCSI_CMD_READ_16 0x88
......@@ -397,7 +397,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
if ((errsts = check_reset(SCpnt, devip)))
break;
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x20, 0, 14);
errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
errsts = (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
break;
}
return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);
......@@ -417,7 +417,7 @@ static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip)
if (devip->reset) {
devip->reset = 0;
mk_sense_buffer(devip, UNIT_ATTENTION, 0x29, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
}
return 0;
}
......@@ -478,7 +478,7 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
arr[0] = pq_pdt;
if (0x2 & cmd[1]) { /* CMDDT bit set */
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
} else if (0x1 & cmd[1]) { /* EVPD bit set */
int dev_id_num, len;
char dev_id_str[6];
......@@ -503,7 +503,7 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
} else {
/* Illegal request, invalid field in cdb */
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
}
memcpy(buff, arr, min_len);
return 0;
......@@ -616,7 +616,7 @@ static int resp_mode_sense(unsigned char * cmd, int target,
memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
if (0x3 == pcontrol) { /* Saving values not supported */
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x39, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
}
dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
if (msense_6) {
......@@ -659,7 +659,7 @@ static int resp_mode_sense(unsigned char * cmd, int target,
break;
default:
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
}
if (msense_6)
arr[0] = offset - 1;
......@@ -683,14 +683,14 @@ static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
if (upper_blk || (block + num > sdebug_capacity)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
}
if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
(block >= OPT_MEDIUM_ERR_ADDR) &&
(block < (OPT_MEDIUM_ERR_ADDR + num))) {
mk_sense_buffer(devip, MEDIUM_ERROR, 0x11, 0, 14);
/* claim unrecoverable read error */
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
}
read_lock_irqsave(&atomic_rw, iflags);
sgcount = 0;
......@@ -732,7 +732,7 @@ static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
if (upper_blk || (block + num > sdebug_capacity)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
}
write_lock_irqsave(&atomic_rw, iflags);
......@@ -773,7 +773,7 @@ static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
if ((alloc_len < 16) || (select_report > 2)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
return (DRIVER_SENSE << 24) | (CHECK_CONDITION << 1);
}
if (bufflen > 3) {
lun_cnt = min((int)(bufflen / sizeof(ScsiLun)),
......
......@@ -393,12 +393,13 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
* any copy_to_user() error on failure there
*/
static int
scsi_ioctl_get_pci(Scsi_Device * dev, void *arg)
scsi_ioctl_get_pci(Scsi_Device * sdev, void *arg)
{
struct device *dev = scsi_get_device(sdev->host);
if (!dev->host->pci_dev) return -ENXIO;
return copy_to_user(arg, dev->host->pci_dev->slot_name,
sizeof(dev->host->pci_dev->slot_name));
if (!dev) return -ENXIO;
return copy_to_user(arg, dev->bus_id,
sizeof(dev->bus_id));
}
......
......@@ -11,12 +11,30 @@
#include <linux/blk.h>
#include <linux/completion.h>
#include <linux/kernel.h>
#include <linux/mempool.h>
#include <linux/slab.h>
#include <linux/init.h>
#include "scsi.h"
#include "hosts.h"
#define SG_MEMPOOL_NR 5
#define SG_MEMPOOL_SIZE 32
struct scsi_host_sg_pool {
size_t size;
char *name;
kmem_cache_t *slab;
mempool_t *pool;
};
#define SP(x) { x, "sgpool-" #x }
struct scsi_host_sg_pool scsi_sg_pools[SG_MEMPOOL_NR] = {
SP(8), SP(16), SP(32), SP(64), SP(MAX_PHYS_SEGMENTS)
};
#undef SP
/*
* Function: scsi_insert_special_cmd()
*
......@@ -348,6 +366,51 @@ static Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt,
return NULL;
}
static struct scatterlist *scsi_alloc_sgtable(Scsi_Cmnd *SCpnt, int gfp_mask)
{
struct scsi_host_sg_pool *sgp;
struct scatterlist *sgl;
BUG_ON(!SCpnt->use_sg);
switch (SCpnt->use_sg) {
case 1 ... 8:
SCpnt->sglist_len = 0;
break;
case 9 ... 16:
SCpnt->sglist_len = 1;
break;
case 17 ... 32:
SCpnt->sglist_len = 2;
break;
case 33 ... 64:
SCpnt->sglist_len = 3;
break;
case 65 ... MAX_PHYS_SEGMENTS:
SCpnt->sglist_len = 4;
break;
default:
return NULL;
}
sgp = scsi_sg_pools + SCpnt->sglist_len;
sgl = mempool_alloc(sgp->pool, gfp_mask);
if (sgl)
memset(sgl, 0, sgp->size);
return sgl;
}
static void scsi_free_sgtable(struct scatterlist *sgl, int index)
{
struct scsi_host_sg_pool *sgp;
BUG_ON(index > SG_MEMPOOL_NR);
sgp = scsi_sg_pools + index;
mempool_free(sgl, sgp->pool);
}
/*
* Function: scsi_release_buffers()
*
......@@ -374,15 +437,10 @@ static void scsi_release_buffers(Scsi_Cmnd * SCpnt)
/*
* Free up any indirection buffers we allocated for DMA purposes.
*/
if (SCpnt->use_sg) {
struct scatterlist *sgpnt;
sgpnt = (struct scatterlist *) SCpnt->request_buffer;
if (SCpnt->use_sg)
scsi_free_sgtable(SCpnt->request_buffer, SCpnt->sglist_len);
} else {
if (SCpnt->request_buffer != req->buffer)
kfree(SCpnt->request_buffer);
}
else if (SCpnt->request_buffer != req->buffer)
kfree(SCpnt->request_buffer);
/*
* Zero these out. They now point to freed memory, and it is
......@@ -462,22 +520,16 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
* For the case of a READ, we need to copy the data out of the
* bounce buffer and into the real buffer.
*/
if (SCpnt->use_sg) {
struct scatterlist *sgpnt;
sgpnt = (struct scatterlist *) SCpnt->buffer;
if (SCpnt->use_sg)
scsi_free_sgtable(SCpnt->buffer, SCpnt->sglist_len);
} else {
if (SCpnt->buffer != req->buffer) {
if (rq_data_dir(req) == READ) {
unsigned long flags;
char *to = bio_kmap_irq(req->bio, &flags);
memcpy(to, SCpnt->buffer, SCpnt->bufflen);
bio_kunmap_irq(to, &flags);
}
kfree(SCpnt->buffer);
else if (SCpnt->buffer != req->buffer) {
if (rq_data_dir(req) == READ) {
unsigned long flags;
char *to = bio_kmap_irq(req->bio, &flags);
memcpy(to, SCpnt->buffer, SCpnt->bufflen);
bio_kunmap_irq(to, &flags);
}
kfree(SCpnt->buffer);
}
if (blk_pc_request(req)) {
......@@ -1093,3 +1145,41 @@ void scsi_register_blocked_host(struct Scsi_Host * SHpnt)
void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt)
{
}
int __init scsi_init_queue(void)
{
int i;
for (i = 0; i < SG_MEMPOOL_NR; i++) {
struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
int size = sgp->size * sizeof(struct scatterlist);
sgp->slab = kmem_cache_create(sgp->name, size, 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!sgp->slab) {
printk(KERN_ERR "SCSI: can't init sg slab %s\n",
sgp->name);
}
sgp->pool = mempool_create(SG_MEMPOOL_SIZE,
mempool_alloc_slab, mempool_free_slab,
sgp->slab);
if (!sgp->pool) {
printk(KERN_ERR "SCSI: can't init sg mempool %s\n",
sgp->name);
}
}
return 0;
}
void __exit scsi_exit_queue(void)
{
int i;
for (i = 0; i < SG_MEMPOOL_NR; i++) {
struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
mempool_destroy(sgp->pool);
kmem_cache_destroy(sgp->slab);
}
}
......@@ -373,11 +373,12 @@ static void scsi_initialize_merge_fn(struct scsi_device *sd)
{
request_queue_t *q = &sd->request_queue;
struct Scsi_Host *sh = sd->host;
struct device *dev = scsi_get_device(sh);
u64 bounce_limit;
if (sh->highmem_io) {
if (sh->pci_dev && PCI_DMA_BUS_IS_PHYS) {
bounce_limit = sh->pci_dev->dma_mask;
if (dev && dev->dma_mask && PCI_DMA_BUS_IS_PHYS) {
bounce_limit = *dev->dma_mask;
} else {
/*
* Platforms with virtual-DMA translation
......
......@@ -132,39 +132,115 @@ void scsi_upper_driver_unregister(struct Scsi_Device_Template *sdev_tp)
}
/**
* scsi_device_type_read - copy out the SCSI type
* @dev: device to check
* @page: copy data into this area
* @count: number of bytes to copy
* @off: start at this offset in page
*
* Return:
* number of bytes written into page.
**/
static ssize_t scsi_device_type_read(struct device *dev, char *page,
size_t count, loff_t off)
{
struct scsi_device *sdev = to_scsi_device(dev);
const char *type;
/*
* show_function: macro to create an attr function that can be used to
* show a non-bit field.
*/
#define show_function(field, format_string) \
static ssize_t \
show_##field (struct device *dev, char *buf, size_t count, loff_t off) \
{ \
struct scsi_device *sdev; \
if (off) \
return 0; \
sdev = to_scsi_device(dev); \
return snprintf (buf, count, format_string, sdev->field); \
} \
if (off)
return 0;
/*
* sdev_rd_attr: macro to create a function and attribute variable for a
* read only field.
*/
#define sdev_rd_attr(field, format_string) \
show_function(field, format_string) \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
/*
* sdev_rd_attr: create a function and attribute variable for a
* read/write field.
*/
#define sdev_rw_attr(field, format_string) \
show_function(field, format_string) \
\
static ssize_t \
store_##field (struct device *dev, const char *buf, size_t count, loff_t off)\
{ \
struct scsi_device *sdev; \
\
if (off) \
return 0; \
sdev = to_scsi_device(dev); \
return snscanf (buf, count, format_string, &sdev->field); \
} \
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, store_##field)
if ((sdev->type > MAX_SCSI_DEVICE_CODE) ||
(scsi_device_types[(int)sdev->type] == NULL))
type = "Unknown";
else
type = scsi_device_types[(int)sdev->type];
/*
* sdev_rd_attr: create a function and attribute variable for a
* read/write bit field.
*/
#define sdev_rw_attr_bit(field) \
show_function(field, "%d\n") \
\
static ssize_t \
store_##field (struct device *dev, const char *buf, size_t count, loff_t off)\
{ \
int ret; \
struct scsi_device *sdev; \
\
if (off) \
return 0; \
ret = scsi_sdev_check_buf_bit(buf); \
if (ret >= 0) { \
sdev = to_scsi_device(dev); \
sdev->field = ret; \
ret = count; \
} \
return ret; \
} \
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, store_##field)
return snprintf(page, count, "%s\n", type);
/*
* scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
* else return -EINVAL.
*/
static int scsi_sdev_check_buf_bit(const char *buf)
{
if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) {
if (buf[0] == '1')
return 1;
else if (buf[0] == '0')
return 0;
else
return -EINVAL;
} else
return -EINVAL;
}
/*
* Create dev_attr_type. This is different from the dev_attr_type in scsi
* upper level drivers.
* Create the actual show/store functions and data structures.
*/
static DEVICE_ATTR(type,S_IRUGO,scsi_device_type_read,NULL);
sdev_rd_attr (device_blocked, "%d\n");
sdev_rd_attr (current_queue_depth, "%d\n");
sdev_rd_attr (new_queue_depth, "%d\n");
sdev_rd_attr (type, "%d\n");
sdev_rd_attr (access_count, "%d\n");
sdev_rd_attr (vendor, "%.8s\n");
sdev_rd_attr (model, "%.16s\n");
sdev_rd_attr (rev, "%.4s\n");
sdev_rw_attr_bit (online);
static struct device_attribute * const sdev_attrs[] = {
&dev_attr_device_blocked,
&dev_attr_current_queue_depth,
&dev_attr_new_queue_depth,
&dev_attr_type,
&dev_attr_access_count,
&dev_attr_vendor,
&dev_attr_model,
&dev_attr_rev,
&dev_attr_online,
};
/**
* scsi_device_register - register a scsi device with the scsi bus
......@@ -175,7 +251,7 @@ static DEVICE_ATTR(type,S_IRUGO,scsi_device_type_read,NULL);
**/
int scsi_device_register(struct scsi_device *sdev)
{
int error = 0;
int error = 0, i;
sprintf(sdev->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
......@@ -186,9 +262,12 @@ int scsi_device_register(struct scsi_device *sdev)
if (error)
return error;
error = device_create_file(&sdev->sdev_driverfs_dev, &dev_attr_type);
for (i = 0; !error && i < ARRAY_SIZE(sdev_attrs); i++)
error = device_create_file(&sdev->sdev_driverfs_dev,
sdev_attrs[i]);
if (error)
device_unregister(&sdev->sdev_driverfs_dev);
scsi_device_unregister(sdev);
return error;
}
......@@ -199,6 +278,9 @@ int scsi_device_register(struct scsi_device *sdev)
**/
void scsi_device_unregister(struct scsi_device *sdev)
{
device_remove_file(&sdev->sdev_driverfs_dev, &dev_attr_type);
int i;
for (i = 0; i < ARRAY_SIZE(sdev_attrs); i++)
device_remove_file(&sdev->sdev_driverfs_dev, sdev_attrs[i]);
device_unregister(&sdev->sdev_driverfs_dev);
}
......@@ -33,7 +33,7 @@ static char *verstr = "20021015";
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/blk.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
#include <asm/system.h>
......@@ -54,9 +54,6 @@ static char *verstr = "20021015";
#define DEBC(a)
#endif
#define MAJOR_NR SCSI_TAPE_MAJOR
#define DEVICE_NR(device) (minor(device) & 0x7f)
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
......@@ -3768,13 +3765,14 @@ static int st_attach(Scsi_Device * SDp)
tpnt->try_dio = try_direct_io && !SDp->host->unchecked_isa_dma;
bounce_limit = BLK_BOUNCE_HIGH; /* Borrowed from scsi_merge.c */
if (SDp->host->highmem_io) {
struct device *dev = scsi_get_device(SDp->host);
if (!PCI_DMA_BUS_IS_PHYS)
/* Platforms with virtual-DMA translation
* hardware have no practical limit.
*/
bounce_limit = BLK_BOUNCE_ANY;
else if (SDp->host->pci_dev)
bounce_limit = SDp->host->pci_dev->dma_mask;
else if (dev && dev->dma_mask)
bounce_limit = *dev->dma_mask;
} else if (SDp->host->unchecked_isa_dma)
bounce_limit = BLK_BOUNCE_ISA;
bounce_limit >>= PAGE_SHIFT;
......
/* -*- mode: c; c-basic-offset: 8 -*- */
/* Platform specific MCA defines */
#ifndef _ASM_MCA_H
#define _ASM_MCA_H
/* Maximal number of MCA slots - actually, some machines have less, but
* they all have sufficient number of POS registers to cover 8.
*/
#define MCA_MAX_SLOT_NR 8
/* Most machines have only one MCA bus. The only multiple bus machines
* I know have at most two */
#define MAX_MCA_BUSSES 2
#define MCA_PRIMARY_BUS 0
#define MCA_SECONDARY_BUS 1
/* Dummy slot numbers on primary MCA for integrated functions */
#define MCA_INTEGSCSI (MCA_MAX_SLOT_NR)
#define MCA_INTEGVIDEO (MCA_MAX_SLOT_NR+1)
#define MCA_MOTHERBOARD (MCA_MAX_SLOT_NR+2)
/* Dummy POS values for integrated functions */
#define MCA_DUMMY_POS_START 0x10000
#define MCA_INTEGSCSI_POS (MCA_DUMMY_POS_START+1)
#define MCA_INTEGVIDEO_POS (MCA_DUMMY_POS_START+2)
#define MCA_MOTHERBOARD_POS (MCA_DUMMY_POS_START+3)
/* MCA registers */
#define MCA_MOTHERBOARD_SETUP_REG 0x94
#define MCA_ADAPTER_SETUP_REG 0x96
#define MCA_POS_REG(n) (0x100+(n))
#define MCA_ENABLED 0x01 /* POS 2, set if adapter enabled */
/* Max number of adapters, including both slots and various integrated
* things.
*/
#define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+3)
/* lock to protect access to the MCA registers */
extern spinlock_t mca_lock;
#endif
......@@ -214,7 +214,7 @@ struct hdlcdrv_state {
struct hdlcdrv_hdlctx {
struct hdlcdrv_hdlcbuffer hbuf;
int in_hdlc_tx;
long in_hdlc_tx;
/*
* 0 = send flags
* 1 = send txtail (flags)
......
/* -*- mode: c; c-basic-offset: 8 -*- */
/* This is the function prototypes for the old legacy MCA interface
*
* Please move your driver to the new sysfs based one instead */
#ifndef _LINUX_MCA_LEGACY_H
#define _LINUX_MCA_LEGACY_H
/* MCA_NOTFOUND is an error condition. The other two indicate
* motherboard POS registers contain the adapter. They might be
* returned by the mca_find_adapter() function, and can be used as
* arguments to mca_read_stored_pos(). I'm not going to allow direct
* access to the motherboard registers until we run across an adapter
* that requires it. We don't know enough about them to know if it's
* safe.
*
* See Documentation/mca.txt or one of the existing drivers for
* more information.
*/
#define MCA_NOTFOUND (-1)
/* Returns the slot of the first enabled adapter matching id. User can
* specify a starting slot beyond zero, to deal with detecting multiple
* devices. Returns MCA_NOTFOUND if id not found. Also checks the
* integrated adapters.
*/
extern int mca_find_adapter(int id, int start);
extern int mca_find_unused_adapter(int id, int start);
/* adapter state info - returns 0 if no */
extern int mca_isadapter(int slot);
extern int mca_isenabled(int slot);
extern int mca_is_adapter_used(int slot);
extern int mca_mark_as_used(int slot);
extern void mca_mark_as_unused(int slot);
/* gets a byte out of POS register (stored in memory) */
extern unsigned char mca_read_stored_pos(int slot, int reg);
/* This can be expanded later. Right now, it gives us a way of
* getting meaningful information into the MCA_info structure,
* so we can have a more interesting /proc/mca.
*/
extern void mca_set_adapter_name(int slot, char* name);
extern char* mca_get_adapter_name(int slot);
/* These routines actually mess with the hardware POS registers. They
* temporarily disable the device (and interrupts), so make sure you know
* what you're doing if you use them. Furthermore, writing to a POS may
* result in two devices trying to share a resource, which in turn can
* result in multiple devices sharing memory spaces, IRQs, or even trashing
* hardware. YOU HAVE BEEN WARNED.
*
* You can only access slots with this. Motherboard registers are off
* limits.
*/
/* read a byte from the specified POS register. */
extern unsigned char mca_read_pos(int slot, int reg);
/* write a byte to the specified POS register. */
extern void mca_write_pos(int slot, int reg, unsigned char byte);
#endif
......@@ -6,6 +6,14 @@
#ifndef _LINUX_MCA_H
#define _LINUX_MCA_H
/* FIXME: This shouldn't happen, but we need everything that previously
* included mca.h to compile. Take it out later when the MCA #includes
* are sorted out */
#include <linux/device.h>
/* get the platform specific defines */
#include <asm/mca.h>
/* The detection of MCA bus is done in the real mode (using BIOS).
* The information is exported to the protected code, where this
* variable is set to one in case MCA bus was detected.
......@@ -14,58 +22,6 @@
extern int MCA_bus;
#endif
/* Maximal number of MCA slots - actually, some machines have less, but
* they all have sufficient number of POS registers to cover 8.
*/
#define MCA_MAX_SLOT_NR 8
/* MCA_NOTFOUND is an error condition. The other two indicate
* motherboard POS registers contain the adapter. They might be
* returned by the mca_find_adapter() function, and can be used as
* arguments to mca_read_stored_pos(). I'm not going to allow direct
* access to the motherboard registers until we run across an adapter
* that requires it. We don't know enough about them to know if it's
* safe.
*
* See Documentation/mca.txt or one of the existing drivers for
* more information.
*/
#define MCA_NOTFOUND (-1)
#define MCA_INTEGSCSI (MCA_MAX_SLOT_NR)
#define MCA_INTEGVIDEO (MCA_MAX_SLOT_NR+1)
#define MCA_MOTHERBOARD (MCA_MAX_SLOT_NR+2)
/* Max number of adapters, including both slots and various integrated
* things.
*/
#define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+3)
/* Returns the slot of the first enabled adapter matching id. User can
* specify a starting slot beyond zero, to deal with detecting multiple
* devices. Returns MCA_NOTFOUND if id not found. Also checks the
* integrated adapters.
*/
extern int mca_find_adapter(int id, int start);
extern int mca_find_unused_adapter(int id, int start);
/* adapter state info - returns 0 if no */
extern int mca_isadapter(int slot);
extern int mca_isenabled(int slot);
extern int mca_is_adapter_used(int slot);
extern int mca_mark_as_used(int slot);
extern void mca_mark_as_unused(int slot);
/* gets a byte out of POS register (stored in memory) */
extern unsigned char mca_read_stored_pos(int slot, int reg);
/* This can be expanded later. Right now, it gives us a way of
* getting meaningful information into the MCA_info structure,
* so we can have a more interesting /proc/mca.
*/
extern void mca_set_adapter_name(int slot, char* name);
extern char* mca_get_adapter_name(int slot);
/* This sets up an information callback for /proc/mca/slot?. The
* function is called with the buffer, slot, and device pointer (or
* some equally informative context information, or nothing, if you
......@@ -78,28 +34,115 @@ extern char* mca_get_adapter_name(int slot);
* nastiness.
*/
typedef int (*MCA_ProcFn)(char* buf, int slot, void* dev);
extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev);
/* These routines actually mess with the hardware POS registers. They
* temporarily disable the device (and interrupts), so make sure you know
* what you're doing if you use them. Furthermore, writing to a POS may
* result in two devices trying to share a resource, which in turn can
* result in multiple devices sharing memory spaces, IRQs, or even trashing
* hardware. YOU HAVE BEEN WARNED.
*
* You can only access slots with this. Motherboard registers are off
* limits.
*/
/* read a byte from the specified POS register. */
extern unsigned char mca_read_pos(int slot, int reg);
/* write a byte to the specified POS register. */
extern void mca_write_pos(int slot, int reg, unsigned char byte);
/* Should only be called by the NMI interrupt handler, this will do some
* fancy stuff to figure out what might have generated a NMI.
*/
extern void mca_handle_nmi(void);
enum MCA_AdapterStatus {
MCA_ADAPTER_NORMAL = 0,
MCA_ADAPTER_NONE = 1,
MCA_ADAPTER_DISABLED = 2,
MCA_ADAPTER_ERROR = 3
};
struct mca_device {
u64 dma_mask;
int pos_id;
int slot;
/* index into id_table, set by the bus match routine */
int index;
/* is there a driver installed? 0 - No, 1 - Yes */
int driver_loaded;
/* POS registers */
unsigned char pos[8];
/* if a pseudo adapter of the motherboard, this is the motherboard
* register value to use for setup cycles */
short pos_register;
enum MCA_AdapterStatus status;
#ifdef CONFIG_MCA_PROC_FS
/* name of the proc/mca file */
char procname[8];
/* /proc info callback */
MCA_ProcFn procfn;
/* device/context info for proc callback */
void *proc_dev;
#endif
struct device dev;
};
#define to_mca_device(mdev) container_of(mdev, struct mca_device, dev)
struct mca_bus_accessor_functions {
unsigned char (*mca_read_pos)(struct mca_device *, int reg);
void (*mca_write_pos)(struct mca_device *, int reg,
unsigned char byte);
int (*mca_transform_irq)(struct mca_device *, int irq);
int (*mca_transform_ioport)(struct mca_device *,
int region);
void * (*mca_transform_memory)(struct mca_device *,
void *memory);
};
struct mca_bus {
u64 default_dma_mask;
int number;
struct mca_bus_accessor_functions f;
struct device dev;
};
#define to_mca_bus(mdev) container_of(mdev, struct mca_bus, dev)
struct mca_driver {
const short *id_table;
void *driver_data;
struct device_driver driver;
};
#define to_mca_driver(mdriver) container_of(mdriver, struct mca_driver, driver)
/* Ongoing supported API functions */
extern struct mca_device *mca_find_device_by_slot(int slot);
extern int mca_system_init(void);
extern struct mca_bus *mca_attach_bus(int);
extern unsigned char mca_device_read_stored_pos(struct mca_device *mca_dev,
int reg);
extern unsigned char mca_device_read_pos(struct mca_device *mca_dev, int reg);
extern void mca_device_write_pos(struct mca_device *mca_dev, int reg,
unsigned char byte);
extern int mca_device_transform_irq(struct mca_device *mca_dev, int irq);
extern int mca_device_transform_ioport(struct mca_device *mca_dev, int port);
extern void *mca_device_transform_memory(struct mca_device *mca_dev,
void *mem);
extern int mca_device_claimed(struct mca_device *mca_dev);
extern void mca_device_set_claim(struct mca_device *mca_dev, int val);
extern enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev);
extern struct bus_type mca_bus_type;
extern int mca_register_driver(struct mca_driver *drv);
extern void mca_unregister_driver(struct mca_driver *drv);
/* WARNING: only called by the boot time device setup */
extern int mca_register_device(int bus, struct mca_device *mca_dev);
#ifdef CONFIG_MCA_LEGACY
#include <linux/mca-legacy.h>
#endif
#ifdef CONFIG_MCA_PROC_FS
extern void mca_do_proc_init(void);
extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev);
#else
static inline void mca_do_proc_init(void)
{
}
static inline void mca_set_adapter_procfn(int slot, MCA_ProcFn *fn, void* dev)
{
}
#endif
#endif /* _LINUX_MCA_H */
......@@ -225,6 +225,8 @@ int init_module(void)
void cleanup_module(void)
{
int i;
for (i = 0; i < sizeof(entries)/sizeof(entries[0]); i++)
devfs_remove("netlink/%s", entries[i].name);
for (i = 0; i < 16; i++)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment